#include "mainwindow.h" #include "./ui_mainwindow.h" #include #include #include #include #include #include #include "../../ApplicationConfig.h" #include "data/settingshandler.h" #include "dialogs/edititemdialog.h" #include "dialogs/newitemdialog.h" #include "genericcore.h" #include "model/tablemodel.h" static QStandardPaths::StandardLocation standardLocation = QStandardPaths::HomeLocation; static QString updateTextClean = "Do you want to update the application now?"; static QString updateTextDirty = "Do you want to save the tasks & update the application now?"; MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); m_core = std::make_unique(); setWindowTitle(QCoreApplication::applicationName() + " [*]"); /// application icon const QString iconString = "://feature.png"; #ifdef QT_DEBUG QPixmap pixmap = QPixmap(iconString); QTransform transform = QTransform(); transform.rotate(180); QPixmap rotated = pixmap.transformed(transform); setWindowIcon(QIcon(rotated)); #else setWindowIcon(QIcon(iconString)); #endif const QVariantMap settings = SettingsHandler::getSettings("GUI"); restoreGeometry(settings.value("geometry").toByteArray()); restoreState(settings.value("windowState").toByteArray()); m_tableModel = m_core->getModel(); ui->tableView->setModel(m_tableModel.get()); createActions(); createHelpMenu(); createGuiDialogs(); connect(m_core.get(), &GenericCore::displayStatusMessage, this, &MainWindow::displayStatusMessage); connect(this, &MainWindow::displayStatusMessage, this, &MainWindow::showStatusMessage); connect(this, &MainWindow::checkForUpdates, this, &MainWindow::on_actionCheck_for_update_triggered, Qt::QueuedConnection); // connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, // &MainWindow::onSelectionChanged); connect(ui->tableView->selectionModel(), &QItemSelectionModel::currentChanged, this, &MainWindow::onCurrentChanged); onSelectionChanged(QItemSelection(), QItemSelection()); onCurrentChanged(QModelIndex(), QModelIndex()); } MainWindow::~MainWindow() { delete ui; } void MainWindow::closeEvent(QCloseEvent* event) { if (isWindowModified()) { QMessageBox msgBox; msgBox.setWindowTitle(windowTitle() + " - Save dialog"); msgBox.setText("The document has been modified."); msgBox.setInformativeText("Do you want to save your changes?"); msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Save); int ret = msgBox.exec(); switch (ret) { case QMessageBox::Save: emit saveItems(); event->accept(); break; case QMessageBox::Discard: event->accept(); break; case QMessageBox::Cancel: event->ignore(); break; default: /// should never be reached qCritical() << "unexpected switch case in closeEvent:" << ret; event->ignore(); break; } } else { event->accept(); } if (event->isAccepted()) { qInfo() << "Saving GUI settings..."; SettingsHandler::saveSettings({{"geometry", saveGeometry()}, {"windowState", saveState()}}, "GUI"); } } void MainWindow::showStatusMessage(const QString text) { qInfo() << text; ui->statusbar->showMessage(text); } void MainWindow::onCurrentChanged(const QModelIndex& current, const QModelIndex& previous) { // Q_UNUSED(current); Q_UNUSED(previous); // QItemSelection localSelection = ui->tableView->selectionModel()->selection(); if (current == QModelIndex()) { // qDebug() << "Nothing selected. Disabling delete action"; m_deleteItemAct->setEnabled(false); } else { // qDebug() << "Something selected. Enabling delete action"; m_deleteItemAct->setEnabled(true); } } void MainWindow::onSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { Q_UNUSED(selected); Q_UNUSED(deselected); QItemSelection localSelection = ui->tableView->selectionModel()->selection(); if (localSelection.empty()) { // qDebug() << "Nothing selected. Disabling delete action"; m_deleteItemAct->setEnabled(false); } else { // qDebug() << "Something selected. Enabling delete action"; m_deleteItemAct->setEnabled(true); } } void MainWindow::onAboutClicked() { const QString applicationName = APPLICATION_NAME; const QString titlePrefix = tr("About "); const QString aboutText = tr(QString("%1 v%2 is a template for Qt applications." "

Working-Copy_Collective website" "

Mail to support" "

It uses the Qt Framework.") .arg(applicationName) .arg(APPLICATION_VERSION) .toLatin1()); QMessageBox::about(this, titlePrefix + applicationName, aboutText); } void MainWindow::on_actionCheck_for_update_triggered() { showStatusMessage("Checking for update..."); const bool updateAvailable = m_core->isApplicationUpdateAvailable(); if (updateAvailable) { const QString text = isWindowModified() ? updateTextDirty : updateTextClean; const QMessageBox::StandardButton clickedButton = QMessageBox::question( this, tr("Update available."), text, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if (clickedButton == QMessageBox::Yes) { m_core->triggerApplicationUpdate(); close(); } } } void MainWindow::on_pushButton_clicked() { const QString prefix("Backend provided by: "); ui->label->setText(prefix + m_core->toString()); } void MainWindow::openNewItemDialog() { showStatusMessage(tr("Invoked 'Edit|New Item'")); m_newItemDialog->show(); } void MainWindow::openEditItemDialog() { showStatusMessage(tr("Invoked 'Edit|Edit Item'")); m_editItemDialog->show(); } void MainWindow::deleteCurrentItem() { showStatusMessage(tr("Invoked 'Edit|Delete Item'")); // QItemSelection localSelection = ui->tableView->selectionModel()->selection(); const QModelIndex currentIndex = ui->tableView->selectionModel()->currentIndex(); if (currentIndex == QModelIndex()) { qDebug() << "No current item. Nothing to remove."; } else { m_tableModel->removeRows(currentIndex.row(), 1); } } void MainWindow::deleteSelectedtItems() { showStatusMessage(tr("Invoked 'Edit|Delete Item'")); QItemSelection localSelection = ui->tableView->selectionModel()->selection(); if (localSelection.empty()) { qDebug() << "No items selected. Nothing to remove."; } else { for (QList::reverse_iterator iter = localSelection.rbegin(), rend = localSelection.rend(); iter != rend; ++iter) { // qInfo() << "iter:" << *iter; // const QModelIndex parentIndex = iter->parent(); const int topRow = iter->top(); const int bottomRow = iter->bottom(); const int nRows = bottomRow - topRow + 1; m_tableModel->removeRows(topRow, nRows); } } } void MainWindow::onCleanStateChanged(bool clean) { qInfo() << "Slot onCleanStateChanged triggered: clean:" << clean; setWindowModified(!clean); if (!clean) { ui->statusbar->clearMessage(); } } void MainWindow::onShowUndoViewToggled(bool checked) { // qInfo() << "Slot onShowUndoViewToggled toggled: checked:" << checked; // m_undoView->setVisible(checked); /// workaround until m_showUndoViewAction is checkable qInfo() << "Slot onShowUndoViewToggled triggered, toggleing undo view..."; Q_UNUSED(checked); if (m_modelUndoView->isVisible()) { m_modelUndoView->setVisible(false); } else { m_modelUndoView->setVisible(true); } } void MainWindow::saveItems() { showStatusMessage(tr("Invoked 'File|Save'")); m_core->saveItems(); } void MainWindow::importCSV() { showStatusMessage(tr("Invoked 'File|Import CSV'")); const QString csvFilePath = QFileDialog::getOpenFileName( this, tr("Import CSV"), QStandardPaths::standardLocations(standardLocation).first(), tr("CSV Files (*.csv)")); if (QFileInfo::exists(csvFilePath)) { m_core->importCSVFile(csvFilePath); } else { qWarning() << "Selected CSV file path doesn't exist. Doing nothing..."; showStatusMessage(tr("Could't find CSV file!")); } } void MainWindow::createActions() { // TODO add generic menu actions (file/new, edit/cut, ...) createFileActions(); createUndoActions(); createEditActions(); } void MainWindow::createFileActions() { m_newFileAct = make_unique(tr("&New File"), this); m_newFileAct->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_N)); m_newFileAct->setStatusTip(tr("Create a new file")); // connect(m_newAct, &QAction::triggered, this, &MainWindow::newFile); m_newFileAct->setEnabled(false); ui->menu_File->addAction(m_newFileAct.get()); m_openAct = make_unique(tr("&Open..."), this); m_openAct->setShortcuts(QKeySequence::Open); m_openAct->setStatusTip(tr("Open an existing file")); // connect(m_openAct, &QAction::triggered, this, &MainWindow::open); m_openAct->setEnabled(false); ui->menu_File->addAction(m_openAct.get()); m_saveAct = make_unique(tr("&Save"), this); m_saveAct->setShortcuts(QKeySequence::Save); m_saveAct->setStatusTip(tr("Save the document to disk")); connect(m_saveAct.get(), &QAction::triggered, this, &MainWindow::saveItems); ui->menu_File->addAction(m_saveAct.get()); ui->menu_File->addSeparator(); m_importAct = make_unique(tr("&Import CSV..."), this); m_importAct->setStatusTip(tr("Import an existing CSV file")); connect(m_importAct.get(), &QAction::triggered, this, &MainWindow::importCSV); ui->menu_File->addAction(m_importAct.get()); m_exportAct = make_unique(tr("&Export CSV..."), this); m_exportAct->setStatusTip(tr("Export content to a CSV document to disk")); // connect(m_exportAct, &QAction::triggered, this, &MainWindow::exportCSV); m_exportAct->setEnabled(false); ui->menu_File->addAction(m_exportAct.get()); ui->menu_File->addSeparator(); m_printAct = make_unique(tr("&Print..."), this); m_printAct->setShortcuts(QKeySequence::Print); m_printAct->setStatusTip(tr("Print the document")); // connect(m_printAct, &QAction::triggered, this, &MainWindow::print); m_printAct->setEnabled(false); ui->menu_File->addAction(m_printAct.get()); ui->menu_File->addSeparator(); m_exitAct = make_unique(tr("E&xit"), this); m_exitAct->setShortcuts(QKeySequence::Quit); m_exitAct->setStatusTip(tr("Exit the application")); connect(m_exitAct.get(), &QAction::triggered, this, &QWidget::close); ui->menu_File->addAction(m_exitAct.get()); } void MainWindow::createUndoActions() { if (!m_core) { qCritical() << "No core instance set, aborting..."; return; } m_modelUndoStack = m_core->getModelUndoStack(); connect(m_modelUndoStack, &QUndoStack::cleanChanged, this, &MainWindow::onCleanStateChanged); m_undoAct.reset(m_modelUndoStack->createUndoAction(this, tr("&Undo"))); m_undoAct->setShortcuts(QKeySequence::Undo); m_undoAct->setStatusTip(tr("Undo the last operation")); ui->menu_Edit->addAction(m_undoAct.get()); m_redoAct.reset(m_modelUndoStack->createRedoAction(this, tr("&Redo"))); m_redoAct->setShortcuts(QKeySequence::Redo); m_redoAct->setStatusTip(tr("Redo the last operation")); ui->menu_Edit->addAction(m_redoAct.get()); m_modelUndoView = make_unique(m_modelUndoStack); m_modelUndoView->setWindowTitle(tr("Undo list")); m_modelUndoView->setAttribute(Qt::WA_QuitOnClose, false); m_modelUndoView->setMinimumSize(450, 600); m_showModelUndoViewAct = make_unique(tr("Show undo/redo window"), this); m_showModelUndoViewAct->setStatusTip(tr("Opens a window displaying the items on the undo stack")); // TODO showUndoViewAction should be checkable // m_showUndoViewAction->setCheckable(true); // connect(m_showUndoViewAction, &QAction::toggled, this, &MainWindow::onShowUndoViewToggled); connect(m_showModelUndoViewAct.get(), &QAction::triggered, this, &MainWindow::onShowUndoViewToggled); ui->menu_View->addAction(m_showModelUndoViewAct.get()); } void MainWindow::createEditActions() { m_cutAct = make_unique(tr("Cu&t"), this); m_cutAct->setShortcuts(QKeySequence::Cut); m_cutAct->setStatusTip( tr("Cut the current selection's contents to the " "clipboard")); // connect(m_cutAct, &QAction::triggered, this, &MainWindow::cut); m_cutAct->setEnabled(false); ui->menu_Edit->addAction(m_cutAct.get()); m_copyAct = make_unique(tr("&Copy"), this); m_copyAct->setShortcuts(QKeySequence::Copy); m_copyAct->setStatusTip( tr("Copy the current selection's contents to the " "clipboard")); // connect(m_copyAct, &QAction::triggered, this, &MainWindow::copy); m_copyAct->setEnabled(false); ui->menu_Edit->addAction(m_copyAct.get()); m_pasteAct = make_unique(tr("&Paste"), this); m_pasteAct->setShortcuts(QKeySequence::Paste); m_pasteAct->setStatusTip( tr("Paste the clipboard's contents into the current " "selection")); // connect(m_pasteAct, &QAction::triggered, this, &MainWindow::paste); m_pasteAct->setEnabled(false); ui->menu_Edit->addAction(m_pasteAct.get()); ui->menu_Edit->addSeparator(); m_openNewItemDialogAct = make_unique(tr("&New item"), this); m_openNewItemDialogAct->setShortcut(QKeySequence::New); m_openNewItemDialogAct->setStatusTip(tr("Opens a dialog to add a new item")); connect(m_openNewItemDialogAct.get(), &QAction::triggered, this, &MainWindow::openNewItemDialog); ui->menu_Edit->addAction(m_openNewItemDialogAct.get()); m_openEditItemDialogAct = make_unique(tr("&Edit item"), this); m_openEditItemDialogAct->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_E)); m_openEditItemDialogAct->setStatusTip(tr("Opens a edit dialog for the current item")); connect(m_openEditItemDialogAct.get(), &QAction::triggered, this, &MainWindow::openEditItemDialog); ui->menu_Edit->addAction(m_openEditItemDialogAct.get()); m_deleteItemAct = make_unique(tr("&Delete item(s)"), this); m_deleteItemAct->setShortcuts(QKeySequence::Delete); m_deleteItemAct->setStatusTip(tr("Delete currently selected item(s)")); // connect(m_deleteItemAct.get(), &QAction::triggered, this, &MainWindow::deleteSelectedtItems); connect(m_deleteItemAct.get(), &QAction::triggered, this, &MainWindow::deleteCurrentItem); ui->menu_Edit->addAction(m_deleteItemAct.get()); ui->menu_Edit->addSeparator(); m_findItemAct = make_unique(tr("&Find item(s)"), this); m_findItemAct->setShortcuts(QKeySequence::Find); m_findItemAct->setStatusTip(tr("Opens a dialog to find item(s) by containing text")); // connect(m_findItemAct, &QAction::triggered, this, &MainWindow::findItems); m_findItemAct->setEnabled(false); ui->menu_Edit->addAction(m_findItemAct.get()); } void MainWindow::createHelpMenu() { QMenu* helpMenu = ui->menu_Help; helpMenu->addSeparator(); QAction* aboutAct = helpMenu->addAction(tr("&About"), this, &MainWindow::onAboutClicked); aboutAct->setStatusTip(tr("Show the application's About box")); QAction* aboutQtAct = helpMenu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); aboutQtAct->setStatusTip(tr("Show the Qt library's About box")); } void MainWindow::createGuiDialogs() { /// new item dialog m_newItemDialog = make_unique(this); m_newItemDialog->createContent(); connect(m_newItemDialog.get(), &NewItemDialog::addItems, m_tableModel.get(), &TableModel::appendItems); /// edit item dialog m_editItemDialog = make_unique(ui->tableView, this); m_editItemDialog->createContent(); }