diff --git a/README.md b/README.md index 74fff483..8c376311 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ | № | ФИО | Directory name | #1 | #2 | #3 | #4 | #5 | #6 | #7 | Рейтинг | Амбиции | Реальность | | --- | ---------------------------------------------------------------- | -------------- | --- | --- | --- | --- | --- | --- | --- | ------- | ------- | ------- | | 1 | [Кузьмич Вадим](https://github.com/orgs/brstu/people/vkn10) |[ii02211](./trunk/ii02211)|:heavy_check_mark:|:heavy_check_mark:| |:heavy_check_mark:|:heavy_check_mark:| | | | | | -| 2 | [Любчук Илья](https://github.com/snep1one)|[ii02212](./trunk/ii02212)|:heavy_check_mark:| | | | | | | | 5 | 0 | +| 2 | [Любчук Илья](https://github.com/snep1one)|[ii02212](./trunk/ii02212)|:heavy_check_mark:|:heavy_check_mark:| | | | | | | 5 | 0 | | 3 | [Марач Максим](https://github.com/orgs/brstu/people/MaximMarach) | | | | | | | | | | | | | 4 | [Нестерчук Дмитрий](https://github.com/nesterchuk11) |[ii02214](./trunk/ii02214)| |:heavy_check_mark:| |:heavy_check_mark:|:heavy_check_mark:| | | | 5 | 0 | | 5 | [Павлюкович Игорь](https://github.com/orgs/brstu/people/Kre1kh) |[ii02215](./trunk/ii02215)| |:heavy_check_mark:| |:heavy_check_mark:|:heavy_check_mark:| | | | 4 | 0 | diff --git a/trunk/ii02212/task_02/README.md b/trunk/ii02212/task_02/README.md new file mode 100644 index 00000000..c441a8cf --- /dev/null +++ b/trunk/ii02212/task_02/README.md @@ -0,0 +1,25 @@ +# Лабораторная работа № 2 +## Разработка приложения "Адресная книга" средствами Qt + +## Цель работы +Изучить базовые компоненты средства разработки графического интерфейса среды Qt + +## Ход работы +В ходе работы над лабораторной работой была реализована программа "Адресная Книга", которая позволяла при помощи графического интерфейса пользователя +добавлять записи, просматривать их, редактировать, сохранять/открывать файлы с записями, а так же экспортировать их в другой формат. + +## Графический интерфейс пользователя и результат работы + +Добавление в адресную книгу +![](images/add.png) +Удаление +![](images/delete.png) +Обновление записи +![](images/update.png) +Поиск +![](images/find.png) +Открытие файла +![](images/open.png) +![](images/open2.png) +Сохранение +![](images/save.png) diff --git a/trunk/ii02212/task_02/images/add.png b/trunk/ii02212/task_02/images/add.png new file mode 100644 index 00000000..154832b2 Binary files /dev/null and b/trunk/ii02212/task_02/images/add.png differ diff --git a/trunk/ii02212/task_02/images/delete.png b/trunk/ii02212/task_02/images/delete.png new file mode 100644 index 00000000..3ddff2b3 Binary files /dev/null and b/trunk/ii02212/task_02/images/delete.png differ diff --git a/trunk/ii02212/task_02/images/find.png b/trunk/ii02212/task_02/images/find.png new file mode 100644 index 00000000..6f0814f7 Binary files /dev/null and b/trunk/ii02212/task_02/images/find.png differ diff --git a/trunk/ii02212/task_02/images/open.png b/trunk/ii02212/task_02/images/open.png new file mode 100644 index 00000000..b479ba36 Binary files /dev/null and b/trunk/ii02212/task_02/images/open.png differ diff --git a/trunk/ii02212/task_02/images/open2.png b/trunk/ii02212/task_02/images/open2.png new file mode 100644 index 00000000..1924417e Binary files /dev/null and b/trunk/ii02212/task_02/images/open2.png differ diff --git a/trunk/ii02212/task_02/images/save.png b/trunk/ii02212/task_02/images/save.png new file mode 100644 index 00000000..1ea461f3 Binary files /dev/null and b/trunk/ii02212/task_02/images/save.png differ diff --git a/trunk/ii02212/task_02/images/update.png b/trunk/ii02212/task_02/images/update.png new file mode 100644 index 00000000..8abe76b8 Binary files /dev/null and b/trunk/ii02212/task_02/images/update.png differ diff --git a/trunk/ii02212/task_02/src/CMakeLists.txt b/trunk/ii02212/task_02/src/CMakeLists.txt new file mode 100644 index 00000000..cd3a1a62 --- /dev/null +++ b/trunk/ii02212/task_02/src/CMakeLists.txt @@ -0,0 +1,70 @@ +cmake_minimum_required(VERSION 3.5) + +project(Lab2Giis VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) + +set(PROJECT_SOURCES + main.cpp + mainwindow.cpp + mainwindow.h + mainwindow.ui +) + +if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) + qt_add_executable(Lab2Giis + MANUAL_FINALIZATION + ${PROJECT_SOURCES} + ) +# Define target properties for Android with Qt 6 as: +# set_property(TARGET Lab2Giis APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR +# ${CMAKE_CURRENT_SOURCE_DIR}/android) +# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation +else() + if(ANDROID) + add_library(Lab2Giis SHARED + ${PROJECT_SOURCES} + ) +# Define properties for Android with Qt 5 after find_package() calls as: +# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") + else() + add_executable(Lab2Giis + ${PROJECT_SOURCES} + ) + endif() +endif() + +target_link_libraries(Lab2Giis PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) + +# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. +# If you are developing for iOS or macOS you should consider setting an +# explicit, fixed bundle identifier manually though. +if(${QT_VERSION} VERSION_LESS 6.1.0) + set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.Lab2Giis) +endif() +set_target_properties(Lab2Giis PROPERTIES + ${BUNDLE_ID_OPTION} + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +include(GNUInstallDirs) +install(TARGETS Lab2Giis + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + +if(QT_VERSION_MAJOR EQUAL 6) + qt_finalize_executable(Lab2Giis) +endif() diff --git a/trunk/ii02212/task_02/src/addressBook.pro b/trunk/ii02212/task_02/src/addressBook.pro new file mode 100644 index 00000000..3cedc058 --- /dev/null +++ b/trunk/ii02212/task_02/src/addressBook.pro @@ -0,0 +1,35 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + addressbook.cpp \ + finddialog.cpp \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + addressbook.h \ + finddialog.h \ + mainwindow.h + +FORMS += \ + mainwindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/trunk/ii02212/task_02/src/addressBook.pro.user b/trunk/ii02212/task_02/src/addressBook.pro.user new file mode 100644 index 00000000..0ba7d0d0 --- /dev/null +++ b/trunk/ii02212/task_02/src/addressBook.pro.user @@ -0,0 +1,562 @@ + + + + + + EnvironmentId + {5e17e7ce-1134-4ed2-9caa-f57208ef9a03} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + -fno-delayed-template-parsing + + true + + + + ProjectExplorer.Project.Target.0 + + Desktop Qt 5.14.2 MinGW 32-bit + Desktop Qt 5.14.2 MinGW 32-bit + qt.qt5.5142.win32_mingw73_kit + 0 + 0 + 0 + + C:/Users/N/Documents/build-addressBook-Desktop_Qt_5_14_2_MinGW_32_bit-Debug + + + true + QtProjectManager.QMakeBuildStep + true + + false + false + false + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Сборка + Сборка + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Очистка + Очистка + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Отладка + Qt4ProjectManager.Qt4BuildConfiguration + 2 + + + C:/Users/N/Documents/build-addressBook-Desktop_Qt_5_14_2_MinGW_32_bit-Release + + + true + QtProjectManager.QMakeBuildStep + false + + false + false + true + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Сборка + Сборка + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Очистка + Очистка + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Выпуск + Qt4ProjectManager.Qt4BuildConfiguration + 0 + + + C:/Users/N/Documents/build-addressBook-Desktop_Qt_5_14_2_MinGW_32_bit-Profile + + + true + QtProjectManager.QMakeBuildStep + true + + false + true + true + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Сборка + Сборка + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Очистка + Очистка + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Профилирование + Qt4ProjectManager.Qt4BuildConfiguration + 0 + + 3 + + + 0 + Развёртывание + Развёртывание + ProjectExplorer.BuildSteps.Deploy + + 1 + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + Qt4ProjectManager.Qt4RunConfiguration:C:/Users/N/Documents/addressBook/addressBook.pro + C:/Users/N/Documents/addressBook/addressBook.pro + + false + + false + true + true + false + false + true + + C:/Users/N/Documents/build-addressBook-Desktop_Qt_5_14_2_MinGW_32_bit-Debug + + 1 + + + + ProjectExplorer.Project.Target.1 + + Desktop Qt 5.14.2 MinGW 64-bit + Desktop Qt 5.14.2 MinGW 64-bit + qt.qt5.5142.win64_mingw73_kit + 0 + 0 + 0 + + C:/Users/N/Documents/build-addressBook-Desktop_Qt_5_14_2_MinGW_64_bit-Debug + + + true + QtProjectManager.QMakeBuildStep + true + + false + false + false + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Сборка + Сборка + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Очистка + Очистка + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Отладка + Qt4ProjectManager.Qt4BuildConfiguration + 2 + + + C:/Users/N/Documents/build-addressBook-Desktop_Qt_5_14_2_MinGW_64_bit-Release + + + true + QtProjectManager.QMakeBuildStep + false + + false + false + true + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Сборка + Сборка + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Очистка + Очистка + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Выпуск + Qt4ProjectManager.Qt4BuildConfiguration + 0 + + + C:/Users/N/Documents/build-addressBook-Desktop_Qt_5_14_2_MinGW_64_bit-Profile + + + true + QtProjectManager.QMakeBuildStep + true + + false + true + true + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Сборка + Сборка + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Очистка + Очистка + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Профилирование + Qt4ProjectManager.Qt4BuildConfiguration + 0 + + 3 + + + 0 + Развёртывание + Развёртывание + ProjectExplorer.BuildSteps.Deploy + + 1 + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + ProjectExplorer.CustomExecutableRunConfiguration + + + false + + false + true + false + false + true + + + + 1 + + + + ProjectExplorer.Project.TargetCount + 2 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + diff --git a/trunk/ii02212/task_02/src/addressbook.cpp b/trunk/ii02212/task_02/src/addressbook.cpp new file mode 100644 index 00000000..f9dbfa8a --- /dev/null +++ b/trunk/ii02212/task_02/src/addressbook.cpp @@ -0,0 +1,407 @@ +#include "addressbook.h" + +#include +#include +#include +#include +#include + +AddressBook::AddressBook(QWidget *parent) + : QWidget(parent) +{ + QLabel nameLabel(tr("Name:")); + nameLine = std::make_unique(); + nameLine->setReadOnly(true); + + QLabel addressLabel(tr("Address:")); + addressText = std::make_unique(); + addressText->setReadOnly(true); + + addButton = std::make_unique(tr("&Add")); + addButton->show(); + + submitButton = std::make_unique(tr("&Submit")); + submitButton->hide(); + + cancelButton = std::make_unique(tr("&Cancel")); + cancelButton->hide(); + + nextButton = std::make_unique(tr("&Next")); + nextButton->setEnabled(false); + + previousButton = std::make_unique(tr("&Previous")); + previousButton->setEnabled(false); + + editButton = std::make_unique(tr("&Edit")); + editButton->setEnabled(false); + + removeButton = std::make_unique(tr("&Remove")); + removeButton->setEnabled(false); + + findButton = std::make_unique(tr("&Find")); + findButton->setEnabled(false); + + loadButton = std::make_unique(tr("&Load...")); + loadButton->setToolTip(tr("Load contacts from a file")); + + saveButton = std::make_unique(tr("&Save...")); + saveButton->setToolTip(tr("Save contacts to a file")); + + exportButton = std::make_unique(tr("E&xport")); + exportButton->setToolTip(tr("Export as vCard")); + + dialog = std::make_unique(); + + connect(addButton.get(), SIGNAL(clicked()), this, SLOT(addContact())); + connect(submitButton.get(), SIGNAL(clicked()), this, SLOT(submitContact())); + connect(cancelButton.get(), SIGNAL(clicked()), this, SLOT(cancel())); + connect(nextButton.get(), SIGNAL(clicked()), this, SLOT(next())); + connect(previousButton.get(), SIGNAL(clicked()), this, SLOT(previous())); + connect(editButton.get(), SIGNAL(clicked()), this, SLOT(editContact())); + connect(removeButton.get(), SIGNAL(clicked()), this, SLOT(removeContact())); + connect(findButton.get(), SIGNAL(clicked()), this, SLOT(findContact())); + connect(loadButton.get(), SIGNAL(clicked()), this, SLOT(loadFromFile())); + connect(saveButton.get(), SIGNAL(clicked()), this, SLOT(saveToFile())); + connect(exportButton.get(), SIGNAL(clicked()), this, SLOT(exportAsVCard())); + + auto buttonLayout1 = std::make_unique(); + buttonLayout1->addWidget(addButton.get(), Qt::AlignTop); + buttonLayout1->addWidget(submitButton.get()); + buttonLayout1->addWidget(cancelButton.get()); + buttonLayout1->addWidget(findButton.get()); + buttonLayout1->addWidget(editButton.get()); + buttonLayout1->addWidget(removeButton.get()); + buttonLayout1->addWidget(loadButton.get()); + buttonLayout1->addWidget(saveButton.get()); + buttonLayout1->addWidget(exportButton.get()); + buttonLayout1->addStretch(); + + auto buttonLayout2 = std::make_unique(); + buttonLayout2->addWidget(previousButton.get()); + buttonLayout2->addWidget(nextButton.get()); + + auto mainLayout = std::make_unique(); + mainLayout->addWidget(&nameLabel, 0, 0); + mainLayout->addWidget(nameLine.get(), 0, 1); + mainLayout->addWidget(&addressLabel, 1, 0, Qt::AlignTop); + mainLayout->addWidget(addressText.get(), 1, 1); + mainLayout->addLayout(buttonLayout1, 1, 2); + mainLayout->addLayout(buttonLayout2, 2, 1); + + setLayout(mainLayout); + setWindowTitle(tr("Simple Address Book")); +} + + +void AddressBook::addContact() +{ + oldName = nameLine->text(); + oldAddress = addressText->toPlainText(); + + nameLine->clear(); + addressText->clear(); + + updateInterface(AddingMode); +} + +void AddressBook::submitContact() +{ + QString name = nameLine->text(); + QString address = addressText->toPlainText(); + + if (name.isEmpty() || address.isEmpty()) { + QMessageBox::information(this, tr("Empty Field"), + tr("Please enter a name and address.")); + return; + } + + if (currentMode == AddingMode) { + + if (!contacts.contains(name)) { + contacts.insert(name, address); + QMessageBox::information(this, tr("Add Successful"), + tr("\"%1\" has been added to your address book.").arg(name)); + } else { + QMessageBox::information(this, tr("Add Unsuccessful"), + tr("Sorry, \"%1\" is already in your address book.").arg(name)); + } + } else if (currentMode == EditingMode) { + + if (oldName != name) { + if (!contacts.contains(name)) { + QMessageBox::information(this, tr("Edit Successful"), + tr("\"%1\" has been edited in your address book.").arg(oldName)); + contacts.remove(oldName); + contacts.insert(name, address); + } else { + QMessageBox::information(this, tr("Edit Unsuccessful"), + tr("Sorry, \"%1\" is already in your address book.").arg(name)); + } + } else if (oldAddress != address) { + QMessageBox::information(this, tr("Edit Successful"), + tr("\"%1\" has been edited in your address book.").arg(name)); + contacts[name] = address; + } + } + + updateInterface(NavigationMode); +} + +void AddressBook::cancel() +{ + int number = contacts.size(); + nextButton->setEnabled(number > 1); + previousButton->setEnabled(number > 1); + + nameLine->setText(oldName); + nameLine->setReadOnly(true); + + addressText->setText(oldAddress); + addressText->setReadOnly(true); + + addButton->setEnabled(true); + submitButton->hide(); + cancelButton->hide(); +} + +void AddressBook::next() +{ + QString name = nameLine->text(); + QMap::iterator i = contacts.find(name); + + if (i != contacts.end()) + i++; + + if (i == contacts.end()) + i = contacts.begin(); + + nameLine->setText(i.key()); + addressText->setText(i.value()); +} + +void AddressBook::previous() +{ + QString name = nameLine->text(); + QMap::iterator i = contacts.find(name); + + if (i == contacts.end()){ + nameLine->clear(); + addressText->clear(); + return; + } + + if (i == contacts.begin()) + i = contacts.end(); + + i--; + nameLine->setText(i.key()); + addressText->setText(i.value()); +} + +void AddressBook::editContact() +{ + oldName = nameLine->text(); + oldAddress = addressText->toPlainText(); + + updateInterface(EditingMode); +} + +void AddressBook::removeContact() +{ + QString name = nameLine->text(); + QString address = addressText->toPlainText(); + + if (contacts.contains(name)) { + + int button = QMessageBox::question(this, + tr("Confirm Remove"), + tr("Are you sure you want to remove \"%1\"?").arg(name), + QMessageBox::Yes | QMessageBox::No); + + if (button == QMessageBox::Yes) { + + previous(); + contacts.remove(name); + + QMessageBox::information(this, tr("Remove Successful"), + tr("\"%1\" has been removed from your address book.").arg(name)); + } + } + + updateInterface(NavigationMode); +} + +void AddressBook::updateInterface(Mode mode) +{ + currentMode = mode; + + switch (currentMode) { + + case AddingMode: + case EditingMode: + + nameLine->setReadOnly(false); + nameLine->setFocus(Qt::OtherFocusReason); + addressText->setReadOnly(false); + + addButton->setEnabled(false); + editButton->setEnabled(false); + removeButton->setEnabled(false); + + nextButton->setEnabled(false); + previousButton->setEnabled(false); + + submitButton->show(); + cancelButton->show(); + break; + case NavigationMode: + + if (contacts.isEmpty()) { + nameLine->clear(); + addressText->clear(); + } + + nameLine->setReadOnly(true); + addressText->setReadOnly(true); + addButton->setEnabled(true); + + int number = contacts.size(); + editButton->setEnabled(number >= 1); + removeButton->setEnabled(number >= 1); + findButton->setEnabled(number > 1); + nextButton->setEnabled(number > 1); + previousButton->setEnabled(number >1 ); + + submitButton->hide(); + cancelButton->hide(); + break; + } +} + +void AddressBook::findContact() +{ + dialog->show(); + + if (dialog->exec() == QDialog::Accepted) { + QString contactName = dialog->getFindText(); + + if (contacts.contains(contactName)) { + nameLine->setText(contactName); + addressText->setText(contacts.value(contactName)); + } else { + QMessageBox::information(this, tr("Contact Not Found"), + tr("Sorry, \"%1\" is not in your address book.").arg(contactName)); + return; + } + } + + updateInterface(NavigationMode); +} + +void AddressBook::saveToFile() +{ + if (QString fileName = QFileDialog::getOpenFileName(this, + tr("Open Address Book"), "", + tr("Address Book (*.abk);;All Files (*)"));fileName.isEmpty()) +{ + return; +} + else { + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly)) { + QMessageBox::information(this, tr("Unable to open file"), + file.errorString()); + return; + } + QDataStream out(&file); + out.setVersion(QDataStream::Qt_4_5); + out << contacts; + } +} + +void AddressBook::loadFromFile() +{ + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open Address Book"), "", + tr("Address Book (*.abk);;All Files (*)")); + if (fileName.isEmpty()) + return; + else { + + QFile file(fileName); + + if (!file.open(QIODevice::ReadOnly)) { + QMessageBox::information(this, tr("Unable to open file"), + file.errorString()); + return; + } + + QDataStream in(&file); + in.setVersion(QDataStream::Qt_4_5); + contacts.empty(); // очищаем существующие контакты + in >> contacts; + if (contacts.isEmpty()) { + QMessageBox::information(this, tr("No contacts in file"), + tr("The file you are attempting to open contains no contacts.")); + } else { + auto i = contacts.begin(); + nameLine->setText(i.key()); + addressText->setText(i.value()); + } + } + + updateInterface(NavigationMode); +} + +void AddressBook::exportAsVCard() +{ + QString name = nameLine->text(); + QString address = addressText->toPlainText(); + QString firstName; + QString lastName; + QStringList nameList; + + int index = name.indexOf(" "); + + if (index != -1) { + nameList = name.split(QRegExp("\\s+"), QString::SkipEmptyParts); + firstName = nameList.first(); + lastName = nameList.last(); + } else { + firstName = name; + lastName = ""; + } + + QString fileName = QFileDialog::getSaveFileName(this, + tr("Export Contact"), "", + tr("vCard Files (*.vcf);;All Files (*)")); + + if (fileName.isEmpty()) + return; + + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly)) { + QMessageBox::information(this, tr("Unable to open file"), + file.errorString()); + return; + } + + QTextStream out(&file); + out << "BEGIN:VCARD" << "\n"; + out << "VERSION:2.1" << "\n"; + out << "N:" << lastName << ";" << firstName << "\n"; + + if (!nameList.isEmpty()) + out << "FN:" << nameList.join(" ") << "\n"; + else + out << "FN:" << firstName << "\n"; + address.replace(";", "\\;", Qt::CaseInsensitive); + address.replace("\n", ";", Qt::CaseInsensitive); + address.replace(",", " ", Qt::CaseInsensitive); + + out << "ADR;HOME:;" << address << "\n"; + out << "END:VCARD" << "\n"; + + QMessageBox::information(this, tr("Export Successful"), + tr("\"%1\" has been exported as a vCard.").arg(name)); +} diff --git a/trunk/ii02212/task_02/src/addressbook.h b/trunk/ii02212/task_02/src/addressbook.h new file mode 100644 index 00000000..090a01a2 --- /dev/null +++ b/trunk/ii02212/task_02/src/addressbook.h @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include "finddialog.h" + +class AddressBook : public QWidget + { + Q_OBJECT + + public: + explicit AddressBook(QWidget *parent = nullptr); + + enum class Mode { NavigationMode, AddingMode, EditingMode }; + + private: + void updateInterface(Mode mode); + + QPushButton *addButton; + QPushButton *submitButton; + QPushButton *cancelButton; + QPushButton *nextButton; + QPushButton *previousButton; + QLineEdit *nameLine; + QTextEdit *addressText; + QPushButton *editButton; + QPushButton *removeButton; + QPushButton *findButton; + FindDialog *dialog; + QPushButton *loadButton; + QPushButton *saveButton; + QPushButton *exportButton; + + + + QMap contacts; + QString oldName; + QString oldAddress; + Mode currentMode; + +public slots: + void addContact(); + void submitContact(); + void cancel(); + void next(); + void previous(); + void editContact(); + void removeContact(); + void findContact(); + void saveToFile(); + void loadFromFile(); + void exportAsVCard(); + + }; diff --git a/trunk/ii02212/task_02/src/finddialog.cpp b/trunk/ii02212/task_02/src/finddialog.cpp new file mode 100644 index 00000000..7a973e14 --- /dev/null +++ b/trunk/ii02212/task_02/src/finddialog.cpp @@ -0,0 +1,64 @@ +#include "finddialog.h" + +#include +#include +#include +#include +#include + +class FindDialog : public QDialog { + Q_OBJECT + +public: + explicit FindDialog(QWidget *parent = nullptr); + + QString getFindText() const; // Объявление публичного метода для получения текста поиска + +private slots: + void findClicked(); // Объявление приватного слота для обработки клика по кнопке + +private: + QString findText = ""; // Приватная переменная-член + std::unique_ptr lineEdit; + std::unique_ptr findButton; +}; + + +FindDialog::FindDialog(QWidget *parent) + : QDialog(parent) +{ + QLabel findLabel(tr("Enter the name of a contact:")); + lineEdit = std::make_unique(); + findButton = std::make_unique(tr("&Find")); + + + auto layout = std::make_unique(); + + layout->addWidget(&findLabel); + layout->addWidget(lineEdit.get()); + layout->addWidget(findButton.get()); + setLayout(layout); + setWindowTitle(tr("Find a Contact")); + + connect(findButton.get(), SIGNAL(clicked()), this, SLOT(findClicked())); + connect(findButton.get(), SIGNAL(clicked()), this, SLOT(accept())); +} + +void FindDialog::findClicked() +{ + QString text = lineEdit->text(); + if (text.isEmpty()) { + QMessageBox::information(this, tr("Empty Field"), + tr("Please enter a name.")); + return; + } else { + findText = text; + lineEdit->clear(); + hide(); + } +} + +QString FindDialog::getFindText() const + { + return findText; + } diff --git a/trunk/ii02212/task_02/src/finddialog.h b/trunk/ii02212/task_02/src/finddialog.h new file mode 100644 index 00000000..f432c7d3 --- /dev/null +++ b/trunk/ii02212/task_02/src/finddialog.h @@ -0,0 +1,21 @@ +#include + +class QLineEdit; +class QPushButton; + +class FindDialog : public QDialog +{ + Q_OBJECT + +public: + explicit FindDialog(QWidget *parent = nullptr); + QString getFindText(); + +public slots: + void findClicked(); + +private: + QPushButton *findButton; + QLineEdit *lineEdit; + QString findText; +}; diff --git a/trunk/ii02212/task_02/src/main.cpp b/trunk/ii02212/task_02/src/main.cpp new file mode 100644 index 00000000..c8593816 --- /dev/null +++ b/trunk/ii02212/task_02/src/main.cpp @@ -0,0 +1,16 @@ +#include "addressbook.h" +#include "mainwindow.h" + +#include + +int main(int argc, char *argv[]) +{ + + QApplication app(argc, argv); + + AddressBook addressBook; + addressBook.show(); + + return app::exec(); + +} diff --git a/trunk/ii02212/task_02/src/mainwindow.cpp b/trunk/ii02212/task_02/src/mainwindow.cpp new file mode 100644 index 00000000..dd073350 --- /dev/null +++ b/trunk/ii02212/task_02/src/mainwindow.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); +} + + diff --git a/trunk/ii02212/task_02/src/mainwindow.h b/trunk/ii02212/task_02/src/mainwindow.h new file mode 100644 index 00000000..b164082b --- /dev/null +++ b/trunk/ii02212/task_02/src/mainwindow.h @@ -0,0 +1,21 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class MainWindow; } +QT_END_NAMESPACE + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = nullptr); + + +private: + Ui::MainWindow *ui; +}; +#endif // MAINWINDOW_H diff --git a/trunk/ii02212/task_02/src/mainwindow.ui b/trunk/ii02212/task_02/src/mainwindow.ui new file mode 100644 index 00000000..b742055a --- /dev/null +++ b/trunk/ii02212/task_02/src/mainwindow.ui @@ -0,0 +1,22 @@ + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + + + + + +