1 /***************************************************************************
2 * SPDX-FileCopyrightText: 2021 S. MANKOWSKI stephane@mankowski.fr
3 * SPDX-FileCopyrightText: 2021 G. DE BURE support@mankowski.fr
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 ***************************************************************************/
6 /** @file
7 * This file defines classes skgmainpanel.
8 *
9 * @author Stephane MANKOWSKI / Guillaume DE BURE
10 */
11 #include "skgmainpanel.h"
12
13 #include <kaboutdata.h>
14 #include <kactioncollection.h>
15 #include <kactionmenu.h>
16 #include <kcombobox.h>
17 #include <kconfigdialog.h>
18 #include <kencodingfiledialog.h>
19 #include <kformat.h>
20 #include <kmessagebox.h>
21 #include <kmessagewidget.h>
22 #include <knotification.h>
23 #include <knotifyconfigwidget.h>
24 #include <kselectaction.h>
25 #include <kservice.h>
26 #include <kservicetypetrader.h>
27 #include <kstandardaction.h>
28 #include <kstatusnotifieritem.h>
29 #include <kstringhandler.h>
30 #include <ktoggleaction.h>
31 #include <ktoolbar.h>
32 #include <ktoolbarpopupaction.h>
33 #include <kxmlguifactory.h>
34
35 #ifdef KActivities_FOUND
36 #include <kactivities/resourceinstance.h>
37 #endif
38
39 #ifdef SKG_DBUS
40 #include <QDBusConnection>
41 #include <QDBusMessage>
42 #endif
43
44 #include <qaction.h>
45 #include <qapplication.h>
46 #include <qcollator.h>
47 #include <qcompleter.h>
48 #include <qdesktopservices.h>
49 #include <qdir.h>
50 #include <qdom.h>
51 #include <qevent.h>
52 #include <qfiledialog.h>
53 #include <qheaderview.h>
54 #include <qlineedit.h>
55 #include <qmenu.h>
56 #include <qprocess.h>
57 #include <qprogressbar.h>
58 #include <qpushbutton.h>
59 #include <qscrollarea.h>
60 #include <qsplashscreen.h>
61 #include <qtabbar.h>
62 #include <qtabwidget.h>
63 #include <qtextcodec.h>
64 #include <qurlquery.h>
65 #include <QRandomGenerator>
66
67 #include <algorithm> // std::sort
68
69 #include "skgdefine.h"
70 #include "skginterfaceplugin.h"
71 #include "skgservices.h"
72 #include "skgtraces.h"
73 #include "skgtransactionmng.h"
74 #include "skgtreeview.h"
75 #include "skgwebview.h"
76 #include "skgzoomselector.h"
77
78 struct doublePointer {
79 void* p1;
80 void* p2;
81 };
82
83 struct historyPage {
84 SKGTabPage::SKGPageHistoryItem current;
85 SKGTabPage::SKGPageHistoryItemList next;
86 SKGTabPage::SKGPageHistoryItemList previous;
87 };
88
89 struct actionDetails {
90 QPointer<QAction> action;
91 QStringList tables;
92 int min{};
93 int max{};
94 int ranking{};
95 bool focus{};
96 };
97 class SKGMainPanelPrivate
98 {
99 public:
100 Ui::skgmainpanel_base ui{};
101 Ui::skgmainpanel_pref uipref{};
102
103 SKGTabWidget* m_tabWidget;
104 QSplashScreen* m_splashScreen;
105
106 SKGDocument* m_currentDocument;
107
108 QList<SKGInterfacePlugin*> m_pluginsList;
109 QMap<QString, actionDetails > m_registeredGlogalAction;
110 QList<historyPage> m_historyClosedPages;
111
112 QMenu* m_contextMenu;
113 QAction* m_actHideContextItem;
114 QAction* m_actShowAllContextItems;
115 QAction* m_actDelete;
116 QAction* m_closePageAction;
117 QAction* m_closeAllOtherPagesAction;
118 QAction* m_switchPinState;
119 QAction* m_saveDefaultStateAction;
120 QAction* m_resetDefaultStateAction;
121 QAction* m_overwriteBookmarkStateAction;
122 QAction* m_configureAction;
123 QAction* m_enableEditorAction;
124 QAction* m_fullScreenAction;
125 QAction* m_actLock;
126 QAction* m_actUnLock;
127 QAction* m_reopenLastClosed;
128 KStatusNotifierItem* m_kSystemTrayIcon;
129 QLabel* m_kNormalMessage;
130 SKGZoomSelector* m_zoomSelector;
131
132 KToolBarPopupAction* m_previousAction;
133 KToolBarPopupAction* m_nextAction;
134 KToolBarPopupAction* m_buttonMenuAction;
135 KToggleAction* m_showMenuBarAction;
136
137 QMenu* m_previousMenu;
138 QMenu* m_nextMenu;
139 QMenu* m_buttonMenu;
140 QWidget* m_mainWidget;
141 QVBoxLayout* m_mainLayout{};
142
143 doublePointer m_progressObjects{};
144 bool m_middleClick;
145 bool m_saveOnClose;
146 QString m_fileName;
147 SKGWidget* m_widgetHavingSelection;
148 QStringList m_tipsOfTheDay;
149
150 #ifdef KActivities_FOUND
151 KActivities::ResourceInstance* m_activityResourceInstance;
152 #endif
153
154 static bool m_currentActionCanceled;
155 static SKGMainPanel* m_mainPanel;
156
SKGMainPanelPrivate()157 SKGMainPanelPrivate()
158 {
159 m_actHideContextItem = nullptr; m_actShowAllContextItems = nullptr; m_actDelete = nullptr;
160 m_closePageAction = nullptr; m_closeAllOtherPagesAction = nullptr; m_switchPinState = nullptr; m_saveDefaultStateAction = nullptr;
161 m_resetDefaultStateAction = nullptr; m_overwriteBookmarkStateAction = nullptr; m_configureAction = nullptr; m_enableEditorAction = nullptr; m_fullScreenAction = nullptr; m_actLock = nullptr;
162 m_actUnLock = nullptr;
163 m_kSystemTrayIcon = nullptr;
164 m_kNormalMessage = nullptr; m_zoomSelector = nullptr; m_previousAction = nullptr; m_nextAction = nullptr; m_buttonMenuAction = nullptr;
165 m_mainWidget = nullptr; m_mainLayout = nullptr; m_middleClick = false; m_saveOnClose = false;
166 m_widgetHavingSelection = nullptr;
167 m_tabWidget = nullptr; m_splashScreen = nullptr; m_currentDocument = nullptr;
168 m_contextMenu = nullptr;
169 m_reopenLastClosed = nullptr;
170 m_showMenuBarAction = nullptr;
171 m_previousMenu = nullptr;
172 m_nextMenu = nullptr;
173 m_buttonMenu = nullptr;
174 m_progressObjects.p1 = nullptr;
175 m_progressObjects.p2 = nullptr;
176 #ifdef KActivities_FOUND
177 m_activityResourceInstance = nullptr;
178 #endif
179 }
180
progressBarCallBack(int iPos,qint64 iTime,const QString & iName,void * iProgressBar)181 static int progressBarCallBack(int iPos, qint64 iTime, const QString& iName, void* iProgressBar)
182 {
183 Q_UNUSED(iTime)
184 QProgressBar* progressBar = nullptr;
185 QPushButton* button = nullptr;
186 auto* pointers = static_cast<doublePointer*>(iProgressBar);
187 if (pointers != nullptr) {
188 progressBar = static_cast<QProgressBar*>(pointers->p1);
189 button = static_cast<QPushButton*>(pointers->p2);
190 }
191
192 bool visible = (iPos > 0 && iPos <= 100);
193 if (progressBar != nullptr) {
194 QString commonFormat = QStringLiteral("%p%");
195 /*if (iPos > 0) {
196 * qint64 estimatedTime = 100 * iTime / iPos;
197 * qint64 remainingTime = estimatedTime - iTime;
198 * commonFormat = commonFormat % " - " % i18nc("To print a remaining time (in seconde) / estimated time (in second)", "%1s / %2s",
199 * SKGServices::intToString(remainingTime / 1000),
200 * SKGServices::intToString(estimatedTime / 1000));
201 }*/
202 progressBar->setFormat(iName.isEmpty() ? commonFormat : commonFormat % '\n' % iName);
203 progressBar->setValue(iPos);
204 progressBar->setVisible(visible);
205 if (iPos == 100) {
206 QTimer::singleShot(300, Qt::CoarseTimer, progressBar, &QProgressBar::hide);
207 }
208 progressBar->setToolTip(iName);
209 #ifdef SKG_DBUS
210 QDBusMessage message = QDBusMessage::createSignal(QLatin1String("/org/") + KAboutData::applicationData().componentName() + QLatin1String("/UnityLauncher"),
211 QStringLiteral("com.canonical.Unity.LauncherEntry"),
212 QStringLiteral("Update"));
213 message << "application://org.kde.skrooge.desktop";
214
215 QVariantMap setProperty;
216 if (iPos == 100) {
217 setProperty.insert(QStringLiteral("progress"), 0.0);
218 setProperty.insert(QStringLiteral("progress-visible"), false);
219 } else {
220 setProperty.insert(QStringLiteral("progress"), static_cast<double>(iPos / 100.0));
221 setProperty.insert(QStringLiteral("progress-visible"), true);
222 }
223 message << setProperty;
224 QDBusConnection::sessionBus().send(message);
225 #endif
226 }
227 if (button != nullptr) {
228 button->setVisible(visible);
229 if (iPos == 100) {
230 QTimer::singleShot(300, Qt::CoarseTimer, button, &QPushButton::hide);
231 }
232 }
233
234
235 SKGMainPanelPrivate::m_currentActionCanceled = false;
236 if (iPos != 0 && iPos != 100) {
237 qApp->processEvents(QEventLoop::AllEvents, 500);
238 }
239 return (SKGMainPanelPrivate::m_currentActionCanceled ? 1 : 0);
240 }
241
adviceLessThan(const SKGAdvice & s1,const SKGAdvice & s2)242 static bool adviceLessThan(const SKGAdvice& s1, const SKGAdvice& s2)
243 {
244 if (s1.getPriority() == s2.getPriority()) {
245 return (s1.getShortMessage() > s2.getShortMessage());
246 }
247 return (s1.getPriority() > s2.getPriority());
248 }
249
setAttribute(QDomElement & iRoot,const QString & iPath,const QString & iValue)250 static void setAttribute(QDomElement& iRoot, const QString& iPath, const QString& iValue)
251 {
252 int pos = iPath.indexOf('.');
253 if (pos == -1) {
254 iRoot.setAttribute(iPath, iValue);
255 } else {
256 QString newElementName = iPath.left(pos);
257 QString newAttribue = iPath.right(iPath.count() - pos - 1);
258
259 QDomDocument doc(QStringLiteral("SKGML"));
260 doc.setContent(iRoot.attribute(newElementName));
261 QDomElement root = doc.documentElement();
262 if (root.isNull()) {
263 root = doc.createElement(QStringLiteral("parameters"));
264 doc.appendChild(root);
265 }
266 setAttribute(root, newAttribue, iValue);
267
268 iRoot.setAttribute(newElementName, doc.toString());
269 }
270 }
271
refreshTabPosition()272 void refreshTabPosition()
273 {
274 m_tabWidget->setTabPosition(static_cast<QTabWidget::TabPosition>(skgbasegui_settings::main_tabs_position()));
275 }
276
rebuildSystemTray()277 void rebuildSystemTray()
278 {
279 if (skgbasegui_settings::icon_in_system_tray()) {
280 if (m_kSystemTrayIcon == nullptr) {
281 m_kSystemTrayIcon = new KStatusNotifierItem(m_mainPanel);
282 m_kSystemTrayIcon->setStandardActionsEnabled(true);
283 m_kSystemTrayIcon->setAssociatedWidget(m_mainPanel);
284 m_kSystemTrayIcon->setIconByPixmap(QApplication::windowIcon());
285 }
286 } else {
287 if (m_kSystemTrayIcon != nullptr) {
288 delete m_kSystemTrayIcon;
289 m_kSystemTrayIcon = nullptr;
290 }
291 }
292 }
293 };
294
295
296 bool SKGMainPanelPrivate::m_currentActionCanceled = false;
297 SKGMainPanel* SKGMainPanelPrivate::m_mainPanel = nullptr;
298
SKGMainPanel(QSplashScreen * iSplashScreen,SKGDocument * iDocument)299 SKGMainPanel::SKGMainPanel(QSplashScreen* iSplashScreen, SKGDocument* iDocument)
300 : d(new SKGMainPanelPrivate)
301 {
302 SKGTRACEINFUNC(1)
303 d->m_tabWidget = new SKGTabWidget(this);
304 d->m_splashScreen = iSplashScreen;
305 d->m_currentDocument = iDocument;
306
307 setComponentName(QStringLiteral("skg"), KAboutData::applicationData().displayName());
308 setObjectName(qApp->applicationDisplayName());
309
310 // Set main panel
311 SKGMainPanelPrivate::m_mainPanel = this;
312 auto w = new QScrollArea(this);
313 w->setFrameShape(QFrame::NoFrame);
314 w->setFocusPolicy(Qt::NoFocus);
315 d->m_mainLayout = new QVBoxLayout(w);
316 d->m_mainLayout->setSpacing(0);
317 d->m_mainLayout->setContentsMargins(0, 0, 0, 0);
318 d->m_mainLayout->addWidget(d->m_tabWidget);
319 d->ui.setupUi(this);
320
321 // setMainWidget(new QLabel("hello"));
322
323 // Initialize settings
324 KSharedConfigPtr config = KSharedConfig::openConfig();
325 KConfigGroup prefskg = config->group("Main Panel");
326 int option = prefskg.readEntry("update_modified_contexts", 100);
327 if (option == 100) {
328 // First call, we set default values
329 prefskg.writeEntry("update_modified_contexts", 2, KConfigBase::Normal);
330 // NEVER: set following setting
331 KMessageBox::saveDontShowAgainYesNo(QStringLiteral("updateContextOnClose"), KMessageBox::No);
332 SKGTRACEL(1) << "update_modified_contexts set to NEVER" << SKGENDL;
333 SKGTRACEL(1) << "updateContextOnClose set to No" << SKGENDL;
334 }
335
336 option = prefskg.readEntry("update_modified_bookmarks", 100);
337 if (option == 100) {
338 // First call, we set default values
339 prefskg.writeEntry("update_modified_bookmarks", 2, KConfigBase::Normal);
340 // NEVER: set following setting
341 KMessageBox::saveDontShowAgainYesNo(QStringLiteral("updateBookmarkOnClose"), KMessageBox::No);
342 SKGTRACEL(1) << "update_modified_bookmarks set to NEVER" << SKGENDL;
343 SKGTRACEL(1) << "updateBookmarkOnClose set to No" << SKGENDL;
344 }
345
346 // Search plugins
347 KService::List offers = KServiceTypeTrader::self()->query(QStringLiteral("SKG GUI/Plugin"));
348
349 // Load plugins
350 int nb = offers.count();
351 SKGTRACEL(1) << nb << " plugins found" << SKGENDL;
352 if (d->m_splashScreen != nullptr) {
353 d->m_splashScreen->showMessage(i18nc("Splash screen message", "Loading plugins..."), Qt::AlignLeft, QColor(221, 130, 8)); // krazy:exclude=qmethods
354 }
355 SKGError err;
356 QStringList listAuthors;
357 QStringList listTasks;
358 QStringList listEmails;
359 QStringList listOscs;
360 for (int i = 0; i < nb; ++i) {
361 KService::Ptr service = offers.at(i);
362 QString name = service->name();
363 QString version = service->property(QStringLiteral("X-KDE-PluginInfo-Version"), QVariant::String).toString();
364 QString id = service->property(QStringLiteral("X-Krunner-ID"), QVariant::String).toString();
365 QString msg = i18nc("Splash screen message", "Loading plugin %1/%2: %3...", i + 1, nb, name);
366 SKGTRACEL(1) << msg << SKGENDL;
367 if (d->m_splashScreen != nullptr) {
368 d->m_splashScreen->showMessage(msg, Qt::AlignLeft, QColor(221, 130, 8)); // krazy:exclude=qmethods
369 }
370 KPluginLoader loader(service->library());
371 if (version.isEmpty() || SKGServices::stringToDouble(version) < 1) {
372 SKGTRACE << "WARNING: plugin [" << name << "] not loaded because of version too old (<1)" << SKGENDL;
373 } else {
374 KPluginFactory* factory2 = loader.factory();
375 if (factory2 != nullptr) {
376 auto* pluginInterface = factory2->create<SKGInterfacePlugin> (this);
377 if (pluginInterface != nullptr) {
378 if (pluginInterface->isEnabled() && pluginInterface->setupActions(getDocument())) {
379 // Add plugin in about
380 QStringList listOfAuthors;
381 QStringList listOfEmails;
382 QStringList listOfPlugins;
383 QString author = service->property(QStringLiteral("X-KDE-PluginInfo-Author"), QVariant::String).toString();
384 QString email = service->property(QStringLiteral("X-KDE-PluginInfo-Email"), QVariant::String).toString();
385 if (!author.isEmpty()) {
386 listOfAuthors.push_back(author);
387 listOfEmails.push_back(email);
388 listOfPlugins.push_back(name);
389 }
390 const auto subPlugins = pluginInterface->subPlugins();
391 for (const QString& subPlugin : subPlugins) {
392 KService::List subOffers = KServiceTypeTrader::self()->query(subPlugin);
393 int nbSubOffers = subOffers.count();
394 for (int j = 0; j < nbSubOffers; ++j) {
395 KService::Ptr subService = subOffers.at(j);
396 QString author2 = subService->property(QStringLiteral("X-KDE-PluginInfo-Author"), QVariant::String).toString();
397 QString email2 = subService->property(QStringLiteral("X-KDE-PluginInfo-Email"), QVariant::String).toString();
398 if (!author2.isEmpty()) {
399 listOfAuthors.push_back(author2);
400 listOfEmails.push_back(email2);
401 listOfPlugins.push_back(subService->name());
402 }
403 }
404 }
405
406 int nbAuthors = listOfAuthors.count();
407 for (int j = 0; j < nbAuthors; ++j) {
408 QString authorId;
409 QString author = listOfAuthors.at(j);
410 QStringList authors = SKGServices::splitCSVLine(author, ',');
411 if (authors.count() == 2) {
412 author = authors.at(0);
413 authorId = authors.at(1);
414 }
415 int pos2 = listAuthors.indexOf(author);
416 if (pos2 == -1) {
417 listAuthors.push_back(author);
418 listTasks.push_back(i18n("Developer of plugin '%1'", listOfPlugins.at(j)));
419 listEmails.push_back(listOfEmails.at(j));
420 listOscs.push_back(authorId);
421 } else {
422 listTasks[pos2] += i18n(", '%1'", listOfPlugins.at(j));
423 }
424 }
425
426 // Store plugin
427 int nbplugin = d->m_pluginsList.count();
428 int pos3 = nbplugin;
429 for (int j = nbplugin - 1; j >= 0; --j) {
430 if (pluginInterface->getOrder() < d->m_pluginsList.at(j)->getOrder()) {
431 pos3 = j;
432 }
433 }
434
435 d->m_pluginsList.insert(pos3, pluginInterface);
436 pluginInterface->setObjectName(id);
437
438 // Add tips
439 d->m_tipsOfTheDay += pluginInterface->tips();
440 }
441 }
442 } else {
443 QString msg2 = i18nc("An information message", "Loading plugin %1 failed because the factory could not be found in %2: %3", id, service->library(), loader.errorString());
444 getDocument()->sendMessage(msg2);
445 SKGTRACEL(1) << "WARNING:" << msg2 << SKGENDL;
446 }
447 }
448 }
449
450 // Add credits
451 KAboutData about = KAboutData::applicationData();
452 nb = listAuthors.count();
453 for (int i = 0; i < nb; ++i) {
454 about.addCredit(listAuthors.at(i), listTasks.at(i), listEmails.at(i), QLatin1String(""), listOscs.at(i));
455 }
456 KAboutData::setApplicationData(about);
457
458 // accept dnd
459 setAcceptDrops(true);
460
461 // tell the KXmlGuiWindow that this is indeed the main widget
462 setCentralWidget(w);
463
464 d->refreshTabPosition();
465 d->m_tabWidget->setMovable(true);
466 d->m_tabWidget->setTabsClosable(true);
467 d->m_tabWidget->setUsesScrollButtons(true);
468 d->m_tabWidget->tabBar()->setSelectionBehaviorOnRemove(QTabBar::SelectPreviousTab);
469 d->m_tabWidget->setDocumentMode(true);
470 d->m_tabWidget->show();
471
472 // System tray
473 d->rebuildSystemTray();
474
475 // then, setup our actions
476 setupActions();
477
478 displayErrorMessage(err);
479
480 // Add a status bar
481 statusBar()->show();
482
483 QPalette palette2 = QApplication::palette();
484 palette2.setColor(QPalette::Base, Qt::transparent);
485 d->ui.kContextList->setPalette(palette2);
486
487 QAction* toggle = d->ui.kDockContext->toggleViewAction();
488 QAction* panelAction = actionCollection()->addAction(QStringLiteral("view_context"));
489 registerGlobalAction(QStringLiteral("view_context"), panelAction);
490 panelAction->setCheckable(true);
491 panelAction->setChecked(toggle->isChecked());
492 panelAction->setText(toggle->text());
493 actionCollection()->setDefaultShortcut(panelAction, Qt::SHIFT + Qt::Key_F9);
494 connect(panelAction, &QAction::triggered, toggle, &QAction::trigger);
495 connect(toggle, &QAction::toggled, panelAction, &QAction::setChecked);
496
497 QAction* toggle2 = d->ui.kDockMessages->toggleViewAction();
498 QAction* panelAction2 = actionCollection()->addAction(QStringLiteral("view_messages"));
499 registerGlobalAction(QStringLiteral("view_messages"), panelAction2);
500 panelAction2->setCheckable(true);
501 panelAction2->setChecked(toggle2->isChecked());
502 panelAction2->setText(toggle2->text());
503 actionCollection()->setDefaultShortcut(panelAction2, Qt::SHIFT + Qt::Key_F8);
504 connect(panelAction2, &QAction::triggered, toggle2, &QAction::trigger);
505 connect(toggle2, &QAction::toggled, panelAction2, &QAction::setChecked);
506
507 auto contextMenu = new KSelectAction(SKGServices::fromTheme(QStringLiteral("tab-new")), i18nc("Noun", "Pages"), this);
508 registerGlobalAction(QStringLiteral("view_contextmenu"), contextMenu);
509
510 // Add plugin in client in right order
511 QList<QListWidgetItem*> pageNotVisible;
512 KConfigGroup prefContextVisibility = config->group("Context Visibility");
513 int shortCutIndex = 0;
514 QString shortCutPrefix = QStringLiteral("Ctrl+");
515 int nbplugin = d->m_pluginsList.count();
516 QList<QAction*> contextActionList;
517 for (int j = 0; j < nbplugin; ++j) {
518 SKGInterfacePlugin* pluginInterface = d->m_pluginsList.at(j);
519 if (pluginInterface != nullptr) {
520 // Creation of the item
521 QString title = pluginInterface->title();
522 SKGTRACEL(1) << "Add plugin (" << pluginInterface->getOrder() << ") : " << title << SKGENDL;
523 if (!title.isEmpty()) {
524 // Add menu item with shortcuts
525 if (pluginInterface->isInPagesChooser()) {
526 bool visible = prefContextVisibility.readEntry(pluginInterface->objectName(), true);
527 QIcon icon = SKGServices::fromTheme(pluginInterface->icon());
528
529 auto contextItem = new QListWidgetItem(icon, title);
530 contextItem->setStatusTip(pluginInterface->statusTip());
531 contextItem->setToolTip(pluginInterface->toolTip());
532 contextItem->setData(12, j); // context item ==> plugin
533 int page2 = d->ui.kContextList->count();
534 pluginInterface->setProperty("contextItem", page2); // plugin ==> context item
535
536 d->ui.kContextList->addItem(contextItem);
537
538 QAction* newAction = contextMenu->addAction(icon, title);
539 if (newAction != nullptr) {
540 newAction->setCheckable(false);
541 newAction->setData(page2);
542 contextItem->setData(15, QVariant::fromValue(static_cast<void*>(newAction))); // context item ==> action
543 if (!shortCutPrefix.isEmpty()) {
544 ++shortCutIndex;
545 if (shortCutIndex == 10) {
546 shortCutIndex = 0;
547 if (shortCutPrefix == QStringLiteral("Ctrl+")) {
548 shortCutPrefix += QStringLiteral("Alt+");
549 } else {
550 shortCutPrefix = QLatin1String("");
551 }
552 }
553 if (!shortCutPrefix.isEmpty()) {
554 actionCollection()->setDefaultShortcut(newAction, QString(shortCutPrefix % SKGServices::intToString(shortCutIndex)));
555 }
556 }
557 connect(newAction, &QAction::triggered, this, &SKGMainPanel::onOpenContext);
558
559 contextActionList.append(newAction);
560
561 if (!visible) {
562 pageNotVisible.push_back(contextItem);
563 }
564
565 // Register action
566 QString id = "page_" % pluginInterface->objectName();
567 registerGlobalAction(id, newAction);
568 registerGlobalAction(id, newAction);
569 }
570 }
571
572 // Create dock if needed
573 QDockWidget* dockWidget = pluginInterface->getDockWidget();
574 if (dockWidget != nullptr) {
575 addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
576 tabifyDockWidget(d->ui.kDockContext, dockWidget);
577 tabifyDockWidget(dockWidget, d->ui.kDockContext);
578 }
579 }
580 }
581 }
582
583 // Lock docs if needed
584 KConfigGroup pref = getMainConfigGroup();
585 if (pref.readEntry("docks_locked", false)) {
586 onLockDocks();
587 }
588
589 if (!pref.readEntry("first_launch", false)) {
590 this->setWindowState(windowState() | Qt::WindowMaximized);
591 pref.writeEntry("first_launch", true);
592 }
593
594 // a call to KXmlGuiWindow::setupGUI() populates the GUI
595 // with actions, using KXMLGUI.
596 // It also applies the saved mainwindow settings, if any, and ask the
597 // mainwindow to automatically save settings if changed: window size,
598 // toolbar position, icon size, etc.
599 setupGUI(Default, QStringLiteral("skgmainpanel.rc"));
600 plugActionList(QStringLiteral("context_actionlist"), contextActionList);
601
602 for (int j = 0; j < nbplugin; ++j) {
603 SKGInterfacePlugin* pluginInterface = d->m_pluginsList.at(j);
604 if (pluginInterface != nullptr) {
605 QString title = pluginInterface->title();
606 SKGTRACEL(1) << "Add plugin client (" << pluginInterface->getOrder() << ") : " << title << SKGENDL;
607 guiFactory()->addClient(pluginInterface);
608 }
609 }
610
611 // Hide items in context
612 nb = pageNotVisible.count();
613 for (int i = 0; i < nb; ++i) {
614 setContextVisibility(pageNotVisible.at(i), false);
615 }
616
617 // Set status bar
618 d->m_kNormalMessage = new QLabel(this);
619 d->m_kNormalMessage->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred));
620
621 auto kProgressBar = new QProgressBar(this);
622 kProgressBar->setObjectName(QStringLiteral("kProgressBar"));
623 kProgressBar->setValue(0);
624 kProgressBar->setMinimumSize(100, 20);
625 QSizePolicy sizePolicyProgessBar(QSizePolicy::Fixed, QSizePolicy::Expanding);
626 kProgressBar->setSizePolicy(sizePolicyProgessBar);
627 kProgressBar->setToolTip(i18nc("Widget description", "Progress of the current action"));
628 QFont f = kProgressBar->font();
629 f.setPointSize(6.0);
630 kProgressBar->setFont(f);
631 kProgressBar->setVisible(false);
632 kProgressBar->setAlignment(Qt::AlignTop | Qt::AlignHCenter);
633 kProgressBar->setRange(0, 100);
634
635 d->m_zoomSelector = new SKGZoomSelector(this);
636 d->m_zoomSelector->setSizePolicy(sizePolicyProgessBar);
637 connect(d->m_zoomSelector, &SKGZoomSelector::changed, this, &SKGMainPanel::onZoomChanged);
638
639 statusBar()->addWidget(d->m_kNormalMessage, 1);
640 statusBar()->addPermanentWidget(kProgressBar);
641
642 // Set Cancel button
643 auto kCancelButton = new QPushButton();
644 kCancelButton->setObjectName(QStringLiteral("kCancelButton"));
645 kCancelButton->setIcon(SKGServices::fromTheme(QStringLiteral("media-playback-stop")));
646 kCancelButton->setToolTip(i18nc("Widget description", "Cancel the current action"));
647 kCancelButton->setStatusTip(i18nc("Widget description", "Cancel the current action"));
648 kCancelButton->setVisible(false);
649 connect(kCancelButton, &QPushButton::clicked, this, &SKGMainPanel::onCancelCurrentAction);
650
651 //
652 d->ui.kClearMessageBtn->setIcon(SKGServices::fromTheme(QStringLiteral("edit-clear")));
653 connect(d->ui.kClearMessageBtn, &QPushButton::clicked, this, &SKGMainPanel::onClearMessages);
654
655 // Add special button in toolbar
656 KToolBar* tb = toolBar();
657 if (tb != nullptr) {
658 auto label = new QLabel(this);
659 QSizePolicy sizePolicyLabel(QSizePolicy::Expanding, QSizePolicy::Preferred);
660 sizePolicyLabel.setHorizontalStretch(0);
661 sizePolicyLabel.setVerticalStretch(0);
662 sizePolicyLabel.setHeightForWidth(label->sizePolicy().hasHeightForWidth());
663 label->setSizePolicy(sizePolicyLabel);
664 tb->addWidget(label);
665 tb->addAction(d->m_buttonMenuAction);
666 }
667
668 statusBar()->addPermanentWidget(kCancelButton);
669 statusBar()->addPermanentWidget(d->m_zoomSelector);
670
671 // Set progress bar call back
672 if (getDocument() != nullptr) {
673 d->m_progressObjects.p1 = static_cast<void*>(kProgressBar);
674 d->m_progressObjects.p2 = static_cast<void*>(kCancelButton);
675 getDocument()->setProgressCallback(&SKGMainPanelPrivate::progressBarCallBack, static_cast<void*>(&d->m_progressObjects));
676 }
677
678 // Connection
679 if (getDocument() != nullptr) {
680 connect(getDocument(), &SKGDocument::transactionSuccessfullyEnded, this, &SKGMainPanel::refresh, Qt::QueuedConnection);
681 connect(getDocument(), &SKGDocument::transactionSuccessfullyEnded, this, &SKGMainPanel::notify, Qt::QueuedConnection);
682 }
683 connect(d->ui.kContextList, &QListWidget::itemPressed, this, &SKGMainPanel::onBeforeOpenContext);
684 connect(d->ui.kContextList, &QListWidget::itemPressed, this, &SKGMainPanel::onOpenContext);
685 connect(d->m_tabWidget->tabBar(), &QTabBar::tabCloseRequested, this, &SKGMainPanel::closePageByIndex);
686 connect(d->m_tabWidget->tabBar(), &QTabBar::tabBarClicked, this, [ = ](int index) {
687 if ((QApplication::mouseButtons() & Qt::MidButton) != 0u) {
688 closePageByIndex(index);
689 }
690 });
691 connect(d->m_tabWidget->tabBar(), &QTabBar::tabBarDoubleClicked, this, &SKGMainPanel::addTab);
692 connect(d->m_tabWidget->tabBar(), &QTabBar::currentChanged, this, &SKGMainPanel::currentPageChanged);
693 connect(this, &SKGMainPanel::currentPageChanged, this, &SKGMainPanel::refresh);
694 connect(this, &SKGMainPanel::currentPageChanged, this, &SKGMainPanel::selectionChanged);
695
696 // Refresh
697 refresh();
698
699 d->ui.kContextList->installEventFilter(this);
700
701 // Build contextual menu
702 d->ui.kContextList->setContextMenuPolicy(Qt::CustomContextMenu);
703
704 d->m_contextMenu = new QMenu(d->ui.kContextList);
705 d->m_actHideContextItem = d->m_contextMenu->addAction(SKGServices::fromTheme(QStringLiteral("layer-visible-off")), i18nc("Verb", "Hide"));
706 connect(d->m_actHideContextItem, &QAction::triggered, this, &SKGMainPanel::onHideContextItem);
707
708 d->m_actShowAllContextItems = d->m_contextMenu->addAction(SKGServices::fromTheme(QStringLiteral("layer-visible-on")), i18nc("Verb", "Show all"));
709 connect(d->m_actShowAllContextItems, &QAction::triggered, this, &SKGMainPanel::onShowAllContextItems);
710
711 d->m_contextMenu->addSeparator();
712 d->m_contextMenu->addAction(getGlobalAction(QStringLiteral("tab_savedefaultstate")));
713 d->m_contextMenu->addAction(getGlobalAction(QStringLiteral("tab_resetdefaultstate")));
714
715 connect(d->ui.kContextList, &QListWidget::customContextMenuRequested, this, &SKGMainPanel::showMenu);
716
717 #ifdef KActivities_FOUND
718 // Initialize kactivities resource instance
719 d->m_activityResourceInstance = new KActivities::ResourceInstance(window()->winId());
720 d->m_activityResourceInstance->setParent(this);
721 #endif
722
723 // Show menu bar and status bar
724 menuBar()->show();
725 statusBar()->show();
726
727 notify(); // Due to sendMessage not in a transaction
728 d->m_splashScreen = nullptr;
729 }
730
~SKGMainPanel()731 SKGMainPanel::~SKGMainPanel()
732 {
733 SKGTRACEINFUNC(1)
734 SKGMainPanelPrivate::m_mainPanel = nullptr;
735 disconnect(getDocument(), nullptr, this, nullptr);
736
737 // close plugins
738 int nb = d->m_pluginsList.count();
739 for (int i = 0; i < nb; ++i) {
740 getPluginByIndex(i)->close();
741 }
742
743 if (getDocument() != nullptr) {
744 getDocument()->close();
745 }
746 delete d;
747 }
748
showMenu(const QPoint iPos)749 void SKGMainPanel::showMenu(const QPoint iPos)
750 {
751 if (d->m_contextMenu != nullptr) {
752 d->m_contextMenu->popup(d->ui.kContextList->mapToGlobal(iPos));
753 }
754 }
755
setContextVisibility(QListWidgetItem * iItem,bool iVisibility)756 void SKGMainPanel::setContextVisibility(QListWidgetItem* iItem, bool iVisibility)
757 {
758 if (iItem != nullptr) {
759 // Hide item in context
760 iItem->setHidden(!iVisibility);
761
762 // Hide corresponding action
763 QAction* act = static_cast< QAction* >(iItem->data(15).value<void*>());
764 if (act != nullptr) {
765 act->setVisible(iVisibility);
766 }
767
768 // Save state in settings
769 SKGInterfacePlugin* plugin = getPluginByIndex(iItem->data(12).toInt());
770 if (plugin != nullptr) {
771 KSharedConfigPtr config = KSharedConfig::openConfig();
772 KConfigGroup pref = config->group("Context Visibility");
773 pref.writeEntry(plugin->objectName(), iVisibility);
774 }
775 }
776 }
777
setContextVisibility(int iPage,bool iVisibility)778 void SKGMainPanel::setContextVisibility(int iPage, bool iVisibility)
779 {
780 setContextVisibility(d->ui.kContextList->item(iPage), iVisibility);
781 }
782
onHideContextItem()783 void SKGMainPanel::onHideContextItem()
784 {
785 setContextVisibility(d->ui.kContextList->currentRow(), false);
786 }
787
onShowAllContextItems()788 void SKGMainPanel::onShowAllContextItems()
789 {
790 int nb = d->ui.kContextList->count();
791 for (int i = 0; i < nb; ++i) {
792 setContextVisibility(i, true);
793 }
794 }
795
getDocument() const796 SKGDocument* SKGMainPanel::getDocument() const
797 {
798 return d->m_currentDocument;
799 }
800
processArguments(const QStringList & iArgument)801 QStringList SKGMainPanel::processArguments(const QStringList& iArgument)
802 {
803 QStringList output = iArgument;
804 for (auto plugin : qAsConst(d->m_pluginsList)) {
805 if (plugin != nullptr) {
806 output = plugin->processArguments(output);
807 }
808 }
809 return output;
810 }
811
registerGlobalAction(const QString & iIdentifier,QAction * iAction,bool iAddInCollection,const QStringList & iListOfTable,int iMinSelection,int iMaxSelection,int iRanking,bool iSelectionMustHaveFocus)812 void SKGMainPanel::registerGlobalAction(const QString& iIdentifier, QAction* iAction, bool iAddInCollection,
813 const QStringList& iListOfTable, int iMinSelection, int iMaxSelection,
814 int iRanking, bool iSelectionMustHaveFocus)
815 {
816 if (iAction == nullptr) {
817 SKGTRACE << "WARNING: registerGlobalAction(" << iIdentifier << ",nullptr)" << SKGENDL;
818 } else {
819 QStringList keys = d->m_registeredGlogalAction.keys();
820 for (const auto& id : qAsConst(keys)) {
821 QPointer<QAction> act = d->m_registeredGlogalAction.value(id).action;
822 if ((act != nullptr) && iIdentifier != id && act != iAction && !act->shortcut().isEmpty() && act->shortcut() == iAction->shortcut()) {
823 SKGTRACE << "WARNING: The actions [" << iAction->text() << " (" << iIdentifier << ")] and [" << act->text() << " (" << id << ")] has same shortcut [" << iAction->shortcut().toString() << "]" << SKGENDL;
824 }
825 }
826 actionDetails actDetails;
827 actDetails.action = iAction;
828 actDetails.tables = iListOfTable;
829 actDetails.min = iMinSelection;
830 actDetails.max = iMaxSelection;
831 actDetails.focus = iSelectionMustHaveFocus;
832 actDetails.ranking = (iRanking == -1 ? 10 * (d->m_registeredGlogalAction.count() + 1) : iRanking);
833 d->m_registeredGlogalAction[iIdentifier] = actDetails;
834
835 // This connect has not been migrated on new connect mechanism to avoid crash when leaving the application
836 connect(iAction, SIGNAL(destroyed(QObject*)), this, SLOT(unRegisterGlobalAction(QObject*))); // clazy:exclude=old-style-connect
837 if (iAddInCollection) {
838 QKeySequence shortCut = iAction->shortcut();
839 if (!shortCut.isEmpty()) {
840 iAction->setShortcut(QKeySequence());
841 }
842 actionCollection()->addAction(iIdentifier, iAction);
843 if (!shortCut.isEmpty()) {
844 actionCollection()->setDefaultShortcut(iAction, shortCut);
845 }
846 }
847 }
848 }
849
unRegisterGlobalAction(QObject * iAction)850 void SKGMainPanel::unRegisterGlobalAction(QObject* iAction)
851 {
852 auto* act = qobject_cast< QAction* >(iAction);
853 if (act != nullptr) {
854 const auto keys = d->m_registeredGlogalAction.keys();
855 for (const auto& id : keys) {
856 if (d->m_registeredGlogalAction.value(id).action == QPointer<QAction>(act)) {
857 d->m_registeredGlogalAction.remove(id);
858 }
859 }
860 }
861 }
862
getGlobalAction(const QString & iIdentifier,bool iWarnIfNotExist)863 QPointer<QAction> SKGMainPanel::getGlobalAction(const QString& iIdentifier, bool iWarnIfNotExist)
864 {
865 QAction* act = d->m_registeredGlogalAction.value(iIdentifier).action;
866 if (act == nullptr && iWarnIfNotExist) {
867 SKGTRACE << "WARNING: getGlobalAction(" << iIdentifier << ")=nullptr" << SKGENDL;
868 }
869 return act;
870 }
871
getActionsForContextualMenu(const QString & iTable)872 QList< QPointer< QAction > > SKGMainPanel::getActionsForContextualMenu(const QString& iTable)
873 {
874 // Filter action
875 QVector<actionDetails> tmp;
876 for (const auto& actDetails : qAsConst(d->m_registeredGlogalAction)) {
877 if (actDetails.ranking > 0 && actDetails.min > 0) {
878 if (actDetails.tables.isEmpty() || actDetails.tables.contains(iTable)) {
879 tmp.push_back(actDetails);
880 } else if (actDetails.tables.count() == 1 && actDetails.tables.at(0).startsWith(QLatin1String("query:"))) {
881 // Dynamic mode
882 QStringList tmpListTable;
883 getDocument()->getDistinctValues(QStringLiteral("sqlite_master"), QStringLiteral("name"), actDetails.tables.at(0).right(actDetails.tables.at(0).count() - 6), tmpListTable);
884 if (tmpListTable.contains(iTable)) {
885 tmp.push_back(actDetails);
886 }
887 }
888 }
889 }
890
891 // Sort
892 std::sort(tmp.begin(), tmp.end(), [&](const actionDetails & a, const actionDetails & b) {
893 return a.ranking < b.ranking;
894 });
895
896 // Generate output
897 int previousGroup = -1;
898 QList< QPointer< QAction > > output;
899 output.reserve(tmp.count());
900 for (const auto& actDetails : qAsConst(tmp)) {
901 int currentGroup = (actDetails.ranking) / 100;
902 if (currentGroup != previousGroup) {
903 output.push_back(nullptr);
904 previousGroup = currentGroup;
905 }
906 output.push_back(actDetails.action);
907 }
908 return output;
909 }
910
getGlobalActions() const911 QMap<QString, QPointer<QAction> > SKGMainPanel::getGlobalActions() const
912 {
913 QMap<QString, QPointer<QAction> > map;
914 const auto keys = d->m_registeredGlogalAction.keys();
915 for (const auto& id : keys) {
916 map[id] = d->m_registeredGlogalAction[id].action;
917 }
918 return map;
919 }
920
getPluginByIndex(int iIndex)921 SKGInterfacePlugin* SKGMainPanel::getPluginByIndex(int iIndex)
922 {
923 SKGInterfacePlugin* output = nullptr;
924 if (iIndex >= 0 && iIndex < d->m_pluginsList.count()) {
925 output = d->m_pluginsList.value(iIndex);
926 }
927
928 return output;
929 }
930
getPluginByName(const QString & iName)931 SKGInterfacePlugin* SKGMainPanel::getPluginByName(const QString& iName)
932 {
933 SKGInterfacePlugin* output = nullptr;
934 int nbplugin = d->m_pluginsList.count();
935 QString name = iName.toLower();
936 for (int j = 0; (output == nullptr) && j < nbplugin; ++j) {
937 QString namep = d->m_pluginsList.at(j)->objectName().toLower();
938 if (namep == name || namep.replace(' ', '_') == name) {
939 output = d->m_pluginsList.at(j);
940 }
941 }
942
943 return output;
944 }
945
setupActions()946 void SKGMainPanel::setupActions()
947 {
948 SKGTRACEINFUNC(1)
949
950 // Std File
951 KStandardAction::quit(this, SLOT(onQuitAction()), actionCollection());
952 KStandardAction::configureNotifications(this, SLOT(onConfigureNotifications()), actionCollection());
953
954 // Preferences
955 KStandardAction::preferences(this, SLOT(optionsPreferences()), actionCollection());
956
957 // New Tab
958 auto actAddTab = new QAction(SKGServices::fromTheme(QStringLiteral("tab-new-background")), i18nc("Noun, user action", "New Tab"), this);
959 actionCollection()->setDefaultShortcut(actAddTab, Qt::CTRL + Qt::SHIFT + Qt::Key_W);
960 connect(actAddTab, &QAction::triggered, this, &SKGMainPanel::addTab);
961 registerGlobalAction(QStringLiteral("new_tab"), actAddTab, true, QStringList(), -1);
962
963 // Add new tab widget
964 auto addTabButton = new QToolButton(this);
965 addTabButton->setIcon(actAddTab->icon());
966 addTabButton->setAutoRaise(true);
967 addTabButton->raise();
968 addTabButton->setDefaultAction(actAddTab);
969 addTabButton->setToolButtonStyle(Qt::ToolButtonIconOnly);
970 addTabButton->setFocusPolicy(Qt::NoFocus);
971 d->m_tabWidget->setCornerWidget(addTabButton);
972
973 d->m_actLock = new QAction(SKGServices::fromTheme(QStringLiteral("document-encrypt")), i18nc("Verb", "Lock panels"), this);
974 connect(d->m_actLock, &QAction::triggered, this, &SKGMainPanel::onLockDocks);
975 registerGlobalAction(QStringLiteral("view_lock"), d->m_actLock);
976
977 d->m_actUnLock = new QAction(SKGServices::fromTheme(QStringLiteral("document-decrypt")), i18nc("Verb", "Unlock panels"), this);
978 connect(d->m_actUnLock, &QAction::triggered, this, &SKGMainPanel::onUnlockDocks);
979 registerGlobalAction(QStringLiteral("view_unlock"), d->m_actUnLock);
980
981 d->m_switchPinState = new QAction(SKGServices::fromTheme(QStringLiteral("document-encrypt")), i18nc("Noun, user action", "Pin this page"), this);
982 connect(d->m_switchPinState, &QAction::triggered, this, [ = ] {this->switchPinPage(nullptr);});
983 registerGlobalAction(QStringLiteral("tab_switchpin"), d->m_switchPinState);
984
985 //
986 d->m_closePageAction = actionCollection()->addAction(KStandardAction::Close, QStringLiteral("tab_close"), this, SLOT(closeCurrentPage()));
987 registerGlobalAction(QStringLiteral("tab_close"), d->m_closePageAction);
988
989 //
990 auto actCloseAllPages = new QAction(SKGServices::fromTheme(QStringLiteral("window-close")), i18nc("Noun, user action", "Close All"), this);
991 actionCollection()->setDefaultShortcut(actCloseAllPages, Qt::ALT + Qt::Key_W);
992 connect(actCloseAllPages, &QAction::triggered, this, &SKGMainPanel::closeAllPages);
993 registerGlobalAction(QStringLiteral("tab_closeall"), actCloseAllPages, true, QStringList(), -1);
994
995 //
996 d->m_closeAllOtherPagesAction = new QAction(SKGServices::fromTheme(QStringLiteral("window-close")), i18nc("Noun, user action", "Close All Other"), this);
997 actionCollection()->setDefaultShortcut(d->m_closeAllOtherPagesAction, Qt::CTRL + Qt::ALT + Qt::Key_W);
998 connect(d->m_closeAllOtherPagesAction, &QAction::triggered, this, [ = ] {this->closeAllOtherPages(nullptr);});
999 registerGlobalAction(QStringLiteral("tab_closeallother"), d->m_closeAllOtherPagesAction);
1000
1001 //
1002 d->m_saveDefaultStateAction = new QAction(SKGServices::fromTheme(QStringLiteral("document-save")), i18nc("Noun, user action", "Save page state"), this);
1003 actionCollection()->setDefaultShortcut(d->m_saveDefaultStateAction, Qt::CTRL + Qt::ALT + Qt::Key_S);
1004 connect(d->m_saveDefaultStateAction, &QAction::triggered, this, &SKGMainPanel::saveDefaultState);
1005 registerGlobalAction(QStringLiteral("tab_savedefaultstate"), d->m_saveDefaultStateAction);
1006
1007 //
1008 d->m_resetDefaultStateAction = new QAction(SKGServices::fromTheme(QStringLiteral("edit-clear")), i18nc("Noun, user action", "Reset page state"), this);
1009 actionCollection()->setDefaultShortcut(d->m_resetDefaultStateAction, Qt::CTRL + Qt::ALT + Qt::Key_R);
1010 connect(d->m_resetDefaultStateAction, &QAction::triggered, this, &SKGMainPanel::resetDefaultState);
1011 registerGlobalAction(QStringLiteral("tab_resetdefaultstate"), d->m_resetDefaultStateAction);
1012
1013 //
1014 d->m_reopenLastClosed = new QAction(SKGServices::fromTheme(QStringLiteral("tab-new")), i18nc("Noun, user action", "Reopen last page closed"), this);
1015 actionCollection()->setDefaultShortcut(d->m_reopenLastClosed, Qt::CTRL + Qt::ALT + Qt::Key_T);
1016 connect(d->m_reopenLastClosed, &QAction::triggered, this, &SKGMainPanel::onReopenLastClosed);
1017 registerGlobalAction(QStringLiteral("tab_reopenlastclosed"), d->m_reopenLastClosed);
1018
1019 //
1020 QStringList overlay;
1021 overlay.push_back(QStringLiteral("bookmarks"));
1022 d->m_overwriteBookmarkStateAction = new QAction(SKGServices::fromTheme(QStringLiteral("document-save"), overlay), i18nc("Noun, user action", "Overwrite bookmark state"), this);
1023 connect(d->m_overwriteBookmarkStateAction, &QAction::triggered, this, &SKGMainPanel::overwriteBookmarkState);
1024 actionCollection()->setDefaultShortcut(d->m_overwriteBookmarkStateAction, Qt::CTRL + Qt::ALT + Qt::Key_B);
1025 registerGlobalAction(QStringLiteral("tab_overwritebookmark"), d->m_overwriteBookmarkStateAction);
1026
1027 //
1028 d->m_configureAction = new QAction(SKGServices::fromTheme(QStringLiteral("configure")), i18nc("Noun, user action", "Configure..."), this);
1029 connect(d->m_configureAction, &QAction::triggered, this, [ = ] {this->optionsPreferences();});
1030 registerGlobalAction(QStringLiteral("tab_configure"), d->m_configureAction);
1031
1032 // Menu
1033 d->m_buttonMenuAction = new KToolBarPopupAction(SKGServices::fromTheme(QStringLiteral("configure")), QLatin1String(""), this);
1034 d->m_buttonMenuAction->setToolTip(i18nc("Noun, user action", "Menu"));
1035 d->m_buttonMenu = d->m_buttonMenuAction->menu();
1036 connect(d->m_buttonMenu, &QMenu::aboutToShow, this, &SKGMainPanel::onShowButtonMenu);
1037 d->m_buttonMenuAction->setDelayed(false);
1038 registerGlobalAction(QStringLiteral("view_menu"), d->m_buttonMenuAction);
1039
1040 d->m_showMenuBarAction = KStandardAction::showMenubar(this, SLOT(onShowMenuBar()), actionCollection());
1041 KConfigGroup pref = getMainConfigGroup();
1042 d->m_showMenuBarAction->setChecked(pref.readEntry("menubar_shown", true));
1043 QTimer::singleShot(200, Qt::CoarseTimer, this, &SKGMainPanel::onShowMenuBar);
1044 registerGlobalAction(QStringLiteral("options_show_menubar"), d->m_showMenuBarAction);
1045
1046 //
1047 d->m_previousAction = new KToolBarPopupAction(SKGServices::fromTheme(QStringLiteral("go-previous")), i18nc("Noun, user action", "Previous"), this);
1048 connect(d->m_previousAction, &QAction::triggered, this, &SKGMainPanel::onPrevious);
1049 actionCollection()->setDefaultShortcut(d->m_previousAction, Qt::ALT + Qt::Key_Left);
1050 d->m_previousAction->setPriority(QAction::LowPriority);
1051 d->m_previousMenu = d->m_previousAction->menu();
1052 connect(d->m_previousMenu, &QMenu::aboutToShow, this, &SKGMainPanel::onShowPreviousMenu);
1053 d->m_previousAction->setStickyMenu(false);
1054 d->m_previousAction->setData(0);
1055 registerGlobalAction(QStringLiteral("go_previous"), d->m_previousAction);
1056
1057 //
1058 d->m_nextAction = new KToolBarPopupAction(SKGServices::fromTheme(QStringLiteral("go-next")), i18nc("Noun, user action", "Next"), this);
1059 connect(d->m_nextAction, &QAction::triggered, this, &SKGMainPanel::onNext);
1060 actionCollection()->setDefaultShortcut(d->m_nextAction, Qt::ALT + Qt::Key_Right);
1061 d->m_nextAction->setPriority(QAction::LowPriority);
1062 d->m_nextMenu = d->m_nextAction->menu();
1063 connect(d->m_nextMenu, &QMenu::aboutToShow, this, &SKGMainPanel::onShowNextMenu);
1064 d->m_nextAction->setStickyMenu(false);
1065 d->m_nextAction->setData(0);
1066 registerGlobalAction(QStringLiteral("go_next"), d->m_nextAction);
1067
1068 //
1069 d->m_fullScreenAction = actionCollection()->addAction(KStandardAction::FullScreen, QStringLiteral("fullscreen"), this, SLOT(onFullScreen()));
1070 registerGlobalAction(QStringLiteral("fullscreen"), d->m_fullScreenAction);
1071
1072 //
1073 d->m_enableEditorAction = new QAction(SKGServices::fromTheme(QStringLiteral("appointment-new")), i18nc("Noun, user action", "Enable editor"), this);
1074 actionCollection()->setDefaultShortcut(d->m_enableEditorAction, Qt::CTRL + Qt::Key_Insert);
1075 connect(d->m_enableEditorAction, &QAction::triggered, this, &SKGMainPanel::enableEditor);
1076 registerGlobalAction(QStringLiteral("enable_editor"), d->m_enableEditorAction);
1077
1078 //
1079 auto migrateSQLCipher = new QAction(SKGServices::fromTheme(QStringLiteral("run-build")), i18nc("Noun, user action", "Migrate to SQLCipher format"), this);
1080 connect(migrateSQLCipher, &QAction::triggered, this, &SKGMainPanel::onMigrateToSQLCipher);
1081 registerGlobalAction(QStringLiteral("migrate_sqlcipher"), migrateSQLCipher);
1082
1083 // Contextual menu
1084 d->m_tabWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
1085 d->m_tabWidget->insertAction(nullptr, getGlobalAction(QStringLiteral("new_tab")));
1086 d->m_tabWidget->insertAction(nullptr, getGlobalAction(QStringLiteral("tab_reopenlastclosed")));
1087 d->m_tabWidget->insertAction(nullptr, getGlobalAction(QStringLiteral("tab_close")));
1088 d->m_tabWidget->insertAction(nullptr, getGlobalAction(QStringLiteral("tab_closeall")));
1089 d->m_tabWidget->insertAction(nullptr, getGlobalAction(QStringLiteral("tab_closeallother")));
1090 {
1091 auto sep = new QAction(this);
1092 sep->setSeparator(true);
1093 d->m_tabWidget->insertAction(nullptr, sep);
1094 }
1095 d->m_tabWidget->insertAction(nullptr, getGlobalAction(QStringLiteral("tab_switchpin")));
1096 d->m_tabWidget->insertAction(nullptr, getGlobalAction(QStringLiteral("tab_resetdefaultstate")));
1097 d->m_tabWidget->insertAction(nullptr, getGlobalAction(QStringLiteral("tab_savedefaultstate")));
1098 d->m_tabWidget->insertAction(nullptr, getGlobalAction(QStringLiteral("tab_overwritebookmark")));
1099 d->m_tabWidget->insertAction(nullptr, getGlobalAction(QStringLiteral("tab_configure")));
1100 {
1101 auto sep = new QAction(this);
1102 sep->setSeparator(true);
1103 d->m_tabWidget->insertAction(nullptr, sep);
1104 }
1105 d->m_tabWidget->insertAction(nullptr, getGlobalAction(QStringLiteral("fullscreen")));
1106 }
1107
enableEditor()1108 void SKGMainPanel::enableEditor()
1109 {
1110 SKGTabPage* cPage = currentPage();
1111 if (cPage != nullptr) {
1112 cPage->activateEditor();
1113 }
1114 }
1115
onPrevious()1116 void SKGMainPanel::onPrevious()
1117 {
1118 SKGError err;
1119 SKGTRACEINFUNCRC(10, err)
1120
1121 SKGTabPage* cPage = currentPage();
1122 if (cPage != nullptr) {
1123 // Get index in history of page to refresh
1124 int indexPrevious = qobject_cast<QAction*>(sender())->data().toInt();
1125
1126 // Get lists
1127 SKGTabPage::SKGPageHistoryItemList listPrevious = cPage->getPreviousPages();
1128 if (indexPrevious < listPrevious.count()) {
1129 SKGTabPage::SKGPageHistoryItemList listNext = cPage->getNextPages();
1130 SKGTabPage::SKGPageHistoryItem current = currentPageHistoryItem();
1131
1132 // Get item to refresh
1133 SKGTabPage::SKGPageHistoryItem item = listPrevious.at(indexPrevious);
1134
1135 // Open page
1136 cPage = openPage(getPluginByName(item.plugin), currentPageIndex(), item.state, item.name, item.bookmarkID);
1137 if (cPage != nullptr) {
1138 cPage->setBookmarkID(item.bookmarkID);
1139
1140 // Update lists
1141 listNext.insert(0, current);
1142 listPrevious.removeAt(indexPrevious);
1143 for (int i = 0; i < indexPrevious; ++i) {
1144 SKGTabPage::SKGPageHistoryItem itemPrevious = listPrevious.at(0); // Because the list is modified
1145 listNext.insert(0, itemPrevious);
1146 listPrevious.removeAt(0);
1147 }
1148
1149 // Set lists
1150 cPage->setPreviousPages(listPrevious);
1151 cPage->setNextPages(listNext);
1152 }
1153
1154 refresh();
1155 }
1156 }
1157 }
1158
onShowPreviousMenu()1159 void SKGMainPanel::onShowPreviousMenu()
1160 {
1161 if (d->m_previousMenu != nullptr) {
1162 d->m_previousMenu->clear();
1163
1164 SKGTabPage* cPage = currentPage();
1165 if (cPage != nullptr) {
1166 SKGTabPage::SKGPageHistoryItemList list = cPage->getPreviousPages();
1167 int nb = list.count();
1168 for (int i = 0; i < nb; ++i) {
1169 QAction* act = d->m_previousMenu->addAction(SKGServices::fromTheme(list.at(i).icon), list.at(i).name);
1170 if (act != nullptr) {
1171 act->setData(i);
1172 connect(act, &QAction::triggered, this, &SKGMainPanel::onPrevious);
1173 }
1174 }
1175 }
1176 }
1177 }
1178
onShowMenuBar()1179 void SKGMainPanel::onShowMenuBar()
1180 {
1181 bool test = d->m_showMenuBarAction->isChecked();
1182 menuBar()->setVisible(test);
1183 d->m_buttonMenuAction->setVisible(!test);
1184
1185 KConfigGroup pref = getMainConfigGroup();
1186 pref.writeEntry("menubar_shown", test);
1187 }
1188
onFullScreen()1189 void SKGMainPanel::onFullScreen()
1190 {
1191 auto* p = d->m_tabWidget;
1192 if (p != nullptr) {
1193 if (!d->m_fullScreenAction->isChecked()) {
1194 // No Full screen
1195 p->setWindowState(p->windowState() & ~Qt::WindowFullScreen); // reset
1196 d->m_mainLayout->addWidget(d->m_tabWidget);
1197 } else {
1198 bool atLeastOnePageOpened = (d->m_tabWidget->count() > 0);
1199 if (atLeastOnePageOpened) {
1200 // Activate Full screen mode
1201 p->setParent(nullptr);
1202 p->setWindowFlags(p->windowFlags() | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
1203 p->setWindowState(p->windowState() | Qt::WindowFullScreen); // set
1204 p->show();
1205
1206 displayMessage(i18nc("Information message", "You can exit full screen mode with %1 or with the contextual menu", d->m_fullScreenAction->shortcut().toString()));
1207 } else {
1208 d->m_fullScreenAction->setChecked(false);
1209 displayMessage(i18nc("Information message", "At least one page must be opened to enable full screen mode"), SKGDocument::Error);
1210 }
1211 }
1212 }
1213 }
1214
onNext()1215 void SKGMainPanel::onNext()
1216 {
1217 SKGError err;
1218 SKGTRACEINFUNCRC(10, err)
1219
1220 SKGTabPage* cPage = currentPage();
1221 if (cPage != nullptr) {
1222 // Get index in history of page to refresh
1223 int posNext = qobject_cast<QAction*>(sender())->data().toInt();
1224
1225 // Get lists
1226 SKGTabPage::SKGPageHistoryItemList listPrevious = cPage->getPreviousPages();
1227 SKGTabPage::SKGPageHistoryItemList listNext = cPage->getNextPages();
1228 SKGTabPage::SKGPageHistoryItem current = currentPageHistoryItem();
1229
1230 // Get item to refresh
1231 SKGTabPage::SKGPageHistoryItem item = listNext.at(posNext);
1232
1233 // Open page
1234 cPage = openPage(getPluginByName(item.plugin), currentPageIndex(), item.state, item.name, item.bookmarkID);
1235 if (cPage != nullptr) {
1236 cPage->setBookmarkID(item.bookmarkID);
1237
1238 // Update lists
1239 listPrevious.insert(0, current);
1240 listNext.removeAt(posNext);
1241 for (int i = 0; i < posNext; ++i) {
1242 SKGTabPage::SKGPageHistoryItem itemNext = listNext.at(0); // Because the list is modified
1243 listPrevious.insert(0, itemNext);
1244 listNext.removeAt(0);
1245 }
1246
1247 // Set lists
1248 cPage->setPreviousPages(listPrevious);
1249 cPage->setNextPages(listNext);
1250 }
1251
1252 refresh();
1253 }
1254 }
1255
onReopenLastClosed()1256 void SKGMainPanel::onReopenLastClosed()
1257 {
1258 SKGError err;
1259 SKGTRACEINFUNCRC(10, err)
1260
1261 SKGTabPage::SKGPageHistoryItem current = currentPageHistoryItem();
1262
1263 // Get item to refresh
1264 historyPage item = d->m_historyClosedPages.takeLast();
1265
1266 // Open page
1267 SKGTabPage* cPage = openPage(getPluginByName(item.current.plugin), -1, item.current.state, item.current.name, item.current.bookmarkID);
1268 if (cPage != nullptr) {
1269 cPage->setBookmarkID(item.current.bookmarkID);
1270 cPage->setNextPages(item.next);
1271 cPage->setPreviousPages(item.previous);
1272 }
1273
1274 refresh();
1275 }
1276
onLockDocks()1277 void SKGMainPanel::onLockDocks()
1278 {
1279 QObjectList cs = children();
1280 for (auto c : qAsConst(cs)) {
1281 auto* doc = qobject_cast<QDockWidget*>(c);
1282 if (doc != nullptr) {
1283 doc->setFeatures(QDockWidget::NoDockWidgetFeatures);
1284 }
1285 }
1286
1287 KConfigGroup pref = getMainConfigGroup();
1288 pref.writeEntry("docks_locked", true);
1289
1290 refresh();
1291 }
1292
onUnlockDocks()1293 void SKGMainPanel::onUnlockDocks()
1294 {
1295 QObjectList cs = children();
1296 for (auto c : qAsConst(cs)) {
1297 auto* doc = qobject_cast<QDockWidget*>(c);
1298 if (doc != nullptr) {
1299 doc->setFeatures(QDockWidget::AllDockWidgetFeatures);
1300 }
1301 }
1302
1303 KConfigGroup pref = getMainConfigGroup();
1304 pref.writeEntry("docks_locked", false);
1305
1306 refresh();
1307 }
1308
onConfigureNotifications()1309 void SKGMainPanel::onConfigureNotifications()
1310 {
1311 KNotifyConfigWidget::configure(this);
1312 }
1313
onShowNextMenu()1314 void SKGMainPanel::onShowNextMenu()
1315 {
1316 if (d->m_nextMenu != nullptr) {
1317 d->m_nextMenu->clear();
1318
1319 SKGTabPage* cPage = currentPage();
1320 if (cPage != nullptr) {
1321 SKGTabPage::SKGPageHistoryItemList list = cPage->getNextPages();
1322 int nb = list.count();
1323 for (int i = 0; i < nb; ++i) {
1324 QAction* act = d->m_nextMenu->addAction(SKGServices::fromTheme(list.at(i).icon), list.at(i).name);
1325 if (act != nullptr) {
1326 act->setData(i);
1327 connect(act, &QAction::triggered, this, &SKGMainPanel::onNext);
1328 }
1329 }
1330 }
1331 }
1332 }
1333
onShowButtonMenu()1334 void SKGMainPanel::onShowButtonMenu()
1335 {
1336 if (d->m_buttonMenu != nullptr) {
1337 d->m_buttonMenu->clear();
1338
1339 QMenuBar* mb = menuBar();
1340 if (mb != nullptr) {
1341 d->m_buttonMenu->addActions(mb->actions());
1342 }
1343 }
1344 }
1345
queryClose()1346 bool SKGMainPanel::queryClose()
1347 {
1348 SKGTRACEINFUNC(1)
1349 // Bug 2777697: To be sure that all page modifications are closed
1350 closeAllPages();
1351 // Bug 2777697:
1352
1353 bool output = queryFileClose();
1354
1355 // To be sure that the application is not closed in fullscreen mode
1356 if (output) {
1357 if (d->m_fullScreenAction->isChecked()) {
1358 d->m_fullScreenAction->trigger();
1359 }
1360 }
1361
1362 return output;
1363 }
1364
setSaveOnClose(bool iSaveOnClose)1365 void SKGMainPanel::setSaveOnClose(bool iSaveOnClose)
1366 {
1367 d->m_saveOnClose = iSaveOnClose;
1368 }
1369
queryFileClose()1370 bool SKGMainPanel::queryFileClose()
1371 {
1372 SKGTRACEINFUNC(1)
1373 bool output = true;
1374 if (getDocument()->getCurrentTransaction() != 0) {
1375 displayMessage(i18nc("skgtestimportskg", "The application cannot be closed when an operation is running."), SKGDocument::Error);
1376 output = false;
1377 } else if (getDocument()->isFileModified()) {
1378 QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
1379 int code = KMessageBox::Yes;
1380 QString fileName = getDocument()->getCurrentFileName();
1381 QAction* save = getGlobalAction(fileName.isEmpty() ? QStringLiteral("file_save_as") : QStringLiteral("file_save"));
1382 if (save != nullptr) {
1383 if (!d->m_saveOnClose) {
1384 code = KMessageBox::questionYesNoCancel(this, i18nc("Question", "The document has been modified.\nDo you want to save it before closing?"),
1385 QString(),
1386 KGuiItem(fileName.isEmpty() ? i18nc("Question", "Save as") : i18nc("Question", "Save"),
1387 SKGServices::fromTheme(fileName.isEmpty() ? QStringLiteral("document-save-as") : QStringLiteral("document-save"))),
1388 KGuiItem(i18nc("Question", "Do not save")));
1389 }
1390 if (code == KMessageBox::Yes) {
1391 save->trigger();
1392 }
1393 output = (code == KMessageBox::No || code == KMessageBox::Yes);
1394 } else {
1395 code = KMessageBox::questionYesNo(this, i18nc("Question", "Current modifications will not be saved.\nDo you want to continue?"));
1396 output = (code == KMessageBox::Yes);
1397 }
1398 QApplication::restoreOverrideCursor();
1399 }
1400
1401 return output;
1402 }
1403
getFirstSelectedObject() const1404 SKGObjectBase SKGMainPanel::getFirstSelectedObject() const
1405 {
1406 SKGObjectBase selection;
1407 SKGWidget* cPage = (d->m_widgetHavingSelection != nullptr ? d->m_widgetHavingSelection : currentPage());
1408 if (cPage != nullptr) {
1409 selection = cPage->getFirstSelectedObject();
1410 }
1411 return selection;
1412 }
1413
getSelectedObjects() const1414 SKGObjectBase::SKGListSKGObjectBase SKGMainPanel::getSelectedObjects() const
1415 {
1416 SKGObjectBase::SKGListSKGObjectBase selection;
1417 SKGWidget* cPage = (d->m_widgetHavingSelection != nullptr ? d->m_widgetHavingSelection : currentPage());
1418 if (cPage != nullptr) {
1419 selection = cPage->getSelectedObjects();
1420 }
1421 return selection;
1422 }
1423
getNbSelectedObjects() const1424 int SKGMainPanel::getNbSelectedObjects() const
1425 {
1426 int nb = 0;
1427 SKGWidget* cPage = (d->m_widgetHavingSelection != nullptr ? d->m_widgetHavingSelection : currentPage());
1428 if (cPage != nullptr) {
1429 nb = cPage->getNbSelectedObjects();
1430 }
1431 return nb;
1432 }
1433
hasSelectionWithFocus()1434 bool SKGMainPanel::hasSelectionWithFocus()
1435 {
1436 bool output = false;
1437 SKGWidget* cPage = (d->m_widgetHavingSelection != nullptr ? d->m_widgetHavingSelection : currentPage());
1438 if (cPage != nullptr) {
1439 output = cPage->hasSelectionWithFocus();
1440 }
1441 return output;
1442 }
1443
getAdvice() const1444 SKGAdviceList SKGMainPanel::getAdvice() const
1445 {
1446 SKGTRACEINFUNC(1)
1447 // Get list of ignored advice
1448 QString currentMonth = QDate::currentDate().toString(QStringLiteral("yyyy-MM"));
1449 QStringList ignoredAdvice = getDocument()->getParameters(QStringLiteral("advice"), "t_value='I' OR t_value='I_" % currentMonth % '\'');
1450
1451 // Build the list of all advice by requesting all plugins
1452 SKGAdviceList globalAdviceList;
1453 int index = 0;
1454 while (index >= 0) {
1455 SKGInterfacePlugin* plugin = SKGMainPanel::getMainPanel()->getPluginByIndex(index);
1456 if (plugin != nullptr) {
1457 const auto list = plugin->advice(ignoredAdvice);
1458 for (const auto& ad : list) {
1459 if (!ignoredAdvice.contains(ad.getUUID()) && !ignoredAdvice.contains(SKGServices::splitCSVLine(ad.getUUID(), '|').at(0))) {
1460 globalAdviceList.push_back(ad);
1461 }
1462 }
1463 } else {
1464 index = -2;
1465 }
1466 ++index;
1467 }
1468 std::sort(globalAdviceList.begin(), globalAdviceList.end(), SKGMainPanelPrivate::adviceLessThan);
1469
1470 return globalAdviceList;
1471 }
1472
getMainConfigGroup()1473 KConfigGroup SKGMainPanel::getMainConfigGroup()
1474 {
1475 KSharedConfigPtr config = KSharedConfig::openConfig();
1476 return config->group("Main Panel");
1477 }
1478
optionsPreferences(const QString & iPluginName)1479 void SKGMainPanel::optionsPreferences(const QString& iPluginName)
1480 {
1481 SKGTRACEINFUNC(1)
1482 // Compute page
1483 QString pluginName = iPluginName;
1484 if (pluginName.isEmpty()) {
1485 auto* act = qobject_cast<QAction*>(sender());
1486 if (act != nullptr) {
1487 pluginName = act->property("page").toString();
1488 }
1489 }
1490 if (pluginName.isEmpty() && (this->currentPage() != nullptr)) {
1491 pluginName = this->currentPage()->objectName();
1492 }
1493 SKGTRACEL(1) << "Open setting page: " << pluginName << SKGENDL;
1494 // Synchronize setting with confirmation panel
1495 if (skgbasegui_settings::update_modified_bookmarks() == 0) {
1496 KMessageBox::ButtonCode confirm;
1497 bool ask = KMessageBox::shouldBeShownYesNo(QStringLiteral("updateBookmarkOnClose"), confirm);
1498
1499 KConfigGroup pref = getMainConfigGroup();
1500 if (ask) {
1501 pref.writeEntry("update_modified_bookmarks", 0, KConfigBase::Normal);
1502 SKGTRACEL(1) << "update_modified_bookmarks set to ASK" << SKGENDL;
1503 } else if (confirm == KMessageBox::Yes) {
1504 pref.writeEntry("update_modified_bookmarks", 1, KConfigBase::Normal);
1505 SKGTRACEL(1) << "update_modified_bookmarks set to ALWAYS" << SKGENDL;
1506 } else {
1507 pref.writeEntry("update_modified_bookmarks", 2, KConfigBase::Normal);
1508 SKGTRACEL(1) << "update_modified_bookmarks set to NEVER" << SKGENDL;
1509 }
1510 }
1511
1512 if (skgbasegui_settings::update_modified_contexts() == 0) {
1513 KMessageBox::ButtonCode confirm;
1514 bool ask = KMessageBox::shouldBeShownYesNo(QStringLiteral("updateContextOnClose"), confirm);
1515
1516 KConfigGroup pref = getMainConfigGroup();
1517 if (ask) {
1518 pref.writeEntry("update_modified_contexts", 0, KConfigBase::Normal);
1519 SKGTRACEL(1) << "update_modified_contexts set to ASK" << SKGENDL;
1520 } else if (confirm == KMessageBox::Yes) {
1521 pref.writeEntry("update_modified_contexts", 1, KConfigBase::Normal);
1522 SKGTRACEL(1) << "update_modified_contexts set to ALWAYS" << SKGENDL;
1523 } else {
1524 pref.writeEntry("update_modified_contexts", 2, KConfigBase::Normal);
1525 SKGTRACEL(1) << "update_modified_contexts set to NEVER" << SKGENDL;
1526 }
1527 }
1528 skgbasegui_settings::self()->load();
1529
1530
1531 if (KConfigDialog::showDialog(QStringLiteral("settings"))) {
1532 return;
1533 }
1534
1535 auto dialog = new KConfigDialog(this, QStringLiteral("settings"), skgbasegui_settings::self());
1536
1537 // Add main
1538 auto w = new QWidget();
1539 d->uipref.setupUi(w);
1540 d->uipref.kcfg_date_format->addItem(i18nc("Date format", "Short date (%1, %2)",
1541 QLocale().toString(QDate::currentDate(), QLocale::ShortFormat),
1542 QLocale().toString(QDate::currentDate().addDays(-10), QLocale::ShortFormat)));
1543 d->uipref.kcfg_date_format->addItem(i18nc("Date format", "Long date (%1, %2)",
1544 QLocale().toString(QDate::currentDate(), QLocale::LongFormat),
1545 QLocale().toString(QDate::currentDate().addDays(-10), QLocale::LongFormat)));
1546 d->uipref.kcfg_date_format->addItem(i18nc("Date format", "Fancy short date (%1, %2)",
1547 KFormat().formatRelativeDate(QDate::currentDate(), QLocale::ShortFormat),
1548 KFormat().formatRelativeDate(QDate::currentDate().addDays(-10), QLocale::ShortFormat)));
1549 d->uipref.kcfg_date_format->addItem(i18nc("Date format", "Fancy long date (%1, %2)",
1550 KFormat().formatRelativeDate(QDate::currentDate(), QLocale::LongFormat),
1551 KFormat().formatRelativeDate(QDate::currentDate().addDays(-10), QLocale::LongFormat)));
1552 d->uipref.kcfg_date_format->addItem(i18nc("Date format", "ISO date (%1, %2)",
1553 QDate::currentDate().toString(Qt::ISODate),
1554 QDate::currentDate().addDays(-10).toString(Qt::ISODate)));
1555 dialog->addPage(w, skgbasegui_settings::self(), i18nc("Noun", "General"), QStringLiteral("preferences-other"));
1556
1557 // Add plugin in client in right order
1558 int nbplugin = d->m_pluginsList.count();
1559 for (int j = 0; j < nbplugin; ++j) {
1560 SKGInterfacePlugin* pluginInterface = getPluginByIndex(j);
1561 if (pluginInterface != nullptr) {
1562 QWidget* w2 = pluginInterface->getPreferenceWidget();
1563 if (w2 != nullptr) {
1564 auto icon = SKGServices::fromTheme(pluginInterface->icon());
1565 KPageWidgetItem* p = dialog->addPage(w2, pluginInterface->getPreferenceSkeleton(), pluginInterface->title(), icon.name());
1566 if ((p != nullptr) && pluginName == pluginInterface->objectName()) {
1567 dialog->setCurrentPage(p);
1568 }
1569 }
1570 }
1571 }
1572
1573 connect(dialog, &KConfigDialog::settingsChanged, this, &SKGMainPanel::onSettingsChanged);
1574
1575 dialog->setAttribute(Qt::WA_DeleteOnClose);
1576 dialog->show();
1577
1578 // Refresh
1579 refresh();
1580 }
1581
onSettingsChanged()1582 void SKGMainPanel::onSettingsChanged()
1583 {
1584 SKGError err;
1585 SKGTRACEINFUNCRC(1, err) {
1586 int nb = d->m_pluginsList.count();
1587 SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Save settings"), err, nb)
1588
1589 // Refresh plugins
1590 for (int i = 0; !err && i < nb; ++i) {
1591 err = getPluginByIndex(i)->savePreferences();
1592 IFOKDO(err, getDocument()->stepForward(i + 1))
1593 }
1594
1595 // Setting for tab position
1596 d->refreshTabPosition();
1597
1598 // Setting for bookmarks modification
1599 {
1600 int option = skgbasegui_settings::update_modified_bookmarks();
1601 if (option == 0) {
1602 // ASK: remove following setting
1603 KMessageBox::enableMessage(QStringLiteral("updateBookmarkOnClose"));
1604 SKGTRACEL(1) << "updateBookmarkOnClose set to ASK" << SKGENDL;
1605 } else if (option == 1) {
1606 // ALWAYS: set following setting
1607 KMessageBox::saveDontShowAgainYesNo(QStringLiteral("updateBookmarkOnClose"), KMessageBox::Yes);
1608 SKGTRACEL(1) << "updateBookmarkOnClose set to Yes" << SKGENDL;
1609 } else {
1610 // NEVER: set following setting
1611 KMessageBox::saveDontShowAgainYesNo(QStringLiteral("updateBookmarkOnClose"), KMessageBox::No);
1612 SKGTRACEL(1) << "updateBookmarkOnClose set to No" << SKGENDL;
1613 }
1614 }
1615 {
1616 int option = skgbasegui_settings::update_modified_contexts();
1617 if (option == 0) {
1618 // ASK: remove following setting
1619 KMessageBox::enableMessage(QStringLiteral("updateContextOnClose"));
1620 SKGTRACEL(1) << "updateContextOnClose set to ASK" << SKGENDL;
1621 } else if (option == 1) {
1622 // ALWAYS: set following setting
1623 KMessageBox::saveDontShowAgainYesNo(QStringLiteral("updateContextOnClose"), KMessageBox::Yes);
1624 SKGTRACEL(1) << "updateContextOnClose set to Yes" << SKGENDL;
1625 } else {
1626 // NEVER: set following setting
1627 KMessageBox::saveDontShowAgainYesNo(QStringLiteral("updateContextOnClose"), KMessageBox::No);
1628 SKGTRACEL(1) << "updateContextOnClose set to No" << SKGENDL;
1629 }
1630 }
1631 skgbasegui_settings::self()->load();
1632 }
1633
1634 // Rebuild system tray
1635 d->rebuildSystemTray();
1636
1637 emit settingsChanged();
1638
1639 // Display error
1640 displayErrorMessage(err);
1641 }
1642
refresh()1643 void SKGMainPanel::refresh()
1644 {
1645 SKGTRACEINFUNC(1)
1646
1647 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1648
1649 // Show/hide main widget
1650 bool atLeastOnePageOpened = (d->m_tabWidget->count() > 0);
1651 d->m_tabWidget->setVisible(atLeastOnePageOpened);
1652 if (d->m_mainWidget != nullptr) {
1653 d->m_mainWidget->setVisible(!atLeastOnePageOpened);
1654 }
1655
1656 // Refresh actions
1657 d->m_widgetHavingSelection = qobject_cast<SKGWidget*>(sender());
1658 SKGObjectBase selection = SKGMainPanel::getMainPanel()->getFirstSelectedObject();
1659 int nbSelectedItems = SKGMainPanel::getMainPanel()->getNbSelectedObjects();
1660 bool hasFocus = SKGMainPanel::getMainPanel()->hasSelectionWithFocus();
1661
1662 QString selectedTable = (nbSelectedItems > 0 ? selection.getRealTable() : QLatin1String(""));
1663 for (const auto& actDetails : qAsConst(d->m_registeredGlogalAction)) {
1664 QStringList tables = actDetails.tables;
1665 if (tables.count() == 1 && tables.at(0).startsWith(QLatin1String("query:"))) {
1666 // Dynamic mode
1667 getDocument()->getDistinctValues(QStringLiteral("sqlite_master"), QStringLiteral("name"), tables.at(0).right(tables.at(0).count() - 6), tables);
1668 }
1669
1670 bool enabled = (tables.contains(selectedTable) || tables.isEmpty()) &&
1671 (nbSelectedItems >= actDetails.min) &&
1672 (nbSelectedItems <= actDetails.max || actDetails.max == -1) &&
1673 (!actDetails.focus || hasFocus);
1674
1675 if (enabled && nbSelectedItems == 0 && (actDetails.min == 0 || actDetails.min == -1)) {
1676 // Check if a page is opened
1677 SKGTabPage* page = SKGMainPanel::getMainPanel()->currentPage();
1678 if (page != nullptr) {
1679 auto* view = qobject_cast<QAbstractItemView*>(page->mainWidget());
1680 enabled = (actDetails.min == -1 || view != nullptr);
1681 } else {
1682 enabled = false;
1683 }
1684 }
1685 if (actDetails.action != nullptr) {
1686 actDetails.action->setEnabled(enabled);
1687 }
1688 }
1689
1690 // Refresh plugins
1691 int nb = d->m_pluginsList.count();
1692 for (int i = 0; i < nb; ++i) {
1693 getPluginByIndex(i)->refresh();
1694 }
1695
1696 // Enable addTabeAction
1697 SKGTabPage* toSave = currentPage();
1698 if (d->m_switchPinState != nullptr) {
1699 if ((toSave != nullptr) && toSave->isPin()) {
1700 d->m_switchPinState->setText(i18nc("Noun, user action", "Unpin this page"));
1701 } else {
1702 d->m_switchPinState->setText(i18nc("Noun, user action", "Pin this page"));
1703 }
1704 }
1705 if (d->m_closePageAction != nullptr) {
1706 d->m_closePageAction->setEnabled(atLeastOnePageOpened && (toSave != nullptr) && !toSave->isPin());
1707 }
1708 if (d->m_switchPinState != nullptr) {
1709 d->m_switchPinState->setEnabled(atLeastOnePageOpened);
1710 }
1711 if (d->m_closeAllOtherPagesAction != nullptr) {
1712 d->m_closeAllOtherPagesAction->setEnabled(d->m_tabWidget->count() > 1);
1713 }
1714 if (d->m_reopenLastClosed != nullptr) {
1715 d->m_reopenLastClosed->setEnabled(!d->m_historyClosedPages.isEmpty());
1716 }
1717
1718 if (d->m_saveDefaultStateAction != nullptr) {
1719 d->m_saveDefaultStateAction->setEnabled((toSave != nullptr) && !toSave->getDefaultStateAttribute().isEmpty());
1720 }
1721 if (d->m_resetDefaultStateAction != nullptr) {
1722 d->m_resetDefaultStateAction->setEnabled((toSave != nullptr) && !toSave->getDefaultStateAttribute().isEmpty());
1723 }
1724 if (d->m_overwriteBookmarkStateAction != nullptr) {
1725 d->m_overwriteBookmarkStateAction->setEnabled((toSave != nullptr) && !toSave->getBookmarkID().isEmpty());
1726 }
1727 if (d->m_enableEditorAction != nullptr) {
1728 d->m_enableEditorAction->setEnabled((toSave != nullptr) && toSave->isEditor());
1729 }
1730 if (d->m_zoomSelector != nullptr) {
1731 d->m_zoomSelector->setVisible((toSave != nullptr) && toSave->isZoomable());
1732 if (toSave != nullptr) {
1733 d->m_zoomSelector->setValue(toSave->zoomPosition());
1734 QWidget* zoomWidget = toSave->zoomableWidget();
1735 auto* treeView = qobject_cast<SKGTreeView*>(zoomWidget);
1736 if (treeView != nullptr) {
1737 disconnect(treeView, &SKGTreeView::zoomChanged, this, nullptr);
1738 connect(treeView, &SKGTreeView::zoomChanged, this, [ = ](int val) {
1739 d->m_zoomSelector->setValue(val);
1740 });
1741 } else {
1742 auto* webView = qobject_cast<SKGWebView*>(zoomWidget);
1743 if (webView != nullptr) {
1744 disconnect(webView, &SKGWebView::zoomChanged, this, nullptr);
1745 connect(webView, &SKGWebView::zoomChanged, this, [ = ](int val) {
1746 d->m_zoomSelector->setValue(val);
1747 });
1748 }
1749 }
1750 }
1751 }
1752
1753 if (d->m_actLock != nullptr) {
1754 d->m_actLock->setVisible(d->ui.kDockContext->features() == QDockWidget::AllDockWidgetFeatures);
1755 }
1756 if (d->m_actUnLock != nullptr) {
1757 d->m_actUnLock->setVisible(d->ui.kDockContext->features() == QDockWidget::NoDockWidgetFeatures);
1758 }
1759
1760 if (d->m_previousAction != nullptr) {
1761 SKGTabPage::SKGPageHistoryItemList list;
1762 if (toSave != nullptr) {
1763 list = toSave->getPreviousPages();
1764 }
1765 d->m_previousAction->setEnabled(!list.isEmpty());
1766 }
1767 if (d->m_nextAction != nullptr) {
1768 SKGTabPage::SKGPageHistoryItemList list;
1769 if (toSave != nullptr) {
1770 list = toSave->getNextPages();
1771 }
1772 d->m_nextAction->setEnabled(!list.isEmpty());
1773 }
1774
1775 // Set current selection of context
1776 d->ui.kContextList->clearSelection();
1777 if (toSave != nullptr) {
1778 // Get plugin of current page
1779 SKGInterfacePlugin* plugin = getPluginByName(toSave->objectName());
1780 int index = (plugin != nullptr ? plugin->property("contextItem").toInt() : -1);
1781 if (index != -1) {
1782 d->ui.kContextList->setCurrentItem(d->ui.kContextList->item(index));
1783 }
1784 }
1785
1786 // Set window title
1787 QString modified;
1788 if (getDocument()->isFileModified()) {
1789 modified += i18nc("Noun, indicate that current document is modified", " [modified]");
1790 }
1791 if (getDocument()->isReadOnly()) {
1792 modified += i18nc("Noun, indicate that current document is loaded in read only", " [read only]");
1793 }
1794 QString fileName = getDocument()->getCurrentFileName();
1795 if (fileName.isEmpty()) {
1796 fileName = i18nc("Noun, default name for a new document", "Untitled");
1797 } else {
1798 if (fileName != d->m_fileName) {
1799 // The file name has been changed
1800 onClearMessages();
1801
1802 d->m_fileName = fileName;
1803 #ifdef KActivities_FOUND
1804 if (!d->m_fileName.isEmpty()) {
1805 d->m_activityResourceInstance->setUri(d->m_fileName);
1806 }
1807 #endif
1808 }
1809 }
1810 setWindowTitle(i18nc("Title of the main window", "%1%2", fileName, modified));
1811
1812 QApplication::restoreOverrideCursor();
1813 }
1814
currentPageHistoryItem() const1815 SKGTabPage::SKGPageHistoryItem SKGMainPanel::currentPageHistoryItem() const
1816 {
1817 SKGTabPage::SKGPageHistoryItem cpage;
1818 int currentIndex = currentPageIndex();
1819 SKGTabPage* cPage = currentPage();
1820 if (currentIndex >= 0 && (cPage != nullptr)) {
1821 cpage.plugin = cPage->objectName();
1822 SKGInterfacePlugin* plugin = SKGMainPanel::getMainPanel()->getPluginByName(cpage.plugin);
1823 if (plugin != nullptr) {
1824 cpage.name = d->m_tabWidget->tabText(currentIndex);
1825 cpage.icon = plugin->icon();
1826 }
1827 cpage.state = cPage->getState();
1828 cpage.bookmarkID = cPage->getBookmarkID();
1829 }
1830
1831 return cpage;
1832 }
1833
openPage(SKGInterfacePlugin * plugin,int index,const QString & parameters,const QString & title,const QString & iID,bool iSetCurrent)1834 SKGTabPage* SKGMainPanel::openPage(SKGInterfacePlugin* plugin, int index, const QString& parameters, const QString& title, const QString& iID, bool iSetCurrent)
1835 {
1836 SKGTRACEINFUNC(1)
1837 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1838 bool previous = d->m_tabWidget->blockSignals(true);
1839 // If the current page is pin, then open new page
1840 SKGTabPage* cPage = currentPage();
1841 if ((cPage != nullptr) && cPage->isPin()) {
1842 index = -1;
1843 iSetCurrent = true;
1844 }
1845
1846 SKGTabPage* w = nullptr;
1847
1848 SKGTabPage::SKGPageHistoryItemList previousPages;
1849 if (index != -1) {
1850 int currentIndex = currentPageIndex();
1851 if (currentIndex >= 0 && (cPage != nullptr)) {
1852 previousPages = cPage->getPreviousPages();
1853 previousPages.insert(0, currentPageHistoryItem());
1854
1855 d->m_tabWidget->removeTab(currentIndex);
1856 closePage(cPage);
1857
1858 // Repair the history of closed page
1859 if (!d->m_historyClosedPages.isEmpty()) {
1860 d->m_historyClosedPages.removeLast();
1861 }
1862 }
1863 }
1864
1865 if (plugin != nullptr) {
1866 w = plugin->getWidget();
1867 if (w != nullptr) {
1868 // Title
1869 QString title2 = (title.isEmpty() ? plugin->title() : title);
1870 w->setObjectName(plugin->objectName());
1871 if (!iID.isEmpty()) {
1872 w->setBookmarkID(iID);
1873 }
1874
1875 QString param = parameters;
1876 if (param.isEmpty()) {
1877 QString def = w->getDefaultStateAttribute();
1878 if (!def.isEmpty()) {
1879 param = getDocument()->getParameter(def);
1880 }
1881 }
1882 SKGTRACEL(10) << "state=[" << param << "]" << SKGENDL;
1883 w->setState(param);
1884 connect(w, &SKGTabPage::selectionChanged, this, &SKGMainPanel::refresh);
1885 connect(w, &SKGTabPage::selectionChanged, this, &SKGMainPanel::selectionChanged);
1886 connect(w, &SKGTabPage::selectionFocusChanged, this, &SKGMainPanel::refresh);
1887
1888 if (index == -1) {
1889 SKGTRACEINFUNC(20)
1890 d->m_tabWidget->addTab(w, SKGServices::fromTheme(plugin->icon()), title2);
1891 if (iSetCurrent) {
1892 d->m_tabWidget->setCurrentWidget(w);
1893 }
1894 } else {
1895 SKGTRACEINFUNC(20)
1896 d->m_tabWidget->insertTab(index, w, SKGServices::fromTheme(plugin->icon()), title2);
1897 if (iSetCurrent) {
1898 d->m_tabWidget->setCurrentWidget(w);
1899 }
1900
1901 w->setPreviousPages(previousPages);
1902 SKGTabPage::SKGPageHistoryItemList empty;
1903 w->setNextPages(empty);
1904 }
1905 SKGTRACEL(1) << "opening plugin [" << plugin->objectName() << ']' << SKGENDL;
1906 Q_EMIT pageOpened();
1907 }
1908 } else {
1909 getDocument()->sendMessage(i18nc("An information message", "Impossible to open the page because the plugin was not found"), SKGDocument::Error);
1910 notify(); // Due to sendMessage not in a transaction
1911 }
1912
1913 // Show/hide main widget
1914 bool atLeastOnePageOpened = (d->m_tabWidget->count() > 0);
1915 d->m_tabWidget->setVisible(atLeastOnePageOpened);
1916 if (d->m_mainWidget != nullptr) {
1917 d->m_mainWidget->setVisible(!atLeastOnePageOpened);
1918 }
1919
1920 d->m_tabWidget->blockSignals(previous);
1921 if (iSetCurrent) {
1922 Q_EMIT currentPageChanged();
1923 }
1924 QApplication::restoreOverrideCursor();
1925 return w;
1926 }
1927
currentPageIndex() const1928 int SKGMainPanel::currentPageIndex() const
1929 {
1930 return d->m_tabWidget->currentIndex();
1931 }
1932
currentPage() const1933 SKGTabPage* SKGMainPanel::currentPage() const
1934 {
1935 return qobject_cast< SKGTabPage* >(d->m_tabWidget->currentWidget());
1936 }
1937
pageIndex(SKGTabPage * iPage) const1938 int SKGMainPanel::pageIndex(SKGTabPage* iPage) const
1939 {
1940 int nb = countPages();
1941 for (int i = 0; i < nb; ++i) {
1942 if (page(i) == iPage) {
1943 return i;
1944 }
1945 }
1946
1947 return -1;
1948 }
1949
splashScreen() const1950 QSplashScreen* SKGMainPanel::splashScreen() const
1951 {
1952 return d->m_splashScreen;
1953 }
1954
countPages() const1955 int SKGMainPanel::countPages() const
1956 {
1957 return d->m_tabWidget->count();
1958 }
1959
page(int iIndex) const1960 SKGTabPage* SKGMainPanel::page(int iIndex) const
1961 {
1962 return qobject_cast<SKGTabPage*>(d->m_tabWidget->widget(iIndex));
1963 }
1964
setCurrentPage(int iIndex)1965 void SKGMainPanel::setCurrentPage(int iIndex)
1966 {
1967 d->m_tabWidget->setCurrentIndex(iIndex);
1968 }
1969
onBeforeOpenContext()1970 void SKGMainPanel::onBeforeOpenContext()
1971 {
1972 d->m_middleClick = ((QApplication::mouseButtons() & Qt::MidButton) != 0u);
1973 }
1974
openPage(const QUrl & iUrl,bool iNewPage)1975 bool SKGMainPanel::openPage(const QUrl& iUrl, bool iNewPage)
1976 {
1977 const QUrl& url(iUrl);
1978 if (url.scheme() == QStringLiteral("skg")) {
1979 // Get plugin
1980 SKGInterfacePlugin* plugin = getPluginByName(url.host());
1981 if (plugin != nullptr) {
1982 // Open special page
1983 SKGTabPage* w = plugin->getWidget();
1984 if (w != nullptr) {
1985 // Create xml
1986 QString path = url.path().remove('/');
1987 QDomDocument doc(QStringLiteral("SKGML"));
1988 doc.setContent(getDocument()->getParameter(path.isEmpty() ? w->getDefaultStateAttribute() : path));
1989 QDomElement root = doc.documentElement();
1990 if (root.isNull()) {
1991 root = doc.createElement(QStringLiteral("parameters"));
1992 doc.appendChild(root);
1993 }
1994 auto params = QUrlQuery(url).queryItems();
1995 for (const auto& p : qAsConst(params)) {
1996 QString value = QUrl::fromPercentEncoding(p.second.toUtf8());
1997 SKGMainPanelPrivate::setAttribute(root, p.first, value);
1998 }
1999
2000 // Open page
2001 openPage(plugin, iNewPage ? -1 : currentPageIndex(), doc.toString(), url.fragment());
2002 return true;
2003 }
2004 } else {
2005 // Trigger action
2006 QAction* act = SKGMainPanel::getMainPanel()->getGlobalAction(url.host());
2007 if (act != nullptr) {
2008 auto params = QUrlQuery(url).queryItems();
2009 for (const auto& p : qAsConst(params)) {
2010 QString value = QUrl::fromPercentEncoding(p.second.toUtf8());
2011 act->setProperty(p.first.toUtf8().data(), value);
2012 }
2013
2014 act->trigger();
2015 return true;
2016 }
2017 }
2018 } else {
2019 QDesktopServices::openUrl(iUrl);
2020 return true;
2021 }
2022 displayErrorMessage(SKGError(ERR_ABORT, i18nc("Error message", "Unknown plugin or action [%1] in url [%2]", url.host(), iUrl.toString())));
2023
2024 return false;
2025 }
2026
openPage()2027 bool SKGMainPanel::openPage()
2028 {
2029 return openPage(QString());
2030 }
2031
openPage(const QString & iUrl,bool iNewPage)2032 bool SKGMainPanel::openPage(const QString& iUrl, bool iNewPage)
2033 {
2034 // Get the url
2035 QString urlString(iUrl);
2036 if (urlString.isEmpty()) {
2037 auto* act = qobject_cast< QAction* >(sender());
2038 if (act != nullptr) {
2039 urlString = act->data().toString();
2040 }
2041 }
2042
2043 return openPage(QUrl(urlString), iNewPage);
2044 }
2045
openPage(int iPage,bool iNewPage)2046 SKGTabPage* SKGMainPanel::openPage(int iPage, bool iNewPage)
2047 {
2048 SKGTRACEINFUNC(1)
2049 SKGTRACEL(1) << "iPage=" << iPage << SKGENDL;
2050 int index = d->ui.kContextList->item(iPage)->data(12).toInt();
2051 return openPage(getPluginByIndex(index), iNewPage ? -1 : currentPageIndex());
2052 }
2053
onOpenContext()2054 void SKGMainPanel::onOpenContext()
2055 {
2056 SKGTRACEINFUNC(1)
2057 if (!(QApplication::mouseButtons() & Qt::RightButton)) {
2058 int cpage = -1;
2059 auto* s = qobject_cast<QAction*>(this->sender());
2060 if (s != nullptr) {
2061 cpage = s->data().toInt();
2062 } else {
2063 cpage = d->ui.kContextList->currentRow();
2064 }
2065 if (cpage != -1) {
2066 openPage(cpage, ((QApplication::keyboardModifiers() &Qt::ControlModifier) != 0u) || d->m_middleClick || ((QGuiApplication::mouseButtons() & Qt::MidButton) != 0u));
2067 }
2068 }
2069 d->m_middleClick = false;
2070 }
2071
switchPinPage(QWidget * iWidget)2072 void SKGMainPanel::switchPinPage(QWidget* iWidget)
2073 {
2074 auto* toSwitch = qobject_cast< SKGTabPage* >(iWidget);
2075 if (toSwitch == nullptr) {
2076 toSwitch = currentPage();
2077 }
2078
2079 if (toSwitch != nullptr) {
2080 toSwitch->setPin(!toSwitch->isPin());
2081 Q_EMIT currentPageChanged();
2082 }
2083 }
2084
closePageByIndex(int iIndex)2085 void SKGMainPanel::closePageByIndex(int iIndex)
2086 {
2087 QWidget* w = nullptr;
2088 if (iIndex >= 0) {
2089 w = d->m_tabWidget->widget(iIndex);
2090 } else {
2091 w = d->m_tabWidget->currentWidget();
2092 }
2093
2094 closePage(w);
2095 }
2096
closeCurrentPage()2097 void SKGMainPanel::closeCurrentPage()
2098 {
2099 closePage(nullptr);
2100 }
2101
closePage(QWidget * iWidget,bool iForce)2102 void SKGMainPanel::closePage(QWidget* iWidget, bool iForce)
2103 {
2104 SKGTRACEINFUNC(1)
2105 if (getDocument()->getCurrentTransaction() != 0) {
2106 QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
2107 displayMessage(i18nc("Information message", "A page cannot be closed when an operation is running."), SKGDocument::Information);
2108 QApplication::restoreOverrideCursor();
2109 } else {
2110 auto* toRemove = qobject_cast< SKGTabPage* >(iWidget);
2111 if (toRemove == nullptr) {
2112 toRemove = currentPage();
2113 }
2114 if ((toRemove != nullptr) && toRemove->close(iForce)) {
2115 historyPage item;
2116 item.current = currentPageHistoryItem();
2117 item.next = toRemove->getNextPages();
2118 item.previous = toRemove->getPreviousPages();
2119 d->m_historyClosedPages.push_back(item);
2120 delete toRemove;
2121
2122 emit pageClosed();
2123 }
2124 }
2125
2126 // Show/hide main widget
2127 bool atLeastOnePageOpened = (d->m_tabWidget->count() > 0);
2128 d->m_tabWidget->setVisible(atLeastOnePageOpened);
2129 if (d->m_mainWidget != nullptr) {
2130 d->m_mainWidget->setVisible(!atLeastOnePageOpened);
2131 }
2132
2133 if (!atLeastOnePageOpened) {
2134 d->m_fullScreenAction->setChecked(false);
2135 onFullScreen();
2136 }
2137 }
2138
closeAllPages(bool iForce)2139 void SKGMainPanel::closeAllPages(bool iForce)
2140 {
2141 SKGTRACEINFUNC(1)
2142 bool previous = d->m_tabWidget->blockSignals(true);
2143 int nb = d->m_tabWidget->count();
2144 for (int i = nb - 1; i >= 0; --i) {
2145 auto* w = qobject_cast< SKGTabPage* >(d->m_tabWidget->widget(i));
2146 if ((w != nullptr) && (iForce || !w->isPin())) {
2147 closePage(w, iForce);
2148 }
2149 }
2150 d->m_tabWidget->blockSignals(previous);
2151 KMessageBox::enableMessage(QStringLiteral("closepinnedpage"));
2152 Q_EMIT currentPageChanged();
2153 }
2154
closeAllOtherPages(QWidget * iWidget)2155 void SKGMainPanel::closeAllOtherPages(QWidget* iWidget)
2156 {
2157 SKGTRACEINFUNC(1)
2158 bool previous = d->m_tabWidget->blockSignals(true);
2159 QWidget* toKeep = iWidget;
2160 if (toKeep == nullptr) {
2161 toKeep = currentPage();
2162 }
2163
2164 int nb = d->m_tabWidget->count();
2165 for (int i = nb - 1; i >= 0; --i) {
2166 auto* w = qobject_cast< SKGTabPage* >(d->m_tabWidget->widget(i));
2167 if ((w != nullptr) && w != toKeep && !w->isPin()) {
2168 closePage(w);
2169 }
2170 }
2171 d->m_tabWidget->blockSignals(previous);
2172 Q_EMIT currentPageChanged();
2173 }
2174
saveDefaultState()2175 void SKGMainPanel::saveDefaultState()
2176 {
2177 SKGTRACEINFUNC(1)
2178 SKGError err;
2179 SKGTabPage* toSave = currentPage();
2180 if (toSave != nullptr) {
2181 // Get bookmarks uuid
2182 QString uuid = toSave->getBookmarkID();
2183
2184 // Reset bookmarks uuid to overwrite page state
2185 toSave->setBookmarkID(QLatin1String(""));
2186
2187 // Overwrite
2188 toSave->overwrite(false);
2189
2190 // Set original bookmarks uuid
2191 toSave->setBookmarkID(uuid);
2192 }
2193 }
2194
overwriteBookmarkState()2195 void SKGMainPanel::overwriteBookmarkState()
2196 {
2197 SKGTRACEINFUNC(1)
2198 SKGError err;
2199 SKGTabPage* toSave = currentPage();
2200 if (toSave != nullptr) {
2201 // Get bookmarks uuid
2202 QString uuid = toSave->getBookmarkID();
2203 if (!uuid.isEmpty()) {
2204 // Overwrite
2205 toSave->overwrite(false);
2206 }
2207 }
2208 }
2209
resetDefaultState()2210 void SKGMainPanel::resetDefaultState()
2211 {
2212 SKGTRACEINFUNC(1)
2213 SKGError err;
2214 SKGTabPage* toSave = currentPage();
2215 if (toSave != nullptr) {
2216 QString name = toSave->getDefaultStateAttribute();
2217 if (!name.isEmpty()) {
2218 SKGBEGINLIGHTTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Reset default state"), err)
2219 IFOKDO(err, getDocument()->setParameter(name, QStringLiteral("<!DOCTYPE SKGML>")))
2220
2221 // Refresh panel
2222 IFOK(err) toSave->setState(QLatin1String(""));
2223 }
2224 }
2225
2226 // status bar
2227 IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Default state has been reset")))
2228 displayErrorMessage(err);
2229 }
2230
addTab()2231 void SKGMainPanel::addTab()
2232 {
2233 SKGTRACEINFUNC(1)
2234 SKGTabPage* cPage = currentPage();
2235 if (cPage != nullptr) {
2236 openPage(getPluginByName(cPage->objectName()));
2237 }
2238 }
2239
eventFilter(QObject * iObject,QEvent * iEvent)2240 bool SKGMainPanel::eventFilter(QObject* iObject, QEvent* iEvent)
2241 {
2242 if ((iObject != nullptr) && (iEvent != nullptr) && iEvent->type() == QEvent::Resize) {
2243 auto* rEvent = dynamic_cast<QResizeEvent*>(iEvent);
2244 if (rEvent != nullptr) {
2245 QSize newSize = rEvent->size();
2246
2247 // Compute icon size
2248 int s = qMax(qMin(newSize.width() / 5, 64), 16);
2249 d->ui.kContextList->setIconSize(QSize(s, s));
2250 }
2251 }
2252 return KXmlGuiWindow::eventFilter(iObject, iEvent);
2253 }
2254
getTipsOfDay() const2255 QStringList SKGMainPanel::getTipsOfDay() const
2256 {
2257 return d->m_tipsOfTheDay;
2258 }
2259
getTipOfDay() const2260 QString SKGMainPanel::getTipOfDay() const
2261 {
2262 auto tips = getTipsOfDay();
2263 return SKGServices::htmlToString(tips.at(QRandomGenerator::global()->bounded(tips.size())));
2264 }
2265
notify(int iTransaction)2266 void SKGMainPanel::notify(int iTransaction)
2267 {
2268 SKGTRACEINFUNC(1)
2269 SKGTRACEL(1) << "iTransaction=" << iTransaction << SKGENDL;
2270
2271 // Notify
2272 SKGObjectBase transaction(getDocument(), QStringLiteral("doctransaction"), iTransaction);
2273 if (iTransaction == 0 || transaction.getAttribute(QStringLiteral("t_mode")) != QStringLiteral("R")) {
2274 SKGDocument::SKGMessageList msg;
2275 getDocument()->getMessages(iTransaction, msg, false);
2276 int nbMessages = msg.count();
2277 if (nbMessages != 0) {
2278 // Build list of types
2279 SKGDocument::MessageType maxType = SKGDocument::Positive;
2280 QList<SKGDocument::MessageType> listGroups;
2281 listGroups.reserve(nbMessages);
2282 for (int i = 0; i < nbMessages; ++i) {
2283 SKGDocument::SKGMessage m = msg.at(i);
2284 // if the message has an action, it can not be grouped
2285 if (!m.Action.isEmpty()) {
2286 displayMessage(m.Text, m.Type, m.Action);
2287 msg.removeAt(i);
2288 i--;
2289 nbMessages--;
2290 } else {
2291 if (listGroups.isEmpty() || m.Type != listGroups.at(listGroups.count() - 1)) {
2292 listGroups.push_back(m.Type);
2293 }
2294 if (static_cast<int>(m.Type) >= static_cast<int>(maxType)) {
2295 maxType = m.Type;
2296 }
2297 }
2298 }
2299
2300 // Is the number of type acceptable?
2301 bool modeGrouped = false;
2302 if (listGroups.count() > 5 || nbMessages > 20) {
2303 // Too many group ==> simplification
2304 listGroups.clear();
2305 listGroups.push_back(maxType);
2306 modeGrouped = true;
2307 }
2308
2309 // Build message
2310 if (nbMessages != 0) {
2311 QString message;
2312 int indexGroup = 0;
2313 for (int i = 0; i < nbMessages; ++i) {
2314 auto m = msg.at(i);
2315 auto t = m.Type;
2316 if (modeGrouped) {
2317 if (t == SKGDocument::Warning) {
2318 m.Text = i18nc("Warning header", "Warning: %1", m.Text);
2319 } else if (t == SKGDocument::Error) {
2320 m.Text = i18nc("Error header", "Error: %1", m.Text);
2321 } else if (t == SKGDocument::Information) {
2322 m.Text = i18nc("Information header", "Information: %1", m.Text);
2323 } else if (t == SKGDocument::Positive) {
2324 m.Text = i18nc("Done header", "Done: %1", m.Text);
2325 }
2326 }
2327 if (modeGrouped || t == listGroups.at(indexGroup)) {
2328 // Same group
2329 if (!message.isEmpty()) {
2330 message += QStringLiteral("<br>");
2331 }
2332 message += m.Text;
2333 } else {
2334 // Different group
2335 displayMessage(message, listGroups.at(indexGroup));
2336
2337 // Reset message
2338 message = m.Text;
2339
2340 indexGroup++;
2341 }
2342 }
2343
2344 if (nbMessages < 21 || !SKGServices::getEnvVariable(QStringLiteral("SKGTEST")).isEmpty()) {
2345 // Display a simple notification
2346 /*auto notify = new KNotification(KAboutData::applicationData().componentName() % "_info_event" , this);
2347 notify->setText(message);
2348 notify->sendEvent();*/
2349 displayMessage(message, listGroups.at(indexGroup));
2350 } else {
2351 // Too many message, display a warning panel
2352 KMessageBox::information(SKGMainPanel::getMainPanel(), message, i18nc("Noun", "Notification"));
2353 }
2354 }
2355 }
2356 }
2357 }
2358
changeEvent(QEvent * e)2359 void SKGMainPanel::changeEvent(QEvent* e)
2360 {
2361 KXmlGuiWindow::changeEvent(e);
2362 }
2363
statusNormalMessage() const2364 QLabel* SKGMainPanel::statusNormalMessage() const
2365 {
2366 return d->m_kNormalMessage;
2367 }
2368
getMessageWidget(const QString & iMessage,SKGDocument::MessageType iType,const QString & iAction,bool iAutoKillOnClick)2369 KMessageWidget* SKGMainPanel::getMessageWidget(const QString& iMessage, SKGDocument::MessageType iType, const QString& iAction, bool iAutoKillOnClick)
2370 {
2371 KMessageWidget* msg = nullptr;
2372 if (!iMessage.isEmpty()) {
2373 msg = new KMessageWidget(this);
2374 msg->setText(iMessage);
2375 msg->setIcon(SKGServices::fromTheme(iType == SKGDocument::Positive ? QStringLiteral("dialog-positive") :
2376 iType == SKGDocument::Information ? QStringLiteral("dialog-information") :
2377 iType == SKGDocument::Warning ? QStringLiteral("dialog-warning") : QStringLiteral("dialog-error")));
2378 msg->setMessageType(static_cast<KMessageWidget::MessageType>(iType));
2379 if (!iAction.isEmpty()) {
2380 QUrl url(iAction);
2381 if (url.scheme() == QStringLiteral("skg")) {
2382 QAction* action = SKGMainPanel::getMainPanel()->getGlobalAction(url.host(), false);
2383 QAction* act = nullptr;
2384 if (action != nullptr) {
2385 // This is an action
2386 act = new QAction(action->icon(), action->text(), SKGMainPanel::getMainPanel());
2387 } else {
2388 // This is a default action
2389 act = new QAction(SKGServices::fromTheme(QStringLiteral("open")), i18nc("Verb", "Open ..."), SKGMainPanel::getMainPanel());
2390 }
2391
2392 act->setData(iAction);
2393
2394 msg->addAction(act);
2395 connect(act, &QAction::triggered, this, [ = ] { openPage(QUrl(qobject_cast< QAction* >(sender())->data().toString()), true);});
2396 if (iAutoKillOnClick) {
2397 connect(act, &QAction::triggered, msg, &KMessageWidget::deleteLater, Qt::QueuedConnection);
2398 }
2399 }
2400 }
2401 }
2402 return msg;
2403 }
2404
displayMessage(const QString & iMessage,SKGDocument::MessageType iType,const QString & iAction)2405 KMessageWidget* SKGMainPanel::displayMessage(const QString& iMessage, SKGDocument::MessageType iType, const QString& iAction)
2406 {
2407 // Create message widget
2408 KMessageWidget* msg = nullptr;
2409 if (!iMessage.isEmpty()) {
2410 msg = getMessageWidget(iMessage, iType, iAction, true);
2411 QTimer::singleShot(iType == SKGDocument::Positive ? 5000 : iType == SKGDocument::Information ? 10000 : 20000, Qt::CoarseTimer, msg, &KMessageWidget::deleteLater);
2412 msg->show();
2413 d->m_mainLayout->insertWidget(qMax(d->m_mainLayout->indexOf(d->m_mainWidget) - 1, 0), msg);
2414
2415 // Store message
2416 auto msg2 = getMessageWidget(iMessage, iType, iAction, false);
2417 auto* l = qobject_cast< QVBoxLayout* >(d->ui.kMessagesLayout->layout());
2418 if (l != nullptr) {
2419 l->insertWidget(0, msg2);
2420 }
2421 }
2422
2423 // Emit message
2424 // [Event/error]
2425 // [Event/neutral]
2426 // [Event/positive]
2427 auto notification = new KNotification(iType == SKGDocument::Error ? QStringLiteral("error") :
2428 (iType == SKGDocument::Positive ? QStringLiteral("positive") :
2429 (iType == SKGDocument::Warning ? QStringLiteral("negative") :
2430 QStringLiteral("neutral"))));
2431 notification->setWidget(this);
2432 notification->setText(iMessage);
2433 notification->sendEvent();
2434
2435 // Alert
2436 if (iType == SKGDocument::Error || iType == SKGDocument::Warning) {
2437 qApp->alert(this);
2438 }
2439
2440 return msg;
2441 }
2442
displayErrorMessage(const QString & iMessage)2443 KMessageWidget* SKGMainPanel::displayErrorMessage(const QString& iMessage)
2444 {
2445 QString msg = iMessage;
2446 if (msg.isEmpty()) {
2447 auto* act = qobject_cast< QAction* >(sender());
2448 if (act != nullptr) {
2449 msg = act->data().toString();
2450 }
2451 }
2452 return displayMessage(msg, SKGDocument::Error);
2453 }
2454
displayErrorMessage(const SKGError & iError,bool iNotifyIfNoError)2455 KMessageWidget* SKGMainPanel::displayErrorMessage(const SKGError& iError, bool iNotifyIfNoError)
2456 {
2457 return displayErrorMessage(iError, nullptr, iNotifyIfNoError);
2458 }
2459
displayErrorMessage(const SKGError & iError,QAction * iAction,bool iNotifyIfNoError)2460 KMessageWidget* SKGMainPanel::displayErrorMessage(const SKGError& iError, QAction* iAction, bool iNotifyIfNoError)
2461 {
2462 SKGTRACEINFUNC(1)
2463 KMessageWidget* msg = nullptr;
2464 SKGMainPanel* parent = SKGMainPanel::getMainPanel();
2465 if (parent != nullptr) {
2466 if (iError) {
2467 // Get the message
2468 //BUG 423311: Remove history button
2469 msg = parent->displayMessage(iError.getFullMessageWithHistorical(), SKGDocument::Error, iError.getAction());
2470
2471 // Add history action in case of
2472 /*if (iError.getHistoricalSize() != 0) {
2473 auto history = new QAction(i18nc("Noun", "History"), msg);
2474 history->setIcon(SKGServices::fromTheme(QStringLiteral("dialog-information")));
2475 history->setData(iError.getFullMessageWithHistorical());
2476 msg->addAction(history);
2477 connect(history, &QAction::triggered, parent, [ = ] { parent->displayErrorMessage();});
2478 connect(history, &QAction::triggered, msg, &KMessageWidget::deleteLater, Qt::QueuedConnection);
2479 }*/
2480
2481 // Add the additional action
2482 if (iAction != nullptr) {
2483 iAction->setParent(msg);
2484 msg->addAction(iAction);
2485 connect(iAction, &QAction::triggered, msg, &KMessageWidget::deleteLater, Qt::QueuedConnection);
2486 }
2487 } else {
2488 if (iNotifyIfNoError) {
2489 auto notification = new KNotification(QStringLiteral("positive"));
2490 notification->setWidget(parent);
2491 notification->setText(iError.getFullMessage());
2492 notification->sendEvent();
2493 }
2494 // Status bar
2495 QLabel* label = parent->statusNormalMessage();
2496 QString message = iError.getMessage();
2497 if ((label != nullptr) && !message.isEmpty()) {
2498 label->setText(message);
2499 }
2500 }
2501 }
2502 return msg;
2503 }
2504
onCancelCurrentAction()2505 void SKGMainPanel::onCancelCurrentAction()
2506 {
2507 SKGMainPanelPrivate::m_currentActionCanceled = true;
2508 }
2509
onQuitAction()2510 void SKGMainPanel::onQuitAction()
2511 {
2512 // Bug 2777697: To be sure that all page modifications are closed
2513 closeAllPages(true);
2514 // Bug 2777697:
2515
2516 qApp->closeAllWindows();
2517 }
2518
getSaveFileName(const QString & iStartDir,const QString & iFilter,QWidget * iParent,QString * iCodec)2519 QString SKGMainPanel::getSaveFileName(const QString& iStartDir, const QString& iFilter, QWidget* iParent, QString* iCodec)
2520 {
2521 QString fileName;
2522
2523 QString lastCodecUsed = QTextCodec::codecForLocale()->name();
2524 KEncodingFileDialog::Result result = KEncodingFileDialog::getSaveUrlAndEncoding(lastCodecUsed, QUrl(iStartDir), iFilter, iParent);
2525 if (!result.URLs.isEmpty()) {
2526 fileName = result.URLs.at(0).toLocalFile();
2527 }
2528 if (iCodec != nullptr) {
2529 *iCodec = result.encoding;
2530 }
2531 if (fileName.isEmpty()) {
2532 return QLatin1String("");
2533 }
2534 QFile f(fileName);
2535 if (f.exists() && KMessageBox::warningContinueCancel(iParent,
2536 i18nc("Question", "File <b>%1</b> already exists. Do you really want to overwrite it?", fileName),
2537 i18nc("Question", "Warning"),
2538 KGuiItem(i18nc("Verb", "Save"), SKGServices::fromTheme(QStringLiteral("document-save")))) != KMessageBox::Continue) {
2539 return QLatin1String("");
2540 }
2541
2542 return fileName;
2543 }
2544
fillWithDistinctValue(const QList<QWidget * > & iWidgets,SKGDocument * iDoc,const QString & iTable,const QString & iAttribut,const QString & iWhereClause,bool iAddoperators)2545 void SKGMainPanel::fillWithDistinctValue(
2546 const QList<QWidget*>& iWidgets,
2547 SKGDocument* iDoc,
2548 const QString& iTable,
2549 const QString& iAttribut,
2550 const QString& iWhereClause,
2551 bool iAddoperators)
2552 {
2553 SKGTRACEINFUNC(10)
2554
2555 if (iDoc != nullptr) {
2556 {
2557 // Get list
2558 QStringList list;
2559 {
2560 SKGTRACEIN(10, "SKGMainPanel::fillWithDistinctValue-build list " % iTable % " " % iAttribut)
2561 iDoc->getDistinctValues(iTable, iAttribut, iWhereClause, list);
2562 if (!list.isEmpty() && !list.at(0).isEmpty()) {
2563 list.insert(0, QLatin1String(""));
2564 }
2565
2566 // Sorting list
2567 {
2568 SKGTRACEIN(10, "SKGMainPanel::fillWithDistinctValue-build list sorting " % iTable % " " % iAttribut)
2569 // Correction bug 202341 vvv
2570 QCollator c;
2571 std::sort(list.begin(), list.end(), [&](const QString & a, const QString & b) {
2572 return c.compare(a, b) < 0;
2573 });
2574 }
2575
2576 // Add operator
2577 if (iAddoperators) {
2578 list.push_back('=' % i18nc("Key word to modify a string into a field", "capitalize"));
2579 list.push_back('=' % i18nc("Key word to modify a string into a field", "capwords"));
2580 list.push_back('=' % i18nc("Key word to modify a string into a field", "lower"));
2581 list.push_back('=' % i18nc("Key word to modify a string into a field", "trim"));
2582 list.push_back('=' % i18nc("Key word to modify a string into a field", "upper"));
2583 }
2584 }
2585
2586 {
2587 SKGTRACEIN(10, "SKGMainPanel::fillWithDistinctValue-fill " % iTable % " " % iAttribut)
2588 SKGTRACEL(10) << "list.count()=" << list.count() << SKGENDL;
2589 for (auto w : qAsConst(iWidgets)) {
2590 auto comp = new QCompleter(list, w);
2591 if (comp != nullptr) {
2592 comp->setCaseSensitivity(Qt::CaseInsensitive);
2593 comp->setFilterMode(Qt::MatchContains);
2594
2595 // Fill completion
2596 auto* kcmb = qobject_cast<KComboBox*> (w);
2597 if (kcmb != nullptr) {
2598 // Fill combo
2599 kcmb->clear();
2600 kcmb->addItems(list);
2601
2602 if (kcmb->isEditable()) {
2603 kcmb->setCompleter(comp);
2604 }
2605 } else {
2606 auto* kline = qobject_cast<QLineEdit*> (w);
2607 if (kline != nullptr) {
2608 kline->setClearButtonEnabled(true);
2609 kline->setCompleter(comp);
2610 }
2611 }
2612 }
2613 }
2614 }
2615 }
2616 }
2617 }
2618
getMainPanel()2619 SKGMainPanel* SKGMainPanel::getMainPanel()
2620 {
2621 return SKGMainPanelPrivate::m_mainPanel;
2622 }
2623
onZoomChanged()2624 void SKGMainPanel::onZoomChanged()
2625 {
2626 SKGTabPage* toSave = currentPage();
2627 if (toSave != nullptr) {
2628 toSave->setZoomPosition(d->m_zoomSelector->value());
2629 d->m_zoomSelector->setValue(toSave->zoomPosition()); // In case of a limit is reached
2630 }
2631 }
2632
setMainWidget(QWidget * iWidget)2633 void SKGMainPanel::setMainWidget(QWidget* iWidget)
2634 {
2635 if (d->m_mainWidget == nullptr && d->m_mainLayout != nullptr && iWidget != nullptr) {
2636 d->m_mainWidget = iWidget;
2637 d->m_mainLayout->addWidget(d->m_mainWidget);
2638
2639 // Show/hide main widget
2640 d->m_tabWidget->setVisible(d->m_tabWidget->count() != 0);
2641 if (d->m_mainWidget != nullptr) {
2642 d->m_mainWidget->setVisible(!d->m_tabWidget->isVisible());
2643 }
2644 }
2645 }
2646
getTabWidget() const2647 SKGTabWidget* SKGMainPanel::getTabWidget() const
2648 {
2649 return d->m_tabWidget;
2650 }
2651
onClearMessages()2652 void SKGMainPanel::onClearMessages()
2653 {
2654 QLayout* l = d->ui.kMessagesLayout->layout();
2655 if (l != nullptr) {
2656 // Remove all item of the layout
2657 while (l->count() > 1) {
2658 QLayoutItem* child = l->takeAt(0);
2659 if (child != nullptr) {
2660 QWidget* w = child->widget();
2661 delete w;
2662 delete child;
2663 }
2664 }
2665 }
2666 }
2667
onMigrateToSQLCipher()2668 void SKGMainPanel::onMigrateToSQLCipher()
2669 {
2670 SKGError err;
2671 SKGTRACEINFUNCRC(10, err)
2672 if (getDocument()->isFileModified()) {
2673 err = SKGError(ERR_ABORT, i18nc("An information message", "The document must be saved to be migrated."), QStringLiteral("skg://file_save"));
2674 } else {
2675 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
2676
2677 // Set parameters
2678 QString input = getDocument()->getCurrentFileName();
2679 QString tmp = input % ".sqlcipher";
2680 QString output = input % "_migrated.skg";
2681 output = output.replace(QStringLiteral(".skg_migrated"), QStringLiteral("_migrated"));
2682
2683 // Build argument
2684 QStringList arg;
2685 arg.push_back(QStringLiteral("--in"));
2686 arg.push_back(input);
2687 arg.push_back(QStringLiteral("--out"));
2688 arg.push_back(tmp);
2689
2690
2691 QString password = getDocument()->getPassword();
2692 if (!password.isEmpty()) {
2693 arg.push_back(QStringLiteral("--param"));
2694 arg.push_back(QStringLiteral("password"));
2695 arg.push_back(QStringLiteral("--value"));
2696 arg.push_back(password);
2697 password = " --param password --value \"" % password % "\"";
2698 }
2699
2700 // Conversion skg => sqlcipher
2701 QString cmd = "skroogeconvert --in \"" % input % "\" --out \"" % tmp % "\"" % password;
2702 int rc = QProcess::execute(QStringLiteral("skroogeconvert"), arg);
2703 if (rc != 0) {
2704 err.setReturnCode(ERR_FAIL).setMessage(i18nc("Error message", "The following command line failed with code %2:\n'%1'", cmd, rc));
2705 } else {
2706 cmd = "skroogeconvert --in \"" % tmp % "\" --out \"" % output % "\"" % password;
2707 arg[1] = tmp;
2708 arg[3] = output;
2709 rc = QProcess::execute(QStringLiteral("skroogeconvert"), arg);
2710 if (rc != 0) {
2711 err.setReturnCode(ERR_FAIL).setMessage(i18nc("Error message", "The following command line failed with code %2:\n'%1'", cmd, rc));
2712 } else {
2713 getDocument()->sendMessage(i18nc("Positive message", "You document has been migrated.\nHere is the new file:\n%1", output), SKGDocument::Positive, "skg://file_open/?filename=" % output);
2714 notify();
2715 }
2716 }
2717 QFile(tmp).remove();
2718
2719 QApplication::restoreOverrideCursor();
2720 }
2721
2722 // Display error
2723 SKGMainPanel::displayErrorMessage(err);
2724 }
2725
dateToString(QDate iDate)2726 QString SKGMainPanel::dateToString(QDate iDate)
2727 {
2728 switch (skgbasegui_settings::date_format()) {
2729 case 0:
2730 return QLocale().toString(iDate, QLocale::ShortFormat);
2731 case 1:
2732 return QLocale().toString(iDate, QLocale::LongFormat);
2733 case 3:
2734 return KFormat().formatRelativeDate(iDate, QLocale::LongFormat);
2735 case 4:
2736 return iDate.toString(Qt::ISODate);
2737 case 2:
2738 default:
2739 return KFormat().formatRelativeDate(iDate, QLocale::ShortFormat);
2740 }
2741 }
2742