File indexing completed on 2024-04-28 07:39:34
0001 /* 0002 main part of parley 0003 SPDX-FileCopyrightText: 1999-2001 Ewald Arnold <kvoctrain@ewald-arnold.de> 0004 SPDX-FileCopyrightText: 2004-2007 Peter Hedlund <peter.hedlund@kdemail.net> 0005 SPDX-FileCopyrightText: 2007-2008 Frederik Gladhorn <frederik.gladhorn@kdemail.net> 0006 SPDX-FileCopyrightText: 2008 Daniel Laidig <d.laidig@gmx.de> 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "parleymainwindow.h" 0011 #include "dashboard/dashboard.h" 0012 #include "editor/editor.h" 0013 #include "parleyactions.h" 0014 #include "practice/configure/configurepracticedialog.h" 0015 #include "practice/guifrontend.h" 0016 #include "practice/practicesummarycomponent.h" 0017 #include "prefs.h" 0018 #include "settings/parleyprefs.h" 0019 #include "statistics/statisticsmainwindow.h" 0020 #include <KActionCollection> 0021 #include <KMessageBox> 0022 #include <KNSWidgets/Action> 0023 #include <KRecentFilesAction> 0024 #include <KToolBar> 0025 #include <KXMLGUIFactory> 0026 #include <QMenuBar> 0027 #include <QTimer> 0028 #include <config-parley.h> 0029 0030 using namespace Editor; 0031 0032 ParleyMainWindow *ParleyMainWindow::s_instance = nullptr; 0033 ParleyMainWindow *ParleyMainWindow::instance() 0034 { 0035 return s_instance; 0036 } 0037 0038 ParleyMainWindow::ParleyMainWindow(const QUrl &filename) 0039 : KXmlGuiWindow(nullptr) 0040 , m_currentComponent(NoComponent) 0041 , m_sessionManager(this) 0042 { 0043 s_instance = this; 0044 m_document = new ParleyDocument(this); 0045 0046 connect(m_document, &ParleyDocument::documentChanged, this, &ParleyMainWindow::documentUpdated); 0047 0048 setCentralWidget(new QWidget()); 0049 centralWidget()->setLayout(new QHBoxLayout()); 0050 centralWidget()->layout()->setContentsMargins(0, 0, 0, 0); 0051 0052 initActions(); 0053 0054 bool startWithDashboard = false; 0055 0056 setupGUI(ToolBar | Keys | Create); ///@todo frameworks KXMLGui warnings 0057 0058 if (!filename.isEmpty()) { 0059 m_document->open(filename); 0060 } else { 0061 bool openLastFile = Prefs::autoOpenLast(); 0062 if (openLastFile && m_recentFilesAction->actions().count() > 0 0063 && m_recentFilesAction->action(m_recentFilesAction->actions().count() - 1)->isEnabled()) { 0064 m_recentFilesAction->action(m_recentFilesAction->actions().count() - 1)->trigger(); 0065 } else { 0066 startWithDashboard = true; 0067 } 0068 } 0069 0070 // save position of dock windows etc 0071 setAutoSaveSettings(); 0072 0073 if (startWithDashboard) { 0074 showDashboard(); 0075 } else { 0076 showEditor(); 0077 } 0078 0079 connect(this, &ParleyMainWindow::preferencesChanged, this, &ParleyMainWindow::slotApplyPreferences); 0080 menuBar()->show(); 0081 } 0082 0083 ParleyMainWindow::~ParleyMainWindow() 0084 { 0085 guiFactory()->removeClient(m_currentComponentWindow); 0086 centralWidget()->layout()->removeWidget(m_currentComponentWindow); 0087 delete m_currentComponentWindow; 0088 0089 // Prevent calling this slot with already deleted m_document as it is no longer needed anyway 0090 if (m_document->document()) { 0091 disconnect(m_document->document().get(), &KEduVocDocument::destroyed, this, &ParleyMainWindow::slotUpdateWindowCaption); 0092 } 0093 delete m_document; 0094 } 0095 0096 void ParleyMainWindow::addRecentFile(const QUrl &url, const QString &name) 0097 { 0098 m_recentFilesAction->addUrl(url, name); 0099 m_recentFilesAction->saveEntries(KSharedConfig::openConfig()->group("Recent Files")); 0100 } 0101 0102 void ParleyMainWindow::removeRecentFile(const QUrl &url) 0103 { 0104 m_recentFilesAction->removeUrl(url); 0105 m_recentFilesAction->saveEntries(KSharedConfig::openConfig()->group("Recent Files")); 0106 } 0107 0108 void ParleyMainWindow::documentUpdated(const std::shared_ptr<KEduVocDocument> &doc) 0109 { 0110 if (doc) { 0111 connect(doc.get(), &KEduVocDocument::docModified, this, &ParleyMainWindow::slotUpdateWindowCaption); 0112 connect(doc.get(), &KEduVocDocument::destroyed, this, &ParleyMainWindow::slotUpdateWindowCaption); 0113 slotUpdateWindowCaption(); 0114 } 0115 } 0116 0117 void ParleyMainWindow::updateRecentFilesModel() 0118 { 0119 Q_EMIT recentFilesChanged(); 0120 } 0121 0122 void ParleyMainWindow::saveOptions() 0123 { 0124 Prefs::self()->save(); 0125 } 0126 0127 void ParleyMainWindow::slotUpdateWindowCaption() 0128 { 0129 QString title; 0130 bool modified = false; 0131 if (m_document->document()) { 0132 title = i18nc("Title and a modified status indicator. [*] is exact and will be shown only when document is modified", 0133 "%1 [*]", 0134 m_document->document()->title()); 0135 modified = m_document->document()->isModified(); 0136 if (title == i18n("Untitled")) { 0137 title = QStringLiteral("[*]"); 0138 } 0139 } 0140 setCaption(title, modified); 0141 } 0142 0143 void ParleyMainWindow::slotGeneralOptions() 0144 { 0145 ParleyPrefs *dialog = new ParleyPrefs(m_document->document().get(), this, QStringLiteral("settings"), Prefs::self()); 0146 connect(dialog, &ParleyPrefs::settingsChanged, this, &ParleyMainWindow::preferencesChanged); 0147 dialog->show(); 0148 } 0149 0150 void ParleyMainWindow::slotApplyPreferences() 0151 { 0152 m_document->enableAutoBackup((m_currentComponent != DashboardComponent) && Prefs::autoBackup()); 0153 } 0154 0155 void ParleyMainWindow::slotCloseDocument() 0156 { 0157 if (!queryClose()) { 0158 return; 0159 } 0160 showDashboard(); 0161 m_document->close(); 0162 } 0163 0164 void ParleyMainWindow::configurePractice() 0165 { 0166 ConfigurePracticeDialog configurePracticeDialog(m_document->document().get(), this, QStringLiteral("practice settings"), Prefs::self()); 0167 configurePracticeDialog.exec(); 0168 } 0169 0170 void ParleyMainWindow::startPractice() 0171 { 0172 if (Prefs::learningLanguage() == Prefs::knownLanguage()) { 0173 KMessageBox::error(this, i18n("You cannot start to practice when the known language is the same as the language to learn."), i18n("Select languages")); 0174 return; 0175 } 0176 qDebug() << "Starting Switch Practice"; 0177 switchComponent(PracticeComponent); 0178 qDebug() << "Finished Switch Practice"; 0179 } 0180 0181 void ParleyMainWindow::practiceFinished() 0182 { 0183 switchComponent(m_componentBeforePractice); 0184 } 0185 0186 bool ParleyMainWindow::queryClose() 0187 { 0188 if (m_document->queryClose()) { 0189 Prefs::self()->save(); 0190 return true; 0191 } 0192 return false; 0193 } 0194 0195 QSize ParleyMainWindow::sizeHint() const 0196 { 0197 return QSize(800, 600).expandedTo(KXmlGuiWindow::minimumSizeHint()); 0198 } 0199 0200 void ParleyMainWindow::slotFileNew() 0201 { 0202 m_document->slotFileNew(); 0203 slotUpdateWindowCaption(); 0204 } 0205 0206 void ParleyMainWindow::initActions() 0207 { 0208 ParleyActions::create(ParleyActions::FileNew, this, SLOT(slotFileNew()), actionCollection()); 0209 ParleyActions::create(ParleyActions::FileOpen, m_document, SLOT(slotFileOpen()), actionCollection()); 0210 0211 KNSWidgets::Action *pAction = new KNSWidgets::Action(i18n("Download New Vocabularies..."), QStringLiteral("parley.knsrc"), actionCollection()); 0212 actionCollection()->addAction(QStringLiteral("file_ghns"), pAction); 0213 QObject::connect(pAction, &KNSWidgets::Action::dialogFinished, m_document, &ParleyDocument::slotGHNS); 0214 0215 pAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_G)); 0216 actionCollection()->setDefaultShortcut(pAction, QKeySequence(Qt::CTRL | Qt::Key_G)); 0217 pAction->setToolTip(i18n("Downloads new vocabulary collections")); 0218 0219 ParleyActions::create(ParleyActions::FileOpenDownloaded, m_document, SLOT(openGHNS()), actionCollection()); 0220 0221 m_recentFilesAction = ParleyActions::createRecentFilesAction(m_document, SLOT(slotFileOpenRecent(QUrl)), actionCollection()); 0222 m_recentFilesAction->loadEntries(KSharedConfig::openConfig()->group("Recent Files")); 0223 0224 ParleyActions::create(ParleyActions::FileSave, m_document, SLOT(save()), actionCollection()); 0225 ParleyActions::create(ParleyActions::FileSaveAs, m_document, SLOT(saveAs()), actionCollection()); 0226 #ifdef HAVE_LIBXSLT 0227 ParleyActions::create(ParleyActions::FileExport, m_document, SLOT(exportDialog()), actionCollection()); 0228 #endif 0229 0230 ParleyActions::create(ParleyActions::FileProperties, m_document, SLOT(documentProperties()), actionCollection()); 0231 0232 ParleyActions::create(ParleyActions::FileClose, this, SLOT(slotCloseDocument()), actionCollection()); 0233 ParleyActions::create(ParleyActions::FileQuit, this, SLOT(close()), actionCollection()); 0234 ParleyActions::create(ParleyActions::Preferences, this, SLOT(slotGeneralOptions()), actionCollection()); 0235 } 0236 0237 void ParleyMainWindow::showDashboard() 0238 { 0239 switchComponent(DashboardComponent); 0240 } 0241 0242 void ParleyMainWindow::showEditor() 0243 { 0244 switchComponent(EditorComponent); 0245 } 0246 0247 void ParleyMainWindow::showPracticeConfiguration() 0248 { 0249 switchComponent(ConfigurePracticeComponent); 0250 } 0251 0252 void ParleyMainWindow::showPractice() 0253 { 0254 switchComponent(PracticeComponent); 0255 } 0256 0257 void ParleyMainWindow::showPracticeSummary() 0258 { 0259 switchComponent(PracticeSummary); 0260 } 0261 0262 void ParleyMainWindow::switchComponent(Component component) 0263 { 0264 if (component == PracticeComponent) { 0265 StatisticsMainWindow *statisticsWidget = qobject_cast<StatisticsMainWindow *>(m_currentComponentWindow); 0266 if (statisticsWidget) { 0267 statisticsWidget->syncConfig(); 0268 } 0269 0270 // Don't start a practice when there are no words to practice. 0271 // This has to be checked before deleting the old component. 0272 m_sessionManager.setDocument(m_document->document().get()); 0273 if (!m_sessionManager.allEntryCount()) { 0274 return; 0275 } 0276 } 0277 0278 // Remove and delete the old component window if there is one active. 0279 if (m_currentComponentWindow) { 0280 guiFactory()->removeClient(m_currentComponentWindow); 0281 centralWidget()->layout()->removeWidget(m_currentComponentWindow); 0282 m_currentComponentWindow->deleteLater(); 0283 } 0284 0285 switch (component) { 0286 case DashboardComponent: { 0287 Dashboard *dashboard = new Dashboard(this); 0288 m_currentComponentWindow = dashboard; 0289 showDocumentActions(true, false); 0290 // dashboard->updateRecentFilesModel(); 0291 break; 0292 } 0293 case ConfigurePracticeComponent: { 0294 StatisticsMainWindow *statisticsWidget = new StatisticsMainWindow(m_document->document(), this); 0295 m_currentComponentWindow = statisticsWidget; 0296 showDocumentActions(true, true); 0297 break; 0298 } 0299 case EditorComponent: { 0300 EditorWindow *editor = new EditorWindow(this); 0301 m_currentComponentWindow = editor; 0302 showDocumentActions(true, true); 0303 editor->updateDocument(m_document->document()); 0304 break; 0305 } 0306 case PracticeComponent: { 0307 ///@todo trust the dirty bit 0308 m_document->document()->setModified(true); 0309 Practice::PracticeMainWindow *practiceWindow = new Practice::PracticeMainWindow(&m_sessionManager, this); 0310 connect(practiceWindow, &Practice::PracticeMainWindow::stopPractice, this, &ParleyMainWindow::showPracticeSummary); 0311 m_currentComponentWindow = practiceWindow; 0312 qDebug() << " Practice Slotted up"; 0313 showDocumentActions(false, false); 0314 practiceWindow->startPractice(); 0315 qDebug() << " Practice Slotted up2"; 0316 break; 0317 } 0318 case PracticeSummary: { 0319 Practice::PracticeSummaryComponent *summary = new Practice::PracticeSummaryComponent(&m_sessionManager, this); 0320 m_currentComponentWindow = summary; 0321 showDocumentActions(true, true); 0322 break; 0323 } 0324 default: 0325 break; 0326 } 0327 // qDebug() << "new component" << m_currentComponentWindow; 0328 0329 guiFactory()->addClient(m_currentComponentWindow); 0330 centralWidget()->layout()->addWidget(m_currentComponentWindow); 0331 m_currentComponentWindow->show(); 0332 switch (component) { 0333 case DashboardComponent: { 0334 setVisibleToolbar(QString()); 0335 break; 0336 } 0337 case ConfigurePracticeComponent: { 0338 setVisibleToolbar(QStringLiteral("statisticsToolBar")); 0339 break; 0340 } 0341 case EditorComponent: { 0342 setVisibleToolbar(QStringLiteral("editorToolBar")); 0343 break; 0344 } 0345 case PracticeComponent: { 0346 setVisibleToolbar(QStringLiteral("practiceToolBar")); 0347 break; 0348 } 0349 case PracticeSummary: { 0350 setVisibleToolbar(QStringLiteral("practiceSummaryToolBar")); 0351 break; 0352 } 0353 default: 0354 break; 0355 } 0356 m_currentComponent = component; 0357 setupToolbarMenuActions(); 0358 } 0359 0360 void ParleyMainWindow::showDocumentActions(bool open, bool edit) 0361 { 0362 actionCollection()->action(QStringLiteral("file_new"))->setVisible(open); 0363 actionCollection()->action(QStringLiteral("file_open"))->setVisible(open); 0364 actionCollection()->action(QStringLiteral("file_open_recent"))->setVisible(open); 0365 actionCollection()->action(QStringLiteral("file_open_downloaded"))->setVisible(open); 0366 0367 actionCollection()->action(QStringLiteral("file_save"))->setVisible(edit); 0368 actionCollection()->action(QStringLiteral("file_save_as"))->setVisible(edit); 0369 actionCollection()->action(QStringLiteral("file_close"))->setVisible(edit); 0370 #ifdef HAVE_LIBXSLT 0371 actionCollection()->action("file_export")->setVisible(edit); 0372 #endif 0373 actionCollection()->action(QStringLiteral("file_properties"))->setVisible(edit); 0374 actionCollection()->action(QStringLiteral("file_close"))->setVisible(edit); 0375 } 0376 0377 void ParleyMainWindow::setVisibleToolbar(const QString &name) 0378 { 0379 const QList<KToolBar *> toolbars = toolBars(); 0380 for (KToolBar *toolbar : toolbars) { 0381 if (toolbar && toolbar->objectName() == name) { 0382 toolbar->show(); 0383 } else if (toolbar) { 0384 toolbar->hide(); 0385 } 0386 } 0387 } 0388 0389 ParleyDocument *ParleyMainWindow::parleyDocument() 0390 { 0391 return m_document; 0392 } 0393 0394 ParleyMainWindow::Component ParleyMainWindow::currentComponent() 0395 { 0396 return m_currentComponent; 0397 } 0398 0399 #include "moc_parleymainwindow.cpp"