Warning, file /sdk/lokalize/src/lokalizemainwindow.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 This file is part of Lokalize 0003 0004 SPDX-FileCopyrightText: 2008-2015 Nick Shaforostoff <shafff@ukr.net> 0005 SPDX-FileCopyrightText: 2018-2019 Simon Depiets <sdepiets@gmail.com> 0006 0007 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0008 */ 0009 0010 #include "lokalizemainwindow.h" 0011 0012 #include "lokalize_debug.h" 0013 0014 #include "actionproxy.h" 0015 #include "editortab.h" 0016 #include "projecttab.h" 0017 #include "tmtab.h" 0018 #include "jobs.h" 0019 #include "filesearchtab.h" 0020 #include "prefs_lokalize.h" 0021 0022 // #define WEBQUERY_ENABLE 0023 0024 #include "project.h" 0025 #include "projectmodel.h" 0026 #include "projectlocal.h" 0027 #include "prefs.h" 0028 0029 #include "tools/widgettextcaptureconfig.h" 0030 0031 #include "multieditoradaptor.h" 0032 0033 #include <KLocalizedString> 0034 #include <KMessageBox> 0035 #include <KNotification> 0036 #include <KActionCollection> 0037 #include <KActionCategory> 0038 #include <KStandardAction> 0039 #include <KStandardShortcut> 0040 #include <KRecentFilesAction> 0041 #include <KXMLGUIFactory> 0042 0043 0044 #include <QMenu> 0045 #include <QTabBar> 0046 #include <QActionGroup> 0047 #include <QMdiSubWindow> 0048 #include <QMdiArea> 0049 #include <QMenuBar> 0050 #include <QStatusBar> 0051 #include <QLabel> 0052 #include <QIcon> 0053 #include <QApplication> 0054 #include <QElapsedTimer> 0055 0056 0057 LokalizeMainWindow::LokalizeMainWindow() 0058 : KXmlGuiWindow() 0059 , m_mdiArea(new LokalizeMdiArea) 0060 , m_prevSubWindow(nullptr) 0061 , m_projectSubWindow(nullptr) 0062 , m_translationMemorySubWindow(nullptr) 0063 , m_editorActions(new QActionGroup(this)) 0064 , m_managerActions(new QActionGroup(this)) 0065 , m_spareEditor(new EditorTab(this, false)) 0066 , m_multiEditorAdaptor(new MultiEditorAdaptor(m_spareEditor)) 0067 { 0068 m_spareEditor->hide(); 0069 m_mdiArea->setViewMode(QMdiArea::TabbedView); 0070 m_mdiArea->setActivationOrder(QMdiArea::ActivationHistoryOrder); 0071 m_mdiArea->setDocumentMode(true); 0072 m_mdiArea->setTabsMovable(true); 0073 m_mdiArea->setTabsClosable(true); 0074 0075 setCentralWidget(m_mdiArea); 0076 connect(m_mdiArea, &QMdiArea::subWindowActivated, this, &LokalizeMainWindow::slotSubWindowActivated); 0077 setupActions(); 0078 0079 //prevent relayout of dockwidgets 0080 m_mdiArea->setOption(QMdiArea::DontMaximizeSubWindowOnActivation, true); 0081 0082 connect(Project::instance(), QOverload<const QString &, const bool>::of(&Project::fileOpenRequested), this, QOverload<QString, const bool>::of(&LokalizeMainWindow::fileOpen_), Qt::QueuedConnection); 0083 connect(Project::instance(), &Project::configChanged, this, &LokalizeMainWindow::projectSettingsChanged); 0084 connect(Project::instance(), &Project::closed, this, &LokalizeMainWindow::closeProject); 0085 showProjectOverview(); 0086 showTranslationMemory(); //fix for #342558 0087 0088 for (int i = ID_STATUS_CURRENT; i <= ID_STATUS_ISFUZZY; i++) { 0089 m_statusBarLabels.append(new QLabel()); 0090 statusBar()->insertWidget(i, m_statusBarLabels.last(), 2); 0091 } 0092 0093 setAttribute(Qt::WA_DeleteOnClose, true); 0094 0095 0096 if (!qApp->isSessionRestored()) { 0097 KConfig config; 0098 KConfigGroup stateGroup(&config, "State"); 0099 readProperties(stateGroup); 0100 } 0101 0102 registerDBusAdaptor(); 0103 0104 QTimer::singleShot(0, this, &LokalizeMainWindow::initLater); 0105 } 0106 0107 void LokalizeMainWindow::initLater() 0108 { 0109 if (!m_prevSubWindow && m_projectSubWindow) 0110 slotSubWindowActivated(m_projectSubWindow); 0111 0112 if (!Project::instance()->isTmSupported()) { 0113 KNotification* notification = new KNotification("NoSqlModulesAvailable"); 0114 notification->setWidget(this); 0115 notification->setText(i18nc("@info", "No Qt Sql modules were found. Translation memory will not work.")); 0116 notification->sendEvent(); 0117 } 0118 } 0119 0120 LokalizeMainWindow::~LokalizeMainWindow() 0121 { 0122 TM::cancelAllJobs(); 0123 0124 KConfig config; 0125 KConfigGroup stateGroup(&config, "State"); 0126 if (!m_lastEditorState.isEmpty()) { 0127 stateGroup.writeEntry("DefaultDockWidgets", m_lastEditorState); 0128 } 0129 saveProjectState(stateGroup); 0130 m_multiEditorAdaptor->deleteLater(); 0131 0132 //Disconnect the signals pointing to this MainWindow object 0133 QMdiSubWindow* sw; 0134 for (int i = 0; i < m_fileToEditor.values().count(); i++) { 0135 sw = m_fileToEditor.values().at(i); 0136 disconnect(sw, &QMdiSubWindow::destroyed, this, &LokalizeMainWindow::editorClosed); 0137 EditorTab* w = static_cast<EditorTab*>(sw->widget()); 0138 disconnect(w, &EditorTab::aboutToBeClosed, this, &LokalizeMainWindow::resetMultiEditorAdaptor); 0139 disconnect(w, QOverload<const QString &, const QString &, const QString &, const bool>::of(&EditorTab::fileOpenRequested), this, QOverload<const QString &, const QString &, const QString &, const bool>::of(&LokalizeMainWindow::fileOpen)); 0140 disconnect(w, QOverload<const QString &, const QString &>::of(&EditorTab::tmLookupRequested), this, QOverload<const QString &, const QString &>::of(&LokalizeMainWindow::lookupInTranslationMemory)); 0141 } 0142 0143 qCWarning(LOKALIZE_LOG) << "MainWindow destroyed"; 0144 } 0145 0146 void LokalizeMainWindow::slotSubWindowActivated(QMdiSubWindow* w) 0147 { 0148 //QTime aaa;aaa.start(); 0149 if (!w || m_prevSubWindow == w) 0150 return; 0151 0152 w->setUpdatesEnabled(true); //QTBUG-23289 0153 0154 if (m_prevSubWindow) { 0155 m_prevSubWindow->setUpdatesEnabled(false); 0156 LokalizeSubwindowBase* prevEditor = static_cast<LokalizeSubwindowBase2*>(m_prevSubWindow->widget()); 0157 prevEditor->hideDocks(); 0158 guiFactory()->removeClient(prevEditor->guiClient()); 0159 prevEditor->statusBarItems.unregisterStatusBar(); 0160 0161 if (qobject_cast<EditorTab*>(prevEditor)) { 0162 EditorTab* w = static_cast<EditorTab*>(prevEditor); 0163 EditorState state = w->state(); 0164 m_lastEditorState = state.dockWidgets.toBase64(); 0165 } 0166 } 0167 LokalizeSubwindowBase* editor = static_cast<LokalizeSubwindowBase2*>(w->widget()); 0168 0169 editor->reloadUpdatedXML(); 0170 if (qobject_cast<EditorTab*>(editor)) { 0171 EditorTab* w = static_cast<EditorTab*>(editor); 0172 w->setProperFocus(); 0173 0174 EditorState state = w->state(); 0175 m_lastEditorState = state.dockWidgets.toBase64(); 0176 0177 m_multiEditorAdaptor->setEditorTab(w); 0178 0179 QTabBar* tw = m_mdiArea->findChild<QTabBar*>(); 0180 if (tw) tw->setTabToolTip(tw->currentIndex(), w->currentFilePath()); 0181 0182 Q_EMIT editorActivated(); 0183 } else if (w == m_projectSubWindow && m_projectSubWindow) { 0184 QTabBar* tw = m_mdiArea->findChild<QTabBar*>(); 0185 if (tw) tw->setTabToolTip(tw->currentIndex(), Project::instance()->path()); 0186 } 0187 0188 editor->showDocks(); 0189 editor->statusBarItems.registerStatusBar(statusBar(), m_statusBarLabels); 0190 guiFactory()->addClient(editor->guiClient()); 0191 0192 m_prevSubWindow = w; 0193 0194 //qCWarning(LOKALIZE_LOG)<<"finished"<<aaa.elapsed(); 0195 } 0196 0197 0198 bool LokalizeMainWindow::queryClose() 0199 { 0200 QList<QMdiSubWindow*> editors = m_mdiArea->subWindowList(); 0201 int i = editors.size(); 0202 while (--i >= 0) { 0203 //if (editors.at(i)==m_projectSubWindow) 0204 if (!qobject_cast<EditorTab*>(editors.at(i)->widget())) 0205 continue; 0206 if (!static_cast<EditorTab*>(editors.at(i)->widget())->queryClose()) 0207 return false; 0208 } 0209 0210 bool ok = Project::instance()->queryCloseForAuxiliaryWindows(); 0211 0212 if (ok) { 0213 QThreadPool::globalInstance()->clear(); 0214 Project::instance()->model()->threadPool()->clear(); 0215 } 0216 return ok; 0217 } 0218 EditorTab* LokalizeMainWindow::fileOpen_(QString filePath, const bool setAsActive) 0219 { 0220 return fileOpen(filePath, 0, setAsActive); 0221 } 0222 EditorTab* LokalizeMainWindow::fileOpen(QString filePath, int entry, bool setAsActive, const QString& mergeFile, bool silent) 0223 { 0224 if (filePath.length()) { 0225 FileToEditor::const_iterator it = m_fileToEditor.constFind(filePath); 0226 if (it != m_fileToEditor.constEnd()) { 0227 qCWarning(LOKALIZE_LOG) << "already opened:" << filePath; 0228 if (QMdiSubWindow* sw = it.value()) { 0229 m_mdiArea->setActiveSubWindow(sw); 0230 return static_cast<EditorTab*>(sw->widget()); 0231 } 0232 } 0233 } 0234 0235 QByteArray state = m_lastEditorState; 0236 EditorTab* w = new EditorTab(this); 0237 0238 QMdiSubWindow* sw = nullptr; 0239 //create QMdiSubWindow BEFORE fileOpen() because it causes some strange QMdiArea behaviour otherwise 0240 if (filePath.length()) 0241 sw = m_mdiArea->addSubWindow(w); 0242 0243 QString suggestedDirPath; 0244 QMdiSubWindow* activeSW = m_mdiArea->currentSubWindow(); 0245 if (activeSW && qobject_cast<LokalizeSubwindowBase*>(activeSW->widget())) { 0246 QString fp = static_cast<LokalizeSubwindowBase*>(activeSW->widget())->currentFilePath(); 0247 if (fp.length()) suggestedDirPath = QFileInfo(fp).absolutePath(); 0248 } 0249 0250 if (!w->fileOpen(filePath, suggestedDirPath, m_fileToEditor, silent)) { 0251 if (sw) { 0252 m_mdiArea->removeSubWindow(sw); 0253 sw->deleteLater(); 0254 } 0255 w->deleteLater(); 0256 return nullptr; 0257 } 0258 filePath = w->currentFilePath(); 0259 m_openRecentFileAction->addUrl(QUrl::fromLocalFile(filePath));//(w->currentUrl()); 0260 0261 if (!sw) 0262 sw = m_mdiArea->addSubWindow(w); 0263 w->showMaximized(); 0264 sw->showMaximized(); 0265 0266 if (!state.isEmpty()) { 0267 w->restoreState(QByteArray::fromBase64(state)); 0268 m_lastEditorState = state; 0269 } else { 0270 //Dummy restore to "initialize" widgets 0271 w->restoreState(w->saveState()); 0272 } 0273 0274 if (entry/* || offset*/) 0275 w->gotoEntry(DocPosition(entry/*, DocPosition::Target, 0, offset*/)); 0276 if (setAsActive) { 0277 m_toBeActiveSubWindow = sw; 0278 QTimer::singleShot(0, this, &LokalizeMainWindow::applyToBeActiveSubWindow); 0279 } else { 0280 m_mdiArea->setActiveSubWindow(activeSW); 0281 sw->setUpdatesEnabled(false); //QTBUG-23289 0282 } 0283 0284 if (!mergeFile.isEmpty()) 0285 w->mergeOpen(mergeFile); 0286 0287 connect(sw, &QMdiSubWindow::destroyed, this, &LokalizeMainWindow::editorClosed); 0288 connect(w, &EditorTab::aboutToBeClosed, this, &LokalizeMainWindow::resetMultiEditorAdaptor); 0289 connect(w, QOverload<const QString &, const QString &, const QString &, const bool>::of(&EditorTab::fileOpenRequested), this, QOverload<const QString &, const QString &, const QString &, const bool>::of(&LokalizeMainWindow::fileOpen)); 0290 connect(w, QOverload<const QString &, const QString &>::of(&EditorTab::tmLookupRequested), this, QOverload<const QString &, const QString &>::of(&LokalizeMainWindow::lookupInTranslationMemory)); 0291 0292 QStringRef fnSlashed = filePath.midRef(filePath.lastIndexOf('/')); 0293 FileToEditor::const_iterator i = m_fileToEditor.constBegin(); 0294 while (i != m_fileToEditor.constEnd()) { 0295 if (i.key().endsWith(fnSlashed)) { 0296 static_cast<EditorTab*>(i.value()->widget())->setFullPathShown(true); 0297 w->setFullPathShown(true); 0298 } 0299 ++i; 0300 } 0301 m_fileToEditor.insert(filePath, sw); 0302 0303 sw->setAttribute(Qt::WA_DeleteOnClose, true); 0304 Q_EMIT editorAdded(); 0305 return w; 0306 } 0307 0308 void LokalizeMainWindow::resetMultiEditorAdaptor() 0309 { 0310 m_multiEditorAdaptor->setEditorTab(m_spareEditor); //it will be reparented shortly if there are other editors 0311 } 0312 0313 void LokalizeMainWindow::editorClosed(QObject* obj) 0314 { 0315 m_fileToEditor.remove(m_fileToEditor.key(static_cast<QMdiSubWindow*>(obj))); 0316 } 0317 0318 EditorTab* LokalizeMainWindow::fileOpen(const QString& filePath, const QString& source, const QString& ctxt, const bool setAsActive) 0319 { 0320 EditorTab* w = fileOpen(filePath, 0, setAsActive); 0321 if (!w) 0322 return nullptr;//TODO message 0323 w->findEntryBySourceContext(source, ctxt); 0324 return w; 0325 } 0326 EditorTab* LokalizeMainWindow::fileOpen(const QString& filePath, DocPosition docPos, int selection, const bool setAsActive) 0327 { 0328 EditorTab* w = fileOpen(filePath, 0, setAsActive); 0329 if (!w) 0330 return nullptr;//TODO message 0331 w->gotoEntry(docPos, selection); 0332 return w; 0333 } 0334 0335 QObject* LokalizeMainWindow::projectOverview() 0336 { 0337 if (!m_projectSubWindow) { 0338 ProjectTab* w = new ProjectTab(this); 0339 m_projectSubWindow = m_mdiArea->addSubWindow(w); 0340 w->showMaximized(); 0341 m_projectSubWindow->showMaximized(); 0342 connect(w, QOverload<const QString &, const bool>::of(&ProjectTab::fileOpenRequested), this, QOverload<QString, const bool>::of(&LokalizeMainWindow::fileOpen_)); 0343 connect(w, QOverload<QString>::of(&ProjectTab::projectOpenRequested), this, QOverload<QString>::of(&LokalizeMainWindow::openProject)); 0344 connect(w, QOverload<>::of(&ProjectTab::projectOpenRequested), this, QOverload<>::of(&LokalizeMainWindow::openProject)); 0345 connect(w, QOverload<const QStringList &>::of(&ProjectTab::searchRequested), this, QOverload<const QStringList &>::of(&LokalizeMainWindow::addFilesToSearch)); 0346 } 0347 if (m_mdiArea->currentSubWindow() == m_projectSubWindow) 0348 return m_projectSubWindow->widget(); 0349 return nullptr; 0350 } 0351 0352 void LokalizeMainWindow::showProjectOverview() 0353 { 0354 projectOverview(); 0355 m_mdiArea->setActiveSubWindow(m_projectSubWindow); 0356 } 0357 0358 TM::TMTab* LokalizeMainWindow::showTM() 0359 { 0360 if (!Project::instance()->isTmSupported()) { 0361 KMessageBox::information(nullptr, i18n("TM facility requires SQLite Qt module."), i18n("No SQLite module available")); 0362 return nullptr; 0363 } 0364 0365 if (!m_translationMemorySubWindow) { 0366 TM::TMTab* w = new TM::TMTab(this); 0367 m_translationMemorySubWindow = m_mdiArea->addSubWindow(w); 0368 w->showMaximized(); 0369 m_translationMemorySubWindow->showMaximized(); 0370 connect(w, QOverload<const QString &, const QString &, const QString &, const bool>::of(&TM::TMTab::fileOpenRequested), this, QOverload<const QString &, const QString &, const QString &, const bool>::of(&LokalizeMainWindow::fileOpen)); 0371 } 0372 0373 m_mdiArea->setActiveSubWindow(m_translationMemorySubWindow); 0374 return static_cast<TM::TMTab*>(m_translationMemorySubWindow->widget()); 0375 } 0376 0377 FileSearchTab* LokalizeMainWindow::showFileSearch(bool activate) 0378 { 0379 EditorTab* precedingEditor = qobject_cast<EditorTab*>(activeEditor()); 0380 0381 if (!m_fileSearchSubWindow) { 0382 FileSearchTab* w = new FileSearchTab(this); 0383 m_fileSearchSubWindow = m_mdiArea->addSubWindow(w); 0384 w->showMaximized(); 0385 m_fileSearchSubWindow->showMaximized(); 0386 connect(w, QOverload<const QString &, DocPosition, int, const bool>::of(&FileSearchTab::fileOpenRequested), this, QOverload<const QString &, DocPosition, int, const bool>::of(&LokalizeMainWindow::fileOpen)); 0387 connect(w, QOverload<const QString &, const bool>::of(&FileSearchTab::fileOpenRequested), this, QOverload<QString, const bool>::of(&LokalizeMainWindow::fileOpen_)); 0388 } 0389 0390 if (activate) { 0391 m_mdiArea->setActiveSubWindow(m_fileSearchSubWindow); 0392 if (precedingEditor) { 0393 if (precedingEditor->selectionInSource().length()) 0394 static_cast<FileSearchTab*>(m_fileSearchSubWindow->widget())->setSourceQuery(precedingEditor->selectionInSource()); 0395 if (precedingEditor->selectionInTarget().length()) 0396 static_cast<FileSearchTab*>(m_fileSearchSubWindow->widget())->setTargetQuery(precedingEditor->selectionInTarget()); 0397 } 0398 } 0399 return static_cast<FileSearchTab*>(m_fileSearchSubWindow->widget()); 0400 } 0401 0402 void LokalizeMainWindow::fileSearchNext() 0403 { 0404 FileSearchTab* w = showFileSearch(/*activate=*/false); 0405 //TODO fill search params based on current selection 0406 w->fileSearchNext(); 0407 } 0408 0409 void LokalizeMainWindow::addFilesToSearch(const QStringList& files) 0410 { 0411 FileSearchTab* w = showFileSearch(); 0412 w->addFilesToSearch(files); 0413 } 0414 0415 0416 void LokalizeMainWindow::applyToBeActiveSubWindow() 0417 { 0418 m_mdiArea->setActiveSubWindow(m_toBeActiveSubWindow); 0419 } 0420 0421 0422 void LokalizeMainWindow::setupActions() 0423 { 0424 //all operations that can be done after initial setup 0425 //(via QTimer::singleShot) go to initLater() 0426 0427 // QElapsedTimer aaa; 0428 // aaa.start(); 0429 0430 setStandardToolBarMenuEnabled(true); 0431 0432 QAction *action; 0433 KActionCollection* ac = actionCollection(); 0434 KActionCategory* actionCategory; 0435 KActionCategory* file = new KActionCategory(i18nc("@title actions category", "File"), ac); 0436 //KActionCategory* config=new KActionCategory(i18nc("@title actions category","Settings"), ac); 0437 KActionCategory* glossary = new KActionCategory(i18nc("@title actions category", "Glossary"), ac); 0438 KActionCategory* tm = new KActionCategory(i18nc("@title actions category", "Translation Memory"), ac); 0439 KActionCategory* proj = new KActionCategory(i18nc("@title actions category", "Project"), ac); 0440 0441 actionCategory = file; 0442 0443 // File 0444 //KStandardAction::open(this, SLOT(fileOpen()), ac); 0445 file->addAction(KStandardAction::Open, this, SLOT(fileOpen())); 0446 m_openRecentFileAction = KStandardAction::openRecent(this, SLOT(fileOpen(QUrl)), ac); 0447 0448 file->addAction(KStandardAction::Quit, qApp, SLOT(closeAllWindows())); 0449 0450 0451 //Settings 0452 SettingsController* sc = SettingsController::instance(); 0453 KStandardAction::preferences(sc, &SettingsController::showSettingsDialog, ac); 0454 0455 #define ADD_ACTION_SHORTCUT(_name,_text,_shortcut)\ 0456 action = actionCategory->addAction(QStringLiteral(_name));\ 0457 ac->setDefaultShortcut(action, QKeySequence( _shortcut ));\ 0458 action->setText(_text); 0459 0460 0461 //Window 0462 //documentBack 0463 //KStandardAction::close(m_mdiArea, SLOT(closeActiveSubWindow()), ac); 0464 0465 actionCategory = file; 0466 ADD_ACTION_SHORTCUT("next-tab", i18n("Next tab"), Qt::CTRL + Qt::Key_Tab) 0467 connect(action, &QAction::triggered, m_mdiArea, &LokalizeMdiArea::activateNextSubWindow); 0468 0469 ADD_ACTION_SHORTCUT("prev-tab", i18n("Previous tab"), Qt::CTRL + Qt::SHIFT + Qt::Key_Tab) 0470 connect(action, &QAction::triggered, m_mdiArea, &LokalizeMdiArea::activatePreviousSubWindow); 0471 0472 ADD_ACTION_SHORTCUT("prev-active-tab", i18n("Previously active tab"), Qt::CTRL + Qt::Key_BracketLeft) 0473 connect(action, &QAction::triggered, m_mdiArea, &QMdiArea::activatePreviousSubWindow); 0474 0475 //Tools 0476 actionCategory = glossary; 0477 Project* project = Project::instance(); 0478 ADD_ACTION_SHORTCUT("tools_glossary", i18nc("@action:inmenu", "Glossary"), Qt::CTRL + Qt::ALT + Qt::Key_G) 0479 connect(action, &QAction::triggered, project, &Project::showGlossary); 0480 0481 actionCategory = tm; 0482 ADD_ACTION_SHORTCUT("tools_tm", i18nc("@action:inmenu", "Translation memory"), Qt::Key_F7) 0483 connect(action, &QAction::triggered, this, &LokalizeMainWindow::showTM); 0484 0485 action = tm->addAction("tools_tm_manage", project, SLOT(showTMManager())); 0486 action->setText(i18nc("@action:inmenu", "Manage translation memories")); 0487 0488 //Project 0489 actionCategory = proj; 0490 ADD_ACTION_SHORTCUT("project_overview", i18nc("@action:inmenu", "Project overview"), Qt::Key_F4) 0491 connect(action, &QAction::triggered, this, &LokalizeMainWindow::showProjectOverview); 0492 0493 action = proj->addAction(QStringLiteral("project_configure"), sc, SLOT(projectConfigure())); 0494 action->setText(i18nc("@action:inmenu", "Configure project...")); 0495 0496 action = proj->addAction(QStringLiteral("project_create"), sc, SLOT(projectCreate())); 0497 action->setText(i18nc("@action:inmenu", "Create software translation project...")); 0498 0499 action = proj->addAction(QStringLiteral("project_create_odf"), Project::instance(), SLOT(projectOdfCreate())); 0500 action->setText(i18nc("@action:inmenu", "Create OpenDocument translation project...")); 0501 0502 action = proj->addAction(QStringLiteral("project_open"), this, SLOT(openProject())); 0503 action->setText(i18nc("@action:inmenu", "Open project...")); 0504 action->setIcon(QIcon::fromTheme("project-open")); 0505 0506 action = proj->addAction(QStringLiteral("project_close"), this, SLOT(closeProject())); 0507 action->setText(i18nc("@action:inmenu", "Close project")); 0508 action->setIcon(QIcon::fromTheme("project-close")); 0509 0510 m_openRecentProjectAction = new KRecentFilesAction(i18nc("@action:inmenu", "Open recent project"), this); 0511 action = proj->addAction(QStringLiteral("project_open_recent"), m_openRecentProjectAction); 0512 connect(m_openRecentProjectAction, QOverload<const QUrl &>::of(&KRecentFilesAction::urlSelected), this, QOverload<const QUrl &>::of(&LokalizeMainWindow::openProject)); 0513 0514 //Qt::QueuedConnection: defer until event loop is running to eliminate QWidgetPrivate::showChildren(bool) startup crash 0515 connect(Project::instance(), &Project::loaded, this, &LokalizeMainWindow::projectLoaded, Qt::QueuedConnection); 0516 0517 0518 ADD_ACTION_SHORTCUT("tools_filesearch", i18nc("@action:inmenu", "Search and replace in files"), Qt::Key_F6) 0519 connect(action, &QAction::triggered, this, &LokalizeMainWindow::showFileSearch); 0520 0521 ADD_ACTION_SHORTCUT("tools_filesearch_next", i18nc("@action:inmenu", "Find next in files"), Qt::META + Qt::Key_F3) 0522 connect(action, &QAction::triggered, this, &LokalizeMainWindow::fileSearchNext); 0523 0524 action = ac->addAction(QStringLiteral("tools_widgettextcapture"), this, SLOT(widgetTextCapture())); 0525 action->setText(i18nc("@action:inmenu", "Widget text capture")); 0526 0527 setupGUI(Default, QStringLiteral("lokalizemainwindowui.rc")); 0528 0529 //qCDebug(LOKALIZE_LOG)<<"action setup finished"<<aaa.elapsed(); 0530 } 0531 0532 bool LokalizeMainWindow::closeProject() 0533 { 0534 if (!queryClose()) 0535 return false; 0536 0537 KConfigGroup emptyGroup; //don't save which project to reopen 0538 saveProjectState(emptyGroup); 0539 //close files from previous project 0540 const auto subwindows = m_mdiArea->subWindowList(); 0541 for (QMdiSubWindow* subwindow : subwindows) { 0542 if (subwindow == m_translationMemorySubWindow && m_translationMemorySubWindow) 0543 subwindow->deleteLater(); 0544 else if (qobject_cast<EditorTab*>(subwindow->widget())) { 0545 m_fileToEditor.remove(static_cast<EditorTab*>(subwindow->widget())->currentFilePath());//safety 0546 m_mdiArea->removeSubWindow(subwindow); 0547 subwindow->deleteLater(); 0548 } else if (subwindow == m_projectSubWindow && m_projectSubWindow) 0549 static_cast<ProjectTab*>(m_projectSubWindow->widget())->showWelcomeScreen(); 0550 } 0551 Project::instance()->load(QString()); 0552 //TODO scripts 0553 return true; 0554 } 0555 0556 void LokalizeMainWindow::openProject(QString path) 0557 { 0558 path = SettingsController::instance()->projectOpen(path, false); //dry run 0559 0560 if (path.isEmpty()) 0561 return; 0562 0563 if (closeProject()) 0564 SettingsController::instance()->projectOpen(path, true);//really open 0565 } 0566 0567 void LokalizeMainWindow::saveProperties(KConfigGroup& stateGroup) 0568 { 0569 saveProjectState(stateGroup); 0570 } 0571 0572 void LokalizeMainWindow::saveProjectState(KConfigGroup& stateGroup) 0573 { 0574 QList<QMdiSubWindow*> editors = m_mdiArea->subWindowList(); 0575 0576 QStringList files; 0577 QStringList mergeFiles; 0578 QList<QByteArray> dockWidgets; 0579 //QList<int> offsets; 0580 QList<int> entries; 0581 QMdiSubWindow* activeSW = m_mdiArea->currentSubWindow(); 0582 int activeSWIndex = -1; 0583 int i = editors.size(); 0584 0585 while (--i >= 0) { 0586 //if (editors.at(i)==m_projectSubWindow) 0587 if (!editors.at(i) || !qobject_cast<EditorTab*>(editors.at(i)->widget())) 0588 continue; 0589 0590 EditorState state = static_cast<EditorTab*>(editors.at(i)->widget())->state(); 0591 if (editors.at(i) == activeSW) { 0592 activeSWIndex = files.size(); 0593 m_lastEditorState = state.dockWidgets.toBase64(); 0594 } 0595 files.append(state.filePath); 0596 mergeFiles.append(state.mergeFilePath); 0597 dockWidgets.append(state.dockWidgets.toBase64()); 0598 entries.append(state.entry); 0599 //offsets.append(state.offset); 0600 //qCWarning(LOKALIZE_LOG)<<static_cast<EditorWindow*>(editors.at(i)->widget() )->state().url; 0601 } 0602 //if (activeSWIndex==-1 && activeSW==m_projectSubWindow) 0603 0604 if (files.size() == 0 && !m_lastEditorState.isEmpty()) { 0605 dockWidgets.append(m_lastEditorState); // save last state if no editor open 0606 } 0607 if (stateGroup.isValid()) 0608 stateGroup.writeEntry("Project", Project::instance()->path()); 0609 0610 0611 KConfig config; 0612 KConfigGroup projectStateGroup(&config, "State-" + Project::instance()->path()); 0613 projectStateGroup.writeEntry("Active", activeSWIndex); 0614 projectStateGroup.writeEntry("Files", files); 0615 projectStateGroup.writeEntry("MergeFiles", mergeFiles); 0616 projectStateGroup.writeEntry("DockWidgets", dockWidgets); 0617 //stateGroup.writeEntry("Offsets",offsets); 0618 projectStateGroup.writeEntry("Entries", entries); 0619 if (m_projectSubWindow) { 0620 ProjectTab *w = static_cast<ProjectTab*>(m_projectSubWindow->widget()); 0621 if (w->unitsCount() > 0) 0622 projectStateGroup.writeEntry("UnitsCount", w->unitsCount()); 0623 } 0624 0625 0626 QString nameSpecifier = Project::instance()->path(); 0627 if (!nameSpecifier.isEmpty()) nameSpecifier.prepend('-'); 0628 KConfig* c = stateGroup.isValid() ? stateGroup.config() : &config; 0629 m_openRecentFileAction->saveEntries(KConfigGroup(c, "RecentFiles" + nameSpecifier)); 0630 m_openRecentProjectAction->saveEntries(KConfigGroup(&config, "RecentProjects")); 0631 } 0632 0633 void LokalizeMainWindow::readProperties(const KConfigGroup& stateGroup) 0634 { 0635 KConfig config; 0636 m_openRecentProjectAction->loadEntries(KConfigGroup(&config, "RecentProjects")); 0637 QString path = stateGroup.readEntry("Project", QString()); 0638 if (Project::instance()->isLoaded() || path.isEmpty()) { 0639 //1. we weren't existing yet when the signal was emitted 0640 //2. defer until event loop is running to eliminate QWidgetPrivate::showChildren(bool) startup crash 0641 QTimer::singleShot(0, this, &LokalizeMainWindow::projectLoaded); 0642 } else 0643 Project::instance()->load(path); 0644 } 0645 0646 void LokalizeMainWindow::projectLoaded() 0647 { 0648 QString projectPath = Project::instance()->path(); 0649 qCDebug(LOKALIZE_LOG) << "Loaded project : " << projectPath; 0650 if (!projectPath.isEmpty()) 0651 m_openRecentProjectAction->addUrl(QUrl::fromLocalFile(projectPath)); 0652 0653 KConfig config; 0654 0655 QString nameSpecifier = projectPath; 0656 if (!nameSpecifier.isEmpty()) nameSpecifier.prepend('-'); 0657 m_openRecentFileAction->loadEntries(KConfigGroup(&config, "RecentFiles" + nameSpecifier)); 0658 0659 0660 //if project isn't loaded, still restore opened files from "State-" 0661 KConfigGroup stateGroup(&config, "State"); 0662 KConfigGroup projectStateGroup(&config, "State-" + projectPath); 0663 0664 QStringList files; 0665 QStringList mergeFiles; 0666 QList<QByteArray> dockWidgets; 0667 //QList<int> offsets; 0668 QList<int> entries; 0669 0670 projectOverview(); 0671 if (m_projectSubWindow) { 0672 ProjectTab *w = static_cast<ProjectTab*>(m_projectSubWindow->widget()); 0673 w->setLegacyUnitsCount(projectStateGroup.readEntry("UnitsCount", 0)); 0674 0675 QTabBar* tw = m_mdiArea->findChild<QTabBar*>(); 0676 if (tw) for (int i = 0; i < tw->count(); i++) 0677 if (tw->tabText(i) == w->windowTitle()) 0678 tw->setTabToolTip(i, Project::instance()->path()); 0679 } 0680 entries = projectStateGroup.readEntry("Entries", entries); 0681 0682 if (Settings::self()->restoreRecentFilesOnStartup()) 0683 files = projectStateGroup.readEntry("Files", files); 0684 mergeFiles = projectStateGroup.readEntry("MergeFiles", mergeFiles); 0685 dockWidgets = projectStateGroup.readEntry("DockWidgets", dockWidgets); 0686 int i = files.size(); 0687 int activeSWIndex = projectStateGroup.readEntry("Active", -1); 0688 QStringList failedFiles; 0689 while (--i >= 0) { 0690 if (i < dockWidgets.size()) { 0691 m_lastEditorState = dockWidgets.at(i); 0692 } 0693 if (!fileOpen(files.at(i), entries.at(i)/*, offsets.at(i)*//*,&activeSW11*/, activeSWIndex == i, mergeFiles.at(i),/*silent*/true)) 0694 failedFiles.append(files.at(i)); 0695 } 0696 if (!failedFiles.isEmpty()) { 0697 qCDebug(LOKALIZE_LOG) << "failedFiles" << failedFiles; 0698 // KMessageBox::error(this, i18nc("@info","Error opening the following files:")+ 0699 // "<br><il><li><filename>"+failedFiles.join("</filename></li><li><filename>")+"</filename></li></il>" ); 0700 KNotification* notification = new KNotification("FilesOpenError"); 0701 notification->setWidget(this); 0702 notification->setText(i18nc("@info", "Error opening the following files:\n\n") + "<filename>" + failedFiles.join("</filename><br><filename>") + "</filename>"); 0703 notification->sendEvent(); 0704 } 0705 0706 if (files.isEmpty() && dockWidgets.size() > 0) { 0707 m_lastEditorState = dockWidgets.last(); // restore last state if no editor open 0708 } else { 0709 m_lastEditorState = stateGroup.readEntry("DefaultDockWidgets", m_lastEditorState); // restore default state if no last editor for this project 0710 } 0711 0712 if (activeSWIndex == -1) { 0713 m_toBeActiveSubWindow = m_projectSubWindow; 0714 QTimer::singleShot(0, this, &LokalizeMainWindow::applyToBeActiveSubWindow); 0715 } 0716 0717 projectSettingsChanged(); 0718 } 0719 0720 void LokalizeMainWindow::projectSettingsChanged() 0721 { 0722 //TODO show langs 0723 setCaption(Project::instance()->projectID()); 0724 } 0725 0726 void LokalizeMainWindow::widgetTextCapture() 0727 { 0728 WidgetTextCaptureConfig* w = new WidgetTextCaptureConfig(this); 0729 w->show(); 0730 } 0731 0732 0733 //BEGIN DBus interface 0734 0735 //#include "plugin.h" 0736 #include "mainwindowadaptor.h" 0737 0738 /* 0739 void LokalizeMainWindow::checkForProjectAlreadyOpened() 0740 { 0741 0742 QStringList services=QDBusConnection::sessionBus().interface()->registeredServiceNames().value(); 0743 int i=services.size(); 0744 while(--i>=0) 0745 { 0746 if (services.at(i).startsWith("org.kde.lokalize")) 0747 //QDBusReply<uint> QDBusConnectionInterface::servicePid ( const QString & serviceName ) const; 0748 QDBusConnection::callWithCallback(QDBusMessage::createMethodCall(services.at(i),"/ThisIsWhatYouWant","org.kde.Lokalize.MainWindow","currentProject"), 0749 this, SLOT(), const char * errorMethod); 0750 } 0751 0752 } 0753 */ 0754 0755 void LokalizeMainWindow::registerDBusAdaptor() 0756 { 0757 new MainWindowAdaptor(this); 0758 QDBusConnection::sessionBus().registerObject(QLatin1String("/ThisIsWhatYouWant"), this); 0759 0760 //qCWarning(LOKALIZE_LOG)<<QDBusConnection::sessionBus().interface()->registeredServiceNames().value(); 0761 0762 //QMenu* projectActions=static_cast<QMenu*>(factory()->container("project_actions",this)); 0763 0764 /* 0765 KActionCollection* actionCollection = mWindow->actionCollection(); 0766 actionCollection->action("file_save")->setEnabled(canSave); 0767 actionCollection->action("file_save_as")->setEnabled(canSave); 0768 */ 0769 } 0770 0771 int LokalizeMainWindow::lookupInTranslationMemory(DocPosition::Part part, const QString& text) 0772 { 0773 TM::TMTab* w = showTM(); 0774 if (!text.isEmpty()) 0775 w->lookup(part == DocPosition::Source ? text : QString(), part == DocPosition::Target ? text : QString()); 0776 return w->dbusId(); 0777 } 0778 0779 int LokalizeMainWindow::lookupInTranslationMemory(const QString& source, const QString& target) 0780 { 0781 TM::TMTab* w = showTM(); 0782 w->lookup(source, target); 0783 return w->dbusId(); 0784 } 0785 0786 0787 int LokalizeMainWindow::showTranslationMemory() 0788 { 0789 /*activateWindow(); 0790 raise(); 0791 show();*/ 0792 return lookupInTranslationMemory(DocPosition::UndefPart, QString()); 0793 } 0794 0795 int LokalizeMainWindow::openFileInEditorAt(const QString& path, const QString& source, const QString& ctxt) 0796 { 0797 EditorTab* w = fileOpen(path, source, ctxt, true); 0798 if (!w) return -1; 0799 return w->dbusId(); 0800 } 0801 0802 int LokalizeMainWindow::openFileInEditor(const QString& path) 0803 { 0804 return openFileInEditorAt(path, QString(), QString()); 0805 } 0806 0807 QObject* LokalizeMainWindow::activeEditor() 0808 { 0809 //QList<QMdiSubWindow*> editors=m_mdiArea->subWindowList(); 0810 QMdiSubWindow* activeSW = m_mdiArea->currentSubWindow(); 0811 if (!activeSW || !qobject_cast<EditorTab*>(activeSW->widget())) 0812 return nullptr; 0813 return activeSW->widget(); 0814 } 0815 0816 QObject* LokalizeMainWindow::editorForFile(const QString& path) 0817 { 0818 FileToEditor::const_iterator it = m_fileToEditor.constFind(QFileInfo(path).canonicalFilePath()); 0819 if (it == m_fileToEditor.constEnd()) return nullptr; 0820 QMdiSubWindow* w = it.value(); 0821 if (!w) return nullptr; 0822 return static_cast<EditorTab*>(w->widget()); 0823 } 0824 0825 int LokalizeMainWindow::editorIndexForFile(const QString& path) 0826 { 0827 EditorTab* editor = static_cast<EditorTab*>(editorForFile(path)); 0828 if (!editor) return -1; 0829 return editor->dbusId(); 0830 } 0831 0832 0833 QString LokalizeMainWindow::currentProject() 0834 { 0835 return Project::instance()->path(); 0836 } 0837 0838 #ifdef Q_OS_WIN 0839 #include <windows.h> 0840 int LokalizeMainWindow::pid() 0841 { 0842 return GetCurrentProcessId(); 0843 } 0844 #else 0845 #include <unistd.h> 0846 int LokalizeMainWindow::pid() 0847 { 0848 return getpid(); 0849 } 0850 #endif 0851 0852 QString LokalizeMainWindow::dbusName() 0853 { 0854 return QStringLiteral("org.kde.lokalize-%1").arg(pid()); 0855 } 0856 void LokalizeMainWindow::busyCursor(bool busy) 0857 { 0858 busy ? QApplication::setOverrideCursor(Qt::WaitCursor) : QApplication::restoreOverrideCursor(); 0859 } 0860 0861 0862 void LokalizeMdiArea::activateNextSubWindow() 0863 { 0864 this->setActivationOrder((QMdiArea::WindowOrder)Settings::tabSwitch()); 0865 this->QMdiArea::activateNextSubWindow(); 0866 this->setActivationOrder(QMdiArea::ActivationHistoryOrder); 0867 } 0868 0869 void LokalizeMdiArea::activatePreviousSubWindow() 0870 { 0871 this->setActivationOrder((QMdiArea::WindowOrder)Settings::tabSwitch()); 0872 this->QMdiArea::activatePreviousSubWindow(); 0873 this->setActivationOrder(QMdiArea::ActivationHistoryOrder); 0874 } 0875 0876 MultiEditorAdaptor::MultiEditorAdaptor(EditorTab *parent) 0877 : EditorAdaptor(parent) 0878 { 0879 setObjectName(QStringLiteral("MultiEditorAdaptor")); 0880 connect(parent, QOverload<QObject*>::of(&EditorTab::destroyed), this, QOverload<QObject*>::of(&MultiEditorAdaptor::handleParentDestroy)); 0881 } 0882 0883 void MultiEditorAdaptor::setEditorTab(EditorTab* e) 0884 { 0885 if (parent()) 0886 disconnect(parent(), QOverload<QObject*>::of(&EditorTab::destroyed), this, QOverload<QObject*>::of(&MultiEditorAdaptor::handleParentDestroy)); 0887 if (e) 0888 connect(e, QOverload<QObject*>::of(&EditorTab::destroyed), this, QOverload<QObject*>::of(&MultiEditorAdaptor::handleParentDestroy)); 0889 setParent(e); 0890 setAutoRelaySignals(false); 0891 setAutoRelaySignals(true); 0892 } 0893 0894 void MultiEditorAdaptor::handleParentDestroy(QObject* p) 0895 { 0896 Q_UNUSED(p); 0897 setParent(nullptr); 0898 } 0899 0900 //END DBus interface 0901 0902 0903 0904 DelayedFileOpener::DelayedFileOpener(const QVector<QString>& urls, LokalizeMainWindow* lmw) 0905 : QObject() 0906 , m_urls(urls) 0907 , m_lmw(lmw) 0908 { 0909 //do the work just after project loading is finished 0910 //(i.e. all the files from previous project session are loaded) 0911 QTimer::singleShot(1, this, &DelayedFileOpener::doOpen); 0912 } 0913 0914 void DelayedFileOpener::doOpen() 0915 { 0916 int lastIndex = m_urls.count() - 1; 0917 for (int i = 0; i <= lastIndex; i++) 0918 m_lmw->fileOpen(m_urls.at(i), 0, /*set as active*/i == lastIndex); 0919 deleteLater(); 0920 } 0921 0922 0923 #include "moc_lokalizesubwindowbase.cpp" 0924 #include "moc_multieditoradaptor.cpp" 0925