1 /*******************************************************************************************************
2 DkNoMacs.cpp
3 Created on: 21.04.2011
4
5 nomacs is a fast and small image viewer with the capability of synchronizing multiple instances
6
7 Copyright (C) 2011-2013 Markus Diem <markus@nomacs.org>
8 Copyright (C) 2011-2013 Stefan Fiel <stefan@nomacs.org>
9 Copyright (C) 2011-2013 Florian Kleber <florian@nomacs.org>
10
11 This file is part of nomacs.
12
13 nomacs is free software: you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 nomacs is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
25
26 *******************************************************************************************************/
27
28 #include "DkNoMacs.h"
29
30 // my stuff
31 #include "DkNetwork.h"
32 #include "DkViewPort.h"
33 #include "DkWidgets.h"
34 #include "DkDialog.h"
35 #include "DkSettings.h"
36 #include "DkMenu.h"
37 #include "DkMessageBox.h"
38 #include "DkMetaDataWidgets.h"
39 #include "DkManipulatorWidgets.h"
40 #include "DkThumbsWidgets.h"
41 #include "DkBatch.h"
42 #include "DkCentralWidget.h"
43 #include "DkMetaData.h"
44 #include "DkImageContainer.h"
45 #include "DkQuickAccess.h"
46 #include "DkUtils.h"
47 #include "DkControlWidget.h"
48 #include "DkImageLoader.h"
49 #include "DkTimer.h"
50 #include "DkActionManager.h"
51 #include "DkStatusBar.h"
52 #include "DkDockWidgets.h"
53 #include "DkLogWidget.h"
54 #include "DkUpdater.h"
55 #include "DkToolbars.h"
56
57 #ifdef WITH_PLUGINS
58 #include "DkPluginInterface.h"
59 #include "DkPluginManager.h"
60 #endif // WITH_PLUGINS
61
62 #pragma warning(push, 0) // no warnings from includes - begin
63 #include <QBoxLayout>
64 #include <QResizeEvent>
65 #include <QAction>
66 #include <QFileDialog>
67 #include <QMessageBox>
68 #include <QStatusBar>
69 //#include <QPanGesture>
70 #include <QSplashScreen>
71 #include <QErrorMessage>
72 #include <QDesktopServices>
73 #include <QClipboard>
74 #include <QEvent>
75 #include <QSettings>
76 #include <QFileInfo>
77 #include <QTimer>
78 #include <QProcess>
79 #include <QStringBuilder>
80 #include <QDesktopWidget>
81 #include <QProgressDialog>
82 #include <QDrag>
83 #include <QVector2D>
84 #include <qmath.h>
85 #include <QMimeData>
86 #include <QNetworkProxyFactory>
87 #include <QInputDialog>
88 #include <QApplication>
89 #include <QShortcut>
90 #pragma warning(pop) // no warnings from includes - end
91
92 #if defined(Q_OS_WIN) && !defined(SOCK_STREAM)
93 #include <winsock2.h> // needed since libraw 0.16
94 #endif
95
96 #ifdef Q_OS_WIN
97 #include <QWinTaskbarButton>
98 #endif
99
100 #include <assert.h>
101
102 #include <iostream>
103
104 namespace nmc {
105
DkNomacsOSXEventFilter(QObject * parent)106 DkNomacsOSXEventFilter::DkNomacsOSXEventFilter(QObject *parent) : QObject(parent) {
107 }
108
109 /*! Handle QFileOpenEvent for mac here */
eventFilter(QObject * obj,QEvent * event)110 bool DkNomacsOSXEventFilter::eventFilter(QObject *obj, QEvent *event) {
111 if (event->type() == QEvent::FileOpen) {
112 emit loadFile(static_cast<QFileOpenEvent*>(event)->file());
113 return true;
114 }
115 return QObject::eventFilter(obj, event);
116 }
117
DkNoMacs(QWidget * parent,Qt::WindowFlags flags)118 DkNoMacs::DkNoMacs(QWidget *parent, Qt::WindowFlags flags)
119 : QMainWindow(parent, flags) {
120
121 QMainWindow::setWindowTitle("nomacs | Image Lounge");
122 setObjectName("DkNoMacs");
123
124 mMenu = new DkMenuBar(this, -1);
125
126 DkActionManager& am = DkActionManager::instance();
127 am.createActions(this);
128 am.createMenus(mMenu);
129 am.enableImageActions(false);
130
131 mSaveSettings = true;
132
133 mOpenDialog = 0;
134 mSaveDialog = 0;
135 mThumbSaver = 0;
136 mOpacityDialog = 0;
137 mUpdater = 0;
138 mTranslationUpdater = 0;
139 mExportTiffDialog = 0;
140 mUpdateDialog = 0;
141 mProgressDialog = 0;
142 mProgressDialogTranslations = 0;
143 mForceDialog = 0;
144 mTrainDialog = 0;
145 mExplorer = 0;
146 mMetaDataDock = 0;
147 mPrintPreviewDialog = 0;
148 mThumbsDock = 0;
149 mQuickAccess = 0;
150 #ifdef WITH_QUAZIP
151 mArchiveExtractionDialog = 0;
152 #endif
153
154 mOldGeometry = geometry();
155 mOverlaid = false;
156
157 resize(850, 504);
158 setMinimumSize(20, 20);
159
160 //// fun fact
161 //double an = pow(3987, 12);
162 //double bn = pow(4365, 12);
163
164 //qDebug() << "3987 ^ 12 + 4365 ^ 12 = " << pow(an + bn, 1/12.0) << "^ 12";
165 //qDebug() << "Sorry Fermat, but the Simpsons are right.";
166 }
167
~DkNoMacs()168 DkNoMacs::~DkNoMacs() {
169 }
170
init()171 void DkNoMacs::init() {
172
173 // assign icon -> in windows the 32px version
174 QString iconPath = ":/nomacs/img/nomacs.svg";
175 loadStyleSheet();
176
177 QIcon nmcIcon = QIcon(iconPath);
178 setObjectName("DkNoMacs");
179
180 if (!nmcIcon.isNull())
181 setWindowIcon(nmcIcon);
182
183 // shortcuts and actions
184 createActions();
185 createMenu();
186 createContextMenu();
187 createStatusBar();
188
189 //// TODO - just for android register me as a gesture recognizer
190 //grabGesture(Qt::PanGesture);
191 //grabGesture(Qt::PinchGesture);
192 //grabGesture(Qt::SwipeGesture);
193
194 // load the window at the same position as last time
195 readSettings();
196 installEventFilter(this);
197
198 if (DkSettingsManager::param().app().appMode != DkSettings::mode_frameless) {
199 DkToolBarManager::inst().showDefaultToolBar(DkSettingsManager::param().app().showToolBar);
200 showMenuBar(DkSettingsManager::param().app().showMenuBar);
201 DkStatusBarManager::instance().show(DkSettingsManager::param().app().showStatusBar);
202 }
203
204 // connections to the image loader
205 connect(getTabWidget(), SIGNAL(imageUpdatedSignal(QSharedPointer<DkImageContainerT>)), this, SLOT(setWindowTitle(QSharedPointer<DkImageContainerT>)));
206
207 DkActionManager::instance().enableMovieActions(false);
208
209 // clean up nomacs
210 #ifdef Q_OS_WIN
211 if (!nmc::DkSettingsManager::param().global().setupPath.isEmpty() && QApplication::applicationVersion() == nmc::DkSettingsManager::param().global().setupVersion) {
212
213 // ask for exists - otherwise we always try to delete it if the user deleted it
214 if (!QFileInfo(nmc::DkSettingsManager::param().global().setupPath).exists() || QFile::remove(nmc::DkSettingsManager::param().global().setupPath)) {
215 nmc::DkSettingsManager::param().global().setupPath = "";
216 nmc::DkSettingsManager::param().global().setupVersion = "";
217 nmc::DkSettingsManager::param().save();
218 }
219 }
220 #endif // Q_WS_WIN
221 }
222
createStatusBar()223 void DkNoMacs::createStatusBar() {
224
225 setStatusBar(DkStatusBarManager::instance().statusbar());
226 }
227
loadStyleSheet()228 void DkNoMacs::loadStyleSheet() {
229
230 DkThemeManager tm;
231 tm.applyTheme();
232 }
233
createMenu()234 void DkNoMacs::createMenu() {
235
236 setMenuBar(mMenu);
237 DkActionManager& am = DkActionManager::instance();
238 mMenu->addMenu(am.fileMenu());
239 mMenu->addMenu(am.editMenu());
240 mMenu->addMenu(am.manipulatorMenu());
241 mMenu->addMenu(am.viewMenu());
242 mMenu->addMenu(am.panelMenu());
243 mMenu->addMenu(am.toolsMenu());
244
245 // no sync menu in frameless view
246 if (DkSettingsManager::param().app().appMode != DkSettings::mode_frameless)
247 mMenu->addMenu(am.syncMenu());
248
249 #ifdef WITH_PLUGINS
250 // plugin menu
251 mPluginsMenu = mMenu->addMenu(tr("Pl&ugins"));
252 am.pluginActionManager()->setMenu(mPluginsMenu);
253 #endif // WITH_PLUGINS
254
255 mMenu->addMenu(am.helpMenu());
256 }
257
createContextMenu()258 void DkNoMacs::createContextMenu() {
259 }
260
createActions()261 void DkNoMacs::createActions() {
262
263 DkActionManager& am = DkActionManager::instance();
264
265 connect(am.action(DkActionManager::menu_file_open), SIGNAL(triggered()), this, SLOT(openFile()));
266 connect(am.action(DkActionManager::menu_file_open_dir), SIGNAL(triggered()), this, SLOT(openDir()));
267 connect(am.action(DkActionManager::menu_file_quick_launch), SIGNAL(triggered()), this, SLOT(openQuickLaunch()));
268 connect(am.action(DkActionManager::menu_file_open_list), SIGNAL(triggered()), this, SLOT(openFileList()));
269 connect(am.action(DkActionManager::menu_file_save_list), SIGNAL(triggered()), this, SLOT(saveFileList()));
270 connect(am.action(DkActionManager::menu_file_rename), SIGNAL(triggered()), this, SLOT(renameFile()));
271 connect(am.action(DkActionManager::menu_file_goto), SIGNAL(triggered()), this, SLOT(goTo()));
272 connect(am.action(DkActionManager::menu_file_show_recent), SIGNAL(triggered(bool)), centralWidget(), SLOT(showRecentFiles(bool)));
273 connect(am.action(DkActionManager::menu_file_new_instance), SIGNAL(triggered()), this, SLOT(newInstance()));
274 connect(am.action(DkActionManager::menu_file_private_instance), SIGNAL(triggered()), this, SLOT(newInstance()));
275 connect(am.action(DkActionManager::menu_file_find), SIGNAL(triggered()), this, SLOT(find()));
276 connect(am.action(DkActionManager::menu_file_recursive), SIGNAL(triggered(bool)), this, SLOT(setRecursiveScan(bool)));
277 connect(am.action(DkActionManager::menu_file_exit), SIGNAL(triggered()), this, SLOT(close()));
278
279 connect(am.action(DkActionManager::menu_sort_filename), SIGNAL(triggered(bool)), this, SLOT(changeSorting(bool)));
280 connect(am.action(DkActionManager::menu_sort_date_created), SIGNAL(triggered(bool)), this, SLOT(changeSorting(bool)));
281 connect(am.action(DkActionManager::menu_sort_date_modified), SIGNAL(triggered(bool)), this, SLOT(changeSorting(bool)));
282 connect(am.action(DkActionManager::menu_sort_random), SIGNAL(triggered(bool)), this, SLOT(changeSorting(bool)));
283 connect(am.action(DkActionManager::menu_sort_ascending), SIGNAL(triggered(bool)), this, SLOT(changeSorting(bool)));
284 connect(am.action(DkActionManager::menu_sort_descending), SIGNAL(triggered(bool)), this, SLOT(changeSorting(bool)));
285
286 connect(am.action(DkActionManager::menu_panel_menu), SIGNAL(toggled(bool)), this, SLOT(showMenuBar(bool)));
287 connect(am.action(DkActionManager::menu_panel_explorer), SIGNAL(toggled(bool)), this, SLOT(showExplorer(bool)));
288 connect(am.action(DkActionManager::menu_panel_metadata_dock), SIGNAL(toggled(bool)), this, SLOT(showMetaDataDock(bool)));
289 connect(am.action(DkActionManager::menu_edit_image), SIGNAL(toggled(bool)), this, SLOT(showEditDock(bool)));
290 connect(am.action(DkActionManager::menu_panel_history), SIGNAL(toggled(bool)), this, SLOT(showHistoryDock(bool)));
291 connect(am.action(DkActionManager::menu_panel_log), SIGNAL(toggled(bool)), this, SLOT(showLogDock(bool)));
292 connect(am.action(DkActionManager::menu_panel_preview), SIGNAL(toggled(bool)), this, SLOT(showThumbsDock(bool)));
293 connect(am.action(DkActionManager::menu_panel_toggle), SIGNAL(toggled(bool)), this, SLOT(toggleDocks(bool)));
294
295 connect(am.action(DkActionManager::menu_view_fit_frame), SIGNAL(triggered()), this, SLOT(fitFrame()));
296 connect(am.action(DkActionManager::menu_view_fullscreen), SIGNAL(triggered()), this, SLOT(toggleFullScreen()));
297 connect(am.action(DkActionManager::menu_view_frameless), SIGNAL(toggled(bool)), this, SLOT(restartFrameless(bool)));
298 connect(am.action(DkActionManager::menu_panel_transfertoolbar), SIGNAL(toggled(bool)), this, SLOT(restartWithPseudoColor(bool)));
299 connect(am.action(DkActionManager::menu_view_opacity_change), SIGNAL(triggered()), this, SLOT(showOpacityDialog()));
300 connect(am.action(DkActionManager::menu_view_opacity_up), SIGNAL(triggered()), this, SLOT(opacityUp()));
301 connect(am.action(DkActionManager::menu_view_opacity_down), SIGNAL(triggered()), this, SLOT(opacityDown()));
302 connect(am.action(DkActionManager::menu_view_opacity_an), SIGNAL(triggered()), this, SLOT(animateChangeOpacity()));
303 connect(am.action(DkActionManager::menu_view_lock_window), SIGNAL(triggered(bool)), this, SLOT(lockWindow(bool)));
304
305 connect(am.action(DkActionManager::menu_tools_thumbs), SIGNAL(triggered()), this, SLOT(computeThumbsBatch()));
306 connect(am.action(DkActionManager::menu_tools_filter), SIGNAL(triggered(bool)), this, SLOT(find(bool)));
307 connect(am.action(DkActionManager::menu_tools_export_tiff), SIGNAL(triggered()), this, SLOT(exportTiff()));
308 connect(am.action(DkActionManager::menu_tools_extract_archive), SIGNAL(triggered()), this, SLOT(extractImagesFromArchive()));
309 connect(am.action(DkActionManager::menu_tools_train_format), SIGNAL(triggered()), this, SLOT(trainFormat()));
310
311 connect(am.action(DkActionManager::sc_test_rec), SIGNAL(triggered()), this, SLOT(loadRecursion()));
312 connect(am.action(DkActionManager::sc_test_pong), SIGNAL(triggered()), this, SLOT(startPong()));
313
314 connect(am.action(DkActionManager::menu_plugin_manager), SIGNAL(triggered()), this, SLOT(openPluginManager()));
315
316 // help menu
317 connect(am.action(DkActionManager::menu_help_about), SIGNAL(triggered()), this, SLOT(aboutDialog()));
318 connect(am.action(DkActionManager::menu_help_documentation), SIGNAL(triggered()), this, SLOT(openDocumentation()));
319 connect(am.action(DkActionManager::menu_help_bug), SIGNAL(triggered()), this, SLOT(bugReport()));
320 connect(am.action(DkActionManager::menu_help_update), SIGNAL(triggered()), this, SLOT(checkForUpdate()));
321 connect(am.action(DkActionManager::menu_help_update_translation), SIGNAL(triggered()), this, SLOT(updateTranslations()));
322
323 connect(am.appManager(), SIGNAL(openFileSignal(QAction*)), this, SLOT(openFileWith(QAction*)));
324 }
325
clearFileHistory()326 void DkNoMacs::clearFileHistory() {
327 DkSettingsManager::param().global().recentFiles.clear();
328 }
329
clearFolderHistory()330 void DkNoMacs::clearFolderHistory() {
331 DkSettingsManager::param().global().recentFolders.clear();
332 }
333
getTabWidget() const334 DkCentralWidget* DkNoMacs::getTabWidget() const {
335
336 DkCentralWidget* cw = dynamic_cast<DkCentralWidget*>(centralWidget());
337 return cw;
338 }
339
340 // Qt how-to
closeEvent(QCloseEvent * event)341 void DkNoMacs::closeEvent(QCloseEvent *event) {
342
343 DkCentralWidget* cw = static_cast<DkCentralWidget*>(centralWidget());
344
345 if (cw && cw->getTabs().size() > 1) {
346
347 DkMessageBox* msg = new DkMessageBox(QMessageBox::Question, tr("Quit nomacs"),
348 tr("Do you want nomacs to save your tabs?"),
349 (QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel), this);
350 msg->setButtonText(QMessageBox::Yes, tr("&Save and Quit"));
351 msg->setButtonText(QMessageBox::No, tr("&Quit"));
352 msg->setObjectName("saveTabsDialog");
353
354 int answer = msg->exec();
355
356 if (answer == QMessageBox::Cancel || answer == QMessageBox::NoButton) { // User canceled - do not close
357 event->ignore();
358 return;
359 }
360
361 cw->saveSettings(answer == QMessageBox::Yes);
362 }
363 else
364 cw->saveSettings(false);
365
366 if (!getTabWidget()->requestClose()) {
367 // do not close if the user hit cancel in the save changes dialog
368 event->ignore();
369 return;
370 }
371
372 emit closeSignal();
373 qDebug() << "saving window settings...";
374 setVisible(false);
375 //showNormal();
376
377 if (mSaveSettings) {
378 DefaultSettings settings;
379 settings.setValue("geometryNomacs", geometry());
380 settings.setValue("geometry", saveGeometry());
381 settings.setValue("windowState", saveState());
382
383 if (mExplorer)
384 settings.setValue(mExplorer->objectName(), QMainWindow::dockWidgetArea(mExplorer));
385 if (mMetaDataDock)
386 settings.setValue(mMetaDataDock->objectName(), QMainWindow::dockWidgetArea(mMetaDataDock));
387 if (mEditDock)
388 settings.setValue(mEditDock->objectName(), QMainWindow::dockWidgetArea(mEditDock));
389 if (mThumbsDock)
390 settings.setValue(mThumbsDock->objectName(), QMainWindow::dockWidgetArea(mThumbsDock));
391
392 nmc::DkSettingsManager::param().save();
393 }
394
395 QMainWindow::closeEvent(event);
396 }
397
resizeEvent(QResizeEvent * event)398 void DkNoMacs::resizeEvent(QResizeEvent *event) {
399
400 QMainWindow::resizeEvent(event);
401
402 if (!mOverlaid)
403 mOldGeometry = geometry();
404 else if (windowOpacity() < 1.0f) {
405 animateChangeOpacity();
406 mOverlaid = false;
407 }
408
409 }
410
moveEvent(QMoveEvent * event)411 void DkNoMacs::moveEvent(QMoveEvent *event) {
412
413 QMainWindow::moveEvent(event);
414
415 if (!mOverlaid)
416 mOldGeometry = geometry();
417 else if (windowOpacity() < 1.0f) {
418 animateChangeOpacity();
419 mOverlaid = false;
420 }
421 }
422
mouseDoubleClickEvent(QMouseEvent * event)423 void DkNoMacs::mouseDoubleClickEvent(QMouseEvent* event) {
424
425 if (event->button() != Qt::LeftButton || (getTabWidget() && !getTabWidget()->getCurrentImage()))
426 return;
427
428 if (isFullScreen())
429 exitFullScreen();
430 else if (DkSettingsManager::instance().param().global().doubleClickForFullscreen)
431 enterFullScreen();
432
433 //QMainWindow::mouseDoubleClickEvent(event);
434 }
435
436
mousePressEvent(QMouseEvent * event)437 void DkNoMacs::mousePressEvent(QMouseEvent* event) {
438
439 mMousePos = event->pos();
440
441 QMainWindow::mousePressEvent(event);
442 }
443
mouseReleaseEvent(QMouseEvent * event)444 void DkNoMacs::mouseReleaseEvent(QMouseEvent *event) {
445
446 QMainWindow::mouseReleaseEvent(event);
447 }
448
contextMenuEvent(QContextMenuEvent * event)449 void DkNoMacs::contextMenuEvent(QContextMenuEvent *event) {
450
451 QMainWindow::contextMenuEvent(event);
452
453 if (!event->isAccepted())
454 DkActionManager::instance().contextMenu()->exec(event->globalPos());
455 }
456
mouseMoveEvent(QMouseEvent * event)457 void DkNoMacs::mouseMoveEvent(QMouseEvent *event) {
458
459 QMainWindow::mouseMoveEvent(event);
460 }
461
462 //bool DkNoMacs::gestureEvent(QGestureEvent *event) {
463 //
464 // DkViewPort* vp = viewport();
465 //
466 // if (QGesture *swipe = event->gesture(Qt::SwipeGesture)) {
467 // QSwipeGesture* swipeG = static_cast<QSwipeGesture *>(swipe);
468 //
469 // qDebug() << "swipe detected\n";
470 // if (vp) {
471 //
472 // if (swipeG->horizontalDirection() == QSwipeGesture::Left)
473 // vp->loadNextFileFast();
474 // else if (swipeG->horizontalDirection() == QSwipeGesture::Right)
475 // vp->loadPrevFileFast();
476 //
477 // // TODO: recognize some other gestures please
478 // }
479 //
480 // }
481 // else if (QGesture *pan = event->gesture(Qt::PanGesture)) {
482 //
483 // QPanGesture* panG = static_cast<QPanGesture *>(pan);
484 //
485 // qDebug() << "you're speedy: " << panG->acceleration();
486 //
487 // QPointF delta = panG->delta();
488 //
489 // if (panG->acceleration() > 10 && delta.x() && fabs(delta.y()/delta.x()) < 0.2) {
490 //
491 // if (delta.x() < 0)
492 // vp->loadNextFileFast();
493 // else
494 // vp->loadPrevFileFast();
495 // }
496 //
497 // if (vp)
498 // vp->moveView(panG->delta());
499 // }
500 // else if (QGesture *pinch = event->gesture(Qt::PinchGesture)) {
501 //
502 // QPinchGesture* pinchG = static_cast<QPinchGesture *>(pinch);
503 //
504 // //if (pinchG->changeFlags() == QPinchGesture::ChangeFlag.ScaleFactorChanged) {
505 // qDebug() << "scale Factor: " << pinchG->scaleFactor();
506 // if (pinchG->scaleFactor() != 0 && vp) {
507 // vp->zoom((float)pinchG->scaleFactor());
508 // }
509 // else if (pinchG->rotationAngle() != 0 && vp) {
510 //
511 // float angle = (float)pinchG->rotationAngle();
512 // qDebug() << "angle: " << angle;
513 // //vp->rotate(angle);
514 // }
515 // }
516 //
517 // qDebug() << "gesture event (NoMacs)";
518 //
519 // // pinchTriggered(static_cast<QPinchGesture *>(pinch));
520 // return true;
521 //}
522
readSettings()523 void DkNoMacs::readSettings() {
524
525 DefaultSettings settings;
526
527 #ifdef Q_WS_WIN
528 // fixes #392 - starting maximized on 2nd screen - tested on win8 only
529 QRect r = settings.value("geometryNomacs", QRect()).toRect();
530
531 if (r.width() && r.height()) // do not set the geometry if nomacs is loaded the first time
532 setGeometry(r);
533 #endif
534
535 restoreGeometry(settings.value("geometry").toByteArray());
536 restoreState(settings.value("windowState").toByteArray());
537
538 // restore state makes the toolbar visible - so hide it again...
539 if (DkSettingsManager::param().app().appMode == DkSettings::mode_frameless) {
540 DkToolBarManager::inst().showDefaultToolBar(false);
541 DkStatusBarManager::instance().show(false);
542 }
543 }
544
toggleFullScreen()545 void DkNoMacs::toggleFullScreen() {
546
547 if (isFullScreen())
548 exitFullScreen();
549 else
550 enterFullScreen();
551 }
552
enterFullScreen()553 void DkNoMacs::enterFullScreen() {
554
555 DkSettingsManager::param().app().currentAppMode += qFloor(DkSettings::mode_end*0.5f);
556 if (DkSettingsManager::param().app().currentAppMode < 0) {
557 qDebug() << "illegal state: " << DkSettingsManager::param().app().currentAppMode;
558 DkSettingsManager::param().app().currentAppMode = DkSettings::mode_default;
559 }
560
561 menuBar()->hide();
562 DkToolBarManager::inst().show(false);
563 DkStatusBarManager::instance().statusbar()->hide();
564 getTabWidget()->showTabs(false);
565
566 restoreDocks();
567
568 // here is an issue with windows that I can't quite fix:
569 // if we send nomacs to fullscreen from an attached window (i.e. split window)
570 setWindowState(windowState() ^ Qt::WindowFullScreen);
571
572 if (getTabWidget()->getViewPort())
573 getTabWidget()->getViewPort()->setFullScreen(true);
574
575 }
576
exitFullScreen()577 void DkNoMacs::exitFullScreen() {
578
579 if (isFullScreen()) {
580 DkSettingsManager::param().app().currentAppMode -= qFloor(DkSettings::mode_end*0.5f);
581 if (DkSettingsManager::param().app().currentAppMode < 0) {
582 qDebug() << "illegal state: " << DkSettingsManager::param().app().currentAppMode;
583 DkSettingsManager::param().app().currentAppMode = DkSettings::mode_default;
584 }
585
586 if (DkSettingsManager::param().app().showMenuBar) mMenu->show();
587 if (DkSettingsManager::param().app().showStatusBar) DkStatusBarManager::instance().statusbar()->show();
588
589 DkToolBarManager::inst().restore();
590 restoreDocks();
591 setWindowState(windowState() ^ Qt::WindowFullScreen);
592
593
594 if (getTabWidget())
595 getTabWidget()->showTabs(true);
596
597 update(); // if no resize is triggered, the viewport won't change its color
598 }
599
600 if (getTabWidget()->getViewPort())
601 getTabWidget()->getViewPort()->setFullScreen(false);
602 }
603
toggleDocks(bool hide)604 void DkNoMacs::toggleDocks(bool hide) {
605
606 if (hide) {
607 showExplorer(false, false);
608 showMetaDataDock(false, false);
609 showEditDock(false, false);
610 showHistoryDock(false, false);
611 showLogDock(false, false);
612 DkToolBarManager::inst().show(false, false);
613 DkStatusBarManager::instance().show(false, false);
614 }
615 else {
616 restoreDocks();
617 DkToolBarManager::inst().restore();
618 DkStatusBarManager::instance().show(DkSettingsManager::param().app().showStatusBar, false);
619 }
620 }
621
restoreDocks()622 void DkNoMacs::restoreDocks() {
623
624 showExplorer(DkDockWidget::testDisplaySettings(DkSettingsManager::param().app().showExplorer), false);
625 showMetaDataDock(DkDockWidget::testDisplaySettings(DkSettingsManager::param().app().showMetaDataDock), false);
626 showEditDock(DkDockWidget::testDisplaySettings(DkSettingsManager::param().app().showEditDock), false);
627 showHistoryDock(DkDockWidget::testDisplaySettings(DkSettingsManager::param().app().showHistoryDock), false);
628 showLogDock(DkDockWidget::testDisplaySettings(DkSettingsManager::param().app().showLogDock), false);
629 }
630
restartFrameless(bool)631 void DkNoMacs::restartFrameless(bool) {
632
633 QString exe = QApplication::applicationFilePath();
634 QStringList args;
635
636 if (objectName() != "DkNoMacsFrameless")
637 args << "-m" << "frameless";
638 else
639 args << "-m" << "default";
640
641 if (getTabWidget()->getCurrentImage())
642 args.append(getTabWidget()->getCurrentImage()->filePath());
643
644 nmc::DkSettingsManager::param().save();
645
646 bool started = mProcess.startDetached(exe, args);
647
648 // close me if the new instance started
649 if (started)
650 close();
651
652 qDebug() << "frameless arguments: " << args;
653 }
654
showRecentFilesOnStartUp()655 void DkNoMacs::showRecentFilesOnStartUp() {
656
657 QTimer::singleShot(100, getTabWidget(), SLOT(showRecentFiles()));
658 }
659
startPong() const660 void DkNoMacs::startPong() const {
661
662 QString exe = QApplication::applicationFilePath();
663 QStringList args;
664
665 args.append("--pong");
666
667 bool started = mProcess.startDetached(exe, args);
668 qDebug() << "pong started: " << started;
669 }
670
fitFrame()671 void DkNoMacs::fitFrame() {
672
673 if (!getTabWidget()->getViewPort())
674 return;
675
676 auto vp = getTabWidget()->getViewPort();
677
678 QRectF viewRect = vp->getImageViewRect();
679 QRectF vpRect = vp->geometry();
680 QRectF nmRect = frameGeometry();
681 QSize frDiff = frameGeometry().size()-geometry().size();
682
683 // compute new size
684 QPointF c = nmRect.center();
685 nmRect.setSize(nmRect.size() + viewRect.size() - vpRect.size());
686 nmRect.moveCenter(c);
687
688 // still fits on screen?
689 QDesktopWidget* dw = QApplication::desktop();
690 QRect screenRect = dw->availableGeometry(this);
691 QRect newGeometry = screenRect.intersected(nmRect.toRect());
692
693 // correct frame
694 newGeometry.setSize(newGeometry.size()-frDiff);
695 newGeometry.moveTopLeft(newGeometry.topLeft() - frameGeometry().topLeft()+geometry().topLeft());
696
697 setGeometry(newGeometry);
698
699 // reset viewport if we did not clip -> compensates round-off errors
700 if (screenRect.contains(nmRect.toRect()))
701 vp->resetView();
702
703 }
704
setRecursiveScan(bool recursive)705 void DkNoMacs::setRecursiveScan(bool recursive) {
706
707 DkSettingsManager::param().global().scanSubFolders = recursive;
708
709 QSharedPointer<DkImageLoader> loader = getTabWidget()->getCurrentImageLoader();
710
711 if (!loader)
712 return;
713
714 if (recursive)
715 getTabWidget()->setInfo(tr("Recursive Folder Scan is Now Enabled"));
716 else
717 getTabWidget()->setInfo(tr("Recursive Folder Scan is Now Disabled"));
718
719 loader->updateSubFolders(loader->getDirPath());
720 }
721
showOpacityDialog()722 void DkNoMacs::showOpacityDialog() {
723
724 if (!mOpacityDialog) {
725 mOpacityDialog = new DkOpacityDialog(this);
726 mOpacityDialog->setWindowTitle(tr("Change Opacity"));
727 }
728
729 if (mOpacityDialog->exec())
730 setWindowOpacity(mOpacityDialog->value()/100.0f);
731 }
732
opacityDown()733 void DkNoMacs::opacityDown() {
734
735 changeOpacity(-0.3f);
736 }
737
opacityUp()738 void DkNoMacs::opacityUp() {
739
740 changeOpacity(0.3f);
741 }
742
changeOpacity(float change)743 void DkNoMacs::changeOpacity(float change) {
744
745 float newO = (float)windowOpacity() + change;
746 if (newO > 1) newO = 1.0f;
747 if (newO < 0.1) newO = 0.1f;
748 setWindowOpacity(newO);
749 }
750
animateOpacityDown()751 void DkNoMacs::animateOpacityDown() {
752
753 float newO = (float)windowOpacity() - 0.03f;
754
755 if (newO < 0.3f) {
756 setWindowOpacity(0.3f);
757 return;
758 }
759
760 setWindowOpacity(newO);
761 QTimer::singleShot(20, this, SLOT(animateOpacityDown()));
762 }
763
animateOpacityUp()764 void DkNoMacs::animateOpacityUp() {
765
766 float newO = (float)windowOpacity() + 0.03f;
767
768 if (newO > 1.0f) {
769 setWindowOpacity(1.0f);
770 return;
771 }
772
773 setWindowOpacity(newO);
774 QTimer::singleShot(20, this, SLOT(animateOpacityUp()));
775 }
776
777 // >DIR: diem - why can't we put it in mViewport?
animateChangeOpacity()778 void DkNoMacs::animateChangeOpacity() {
779
780 float newO = (float)windowOpacity();
781
782 if (newO >= 1.0f)
783 animateOpacityDown();
784 else
785 animateOpacityUp();
786 }
787
lockWindow(bool lock)788 void DkNoMacs::lockWindow(bool lock) {
789
790
791 #ifdef Q_OS_WIN
792
793 qDebug() << "locking: " << lock;
794
795 if (lock) {
796 //setAttribute(Qt::WA_TransparentForMouseEvents);
797 HWND hwnd = (HWND) winId(); // get handle of the widget
798 LONG styles = GetWindowLong(hwnd, GWL_EXSTYLE);
799 SetWindowLong(hwnd, GWL_EXSTYLE, styles | WS_EX_TRANSPARENT);
800 SetWindowPos((HWND)this->winId(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
801
802 auto keyStr = DkActionManager::instance().action(DkActionManager::menu_view_lock_window)->shortcut().toString();
803 getTabWidget()->setInfo(tr("Window Locked\nTo unlock: gain focus (ALT+Tab),\nthen press %1")
804 .arg(keyStr));
805 }
806 else if (lock && windowOpacity() == 1.0f) {
807 getTabWidget()->setInfo(tr("You should first reduce opacity\n before working through the window."));
808 DkActionManager::instance().action(DkActionManager::menu_view_lock_window)->setChecked(false);
809 }
810 else {
811 qDebug() << "deactivating...";
812 HWND hwnd = (HWND) winId(); // get handle of the widget
813 LONG styles = GetWindowLong(hwnd, GWL_EXSTYLE);
814 SetWindowLong(hwnd, GWL_EXSTYLE, styles & ~WS_EX_TRANSPARENT);
815
816 SetWindowPos((HWND)this->winId(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
817 }
818 #else
819 // TODO: find corresponding command for linux etc
820
821 //setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
822 //show();
823 #endif
824 }
825
newClientConnected(bool connected)826 void DkNoMacs::newClientConnected(bool connected) {
827
828 mOverlaid = false;
829 // add methods if clients are connected
830
831 DkActionManager& am = DkActionManager::instance();
832 am.action(DkActionManager::menu_sync_view)->setEnabled(connected);
833 am.action(DkActionManager::menu_sync_pos)->setEnabled(connected);
834 am.action(DkActionManager::menu_sync_arrange)->setEnabled(connected);
835
836 }
837
tcpSetWindowRect(QRect newRect,bool opacity,bool overlaid)838 void DkNoMacs::tcpSetWindowRect(QRect newRect, bool opacity, bool overlaid) {
839
840 this->mOverlaid = overlaid;
841
842 // we are currently overlaid...
843 if (!overlaid) {
844
845 setGeometry(mOldGeometry);
846 if (opacity)
847 animateOpacityUp();
848 mOldGeometry = geometry();
849 }
850 else {
851
852 #ifdef Q_OS_WIN
853 showMinimized();
854 setWindowState(Qt::WindowActive);
855 #else
856 Qt::WindowFlags flags = windowFlags();
857 setWindowFlags(Qt::WindowStaysOnTopHint); // we need this to 'generally' (for all OSs) bring the window to front
858 setWindowFlags(flags); // reset flags
859 showNormal();
860 #endif
861
862 mOldGeometry = geometry();
863
864 this->move(newRect.topLeft());
865 this->resize(newRect.size() - (frameGeometry().size() - geometry().size()));
866
867 //setGeometry(newRect);
868 if (opacity)
869 animateOpacityDown();
870
871 //this->setActiveWindow();
872 }
873 }
874
tcpSendWindowRect()875 void DkNoMacs::tcpSendWindowRect() {
876
877 mOverlaid = !mOverlaid;
878
879 qDebug() << "overlaying";
880 // change my geometry
881 tcpSetWindowRect(this->frameGeometry(), !mOverlaid, mOverlaid);
882
883
884 auto cm = DkSyncManager::inst().client();
885 if (cm)
886 cm->sendPosition(frameGeometry(), mOverlaid);
887 }
888
tcpSendArrange()889 void DkNoMacs::tcpSendArrange() {
890
891 mOverlaid = !mOverlaid;
892 emit sendArrangeSignal(mOverlaid);
893 }
894
showExplorer(bool show,bool saveSettings)895 void DkNoMacs::showExplorer(bool show, bool saveSettings) {
896
897 if (!show && !mExplorer)
898 return;
899
900 if (!mExplorer) {
901
902 // get last location
903 mExplorer = new DkBrowseExplorer(tr("File Explorer"));
904 mExplorer->registerAction(DkActionManager::instance().action(DkActionManager::menu_panel_explorer));
905 mExplorer->setDisplaySettings(&DkSettingsManager::param().app().showExplorer);
906 addDockWidget(mExplorer->getDockLocationSettings(Qt::LeftDockWidgetArea), mExplorer);
907
908 connect(mExplorer, SIGNAL(openFile(const QString&)), getTabWidget(), SLOT(loadFile(const QString&)));
909 connect(mExplorer, SIGNAL(openDir(const QString&)), getTabWidget(), SLOT(loadDirToTab(const QString&)));
910 connect(getTabWidget(), SIGNAL(imageUpdatedSignal(QSharedPointer<DkImageContainerT>)), mExplorer, SLOT(setCurrentImage(QSharedPointer<DkImageContainerT>)));
911 }
912
913 mExplorer->setVisible(show, saveSettings);
914
915 if (getTabWidget()->getCurrentImage() && QFileInfo(getTabWidget()->getCurrentFilePath()).exists()) {
916 mExplorer->setCurrentPath(getTabWidget()->getCurrentFilePath());
917 }
918 else {
919 QStringList folders = DkSettingsManager::param().global().recentFiles;
920
921 if (folders.size() > 0)
922 mExplorer->setCurrentPath(folders[0]);
923 }
924 }
925
showMetaDataDock(bool show,bool saveSettings)926 void DkNoMacs::showMetaDataDock(bool show, bool saveSettings) {
927
928 if (!show && !mMetaDataDock)
929 return;
930
931 if (!mMetaDataDock) {
932
933 mMetaDataDock = new DkMetaDataDock(tr("Meta Data Info"), this);
934 mMetaDataDock->registerAction(DkActionManager::instance().action(DkActionManager::menu_panel_metadata_dock));
935 mMetaDataDock->setDisplaySettings(&DkSettingsManager::param().app().showMetaDataDock);
936 addDockWidget(mMetaDataDock->getDockLocationSettings(Qt::RightDockWidgetArea), mMetaDataDock);
937
938 connect(getTabWidget(), SIGNAL(imageUpdatedSignal(QSharedPointer<DkImageContainerT>)), mMetaDataDock, SLOT(setImage(QSharedPointer<DkImageContainerT>)));
939 }
940
941 mMetaDataDock->setVisible(show, saveSettings);
942
943 if (getTabWidget()->getCurrentImage())
944 mMetaDataDock->setImage(getTabWidget()->getCurrentImage());
945 }
946
showEditDock(bool show,bool saveSettings)947 void DkNoMacs::showEditDock(bool show, bool saveSettings) {
948
949 if (!show && !mEditDock)
950 return;
951
952 if (!mEditDock) {
953
954 mEditDock = new DkEditDock(tr("Edit Image"), this);
955 mEditDock->registerAction(DkActionManager::instance().action(DkActionManager::menu_edit_image));
956 mEditDock->setDisplaySettings(&DkSettingsManager::param().app().showEditDock);
957 addDockWidget(mEditDock->getDockLocationSettings(Qt::RightDockWidgetArea), mEditDock);
958
959 connect(getTabWidget(), SIGNAL(imageUpdatedSignal(QSharedPointer<DkImageContainerT>)), mEditDock, SLOT(setImage(QSharedPointer<DkImageContainerT>)));
960 }
961
962 mEditDock->setVisible(show, saveSettings);
963
964 if (getTabWidget()->getCurrentImage())
965 mEditDock->setImage(getTabWidget()->getCurrentImage());
966 }
967
showHistoryDock(bool show,bool saveSettings)968 void DkNoMacs::showHistoryDock(bool show, bool saveSettings) {
969
970 if (!show && !mHistoryDock)
971 return;
972
973 if (!mHistoryDock) {
974
975 mHistoryDock = new DkHistoryDock(tr("History"), this);
976 mHistoryDock->registerAction(DkActionManager::instance().action(DkActionManager::menu_panel_history));
977 mHistoryDock->setDisplaySettings(&DkSettingsManager::param().app().showHistoryDock);
978 addDockWidget(mHistoryDock->getDockLocationSettings(Qt::RightDockWidgetArea), mHistoryDock);
979
980 connect(getTabWidget(), SIGNAL(imageUpdatedSignal(QSharedPointer<DkImageContainerT>)), mHistoryDock, SLOT(updateImage(QSharedPointer<DkImageContainerT>)));
981 }
982
983 mHistoryDock->setVisible(show, saveSettings);
984
985 if (show && getTabWidget()->getCurrentImage())
986 mHistoryDock->updateImage(getTabWidget()->getCurrentImage());
987 }
988
showLogDock(bool show,bool saveSettings)989 void DkNoMacs::showLogDock(bool show, bool saveSettings) {
990
991 if (!show && !mLogDock)
992 return;
993
994 if (!mLogDock) {
995
996 // get last location
997 mLogDock = new DkLogDock(tr("Console"), this);
998 mLogDock->registerAction(DkActionManager::instance().action(DkActionManager::menu_panel_log));
999 mLogDock->setDisplaySettings(&DkSettingsManager::param().app().showLogDock);
1000 addDockWidget(mLogDock->getDockLocationSettings(Qt::LeftDockWidgetArea), mLogDock);
1001 }
1002
1003 mLogDock->setVisible(show, saveSettings);
1004 qInfoClean() << QStringLiteral("Say \"Hi\" to ") << QApplication::applicationName() << " " << QApplication::applicationVersion();
1005
1006 }
1007
showThumbsDock(bool show)1008 void DkNoMacs::showThumbsDock(bool show) {
1009
1010 if (!show && !mThumbsDock)
1011 return;
1012
1013 // nothing todo here
1014 if (mThumbsDock && mThumbsDock->isVisible() && show)
1015 return;
1016
1017 if (!getTabWidget()->getViewPort())
1018 return;
1019
1020 auto vp = getTabWidget()->getViewPort();
1021 int winPos = vp->getController()->getFilePreview()->getWindowPosition();
1022
1023 if (winPos != DkFilePreview::cm_pos_dock_hor && winPos != DkFilePreview::cm_pos_dock_ver) {
1024 if (mThumbsDock) {
1025
1026 //DkSettingsManager::param().display().thumbDockSize = qMin(thumbsDock->width(), thumbsDock->height());
1027 DefaultSettings settings;
1028 settings.setValue("thumbsDockLocation", QMainWindow::dockWidgetArea(mThumbsDock));
1029
1030 mThumbsDock->hide();
1031 mThumbsDock->setWidget(0);
1032 mThumbsDock->deleteLater();
1033 mThumbsDock = 0;
1034 }
1035 return;
1036 }
1037
1038 if (!mThumbsDock) {
1039 mThumbsDock = new DkDockWidget(tr("Thumbnails"), this);
1040 mThumbsDock->registerAction(DkActionManager::instance().action(DkActionManager::menu_panel_preview));
1041 mThumbsDock->setDisplaySettings(&DkSettingsManager::param().app().showFilePreview);
1042 mThumbsDock->setWidget(vp->getController()->getFilePreview());
1043 addDockWidget(mThumbsDock->getDockLocationSettings(Qt::TopDockWidgetArea), mThumbsDock);
1044 thumbsDockAreaChanged();
1045
1046 QLabel* thumbsTitle = new QLabel(mThumbsDock);
1047 thumbsTitle->setObjectName("thumbsTitle");
1048 thumbsTitle->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
1049 thumbsTitle->setPixmap(QPixmap(":/nomacs/img/widget-separator.png").scaled(QSize(16, 4)));
1050 thumbsTitle->setFixedHeight(16);
1051 mThumbsDock->setTitleBarWidget(thumbsTitle);
1052
1053 connect(mThumbsDock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(thumbsDockAreaChanged()));
1054 }
1055
1056 if (show != mThumbsDock->isVisible())
1057 mThumbsDock->setVisible(show);
1058 }
1059
thumbsDockAreaChanged()1060 void DkNoMacs::thumbsDockAreaChanged() {
1061
1062 Qt::DockWidgetArea area = dockWidgetArea(mThumbsDock);
1063
1064 int thumbsOrientation = DkFilePreview::cm_pos_dock_hor;
1065
1066 if (area == Qt::LeftDockWidgetArea || area == Qt::RightDockWidgetArea)
1067 thumbsOrientation = DkFilePreview::cm_pos_dock_ver;
1068
1069 if (getTabWidget()->getViewPort())
1070 getTabWidget()->getViewPort()->getController()->getFilePreview()->setWindowPosition(thumbsOrientation);
1071
1072 }
1073
openDir()1074 void DkNoMacs::openDir() {
1075
1076 // load system default open dialog
1077 QString dirName = QFileDialog::getExistingDirectory(
1078 this,
1079 tr("Open an Image Directory"),
1080 getTabWidget()->getCurrentDir(),
1081 QFileDialog::ShowDirsOnly | DkDialog::fileDialogOptions()
1082 );
1083
1084 if (dirName.isEmpty())
1085 return;
1086
1087 getTabWidget()->loadDirToTab(dirName);
1088 }
1089
openFile()1090 void DkNoMacs::openFile() {
1091
1092 QStringList openFilters = DkSettingsManager::param().app().openFilters;
1093 openFilters.pop_front();
1094 openFilters.prepend(tr("All Files (*.*)"));
1095
1096 // load system default open dialog
1097 QStringList filePaths = QFileDialog::getOpenFileNames(
1098 this,
1099 tr("Open Image"),
1100 getTabWidget()->getCurrentDir(),
1101 openFilters.join(";;"),
1102 nullptr,
1103 DkDialog::fileDialogOptions()
1104 );
1105
1106 if (filePaths.isEmpty())
1107 return;
1108
1109 int count = getTabWidget()->getTabs().count(); // Save current count of tabs for setting tab position later
1110 if (getTabWidget()->getTabs().at(0)->getMode() == DkTabInfo::tab_empty)
1111 count = 0;
1112
1113 QSet<QString> duplicates;
1114 for (const QString& fp : filePaths) {
1115 bool dup = false;
1116
1117 if (DkSettingsManager::param().global().checkOpenDuplicates) { // Should we check for duplicates?
1118 for (auto tab : getTabWidget()->getTabs()) {
1119 if (tab->getFilePath().compare(fp) == 0) {
1120 duplicates.insert(tab->getFilePath());
1121 dup = true;
1122 break;
1123 }
1124 }
1125 }
1126
1127 if (!dup) {
1128
1129 // > 1: only open in tab if more than one file is opened
1130 bool newTab = filePaths.size() > 1 | getTabWidget()->getTabs().size() > 1;
1131 getTabWidget()->loadFile(fp, newTab);
1132 }
1133 }
1134 if (duplicates.count() > 0) { // Show message if at least one duplicate was found
1135 QString duptext = tr("The following duplicates were not opened:");
1136 for (auto dup : duplicates) {
1137 duptext.append("\n" + dup);
1138 }
1139 getTabWidget()->getViewPort()->getController()->setInfo(duptext);
1140 }
1141
1142 if (filePaths.count() > duplicates.count()) // Only set the active tab if there is actually something added
1143 getTabWidget()->setActiveTab(count); // Set first file opened to be the active tab
1144 }
1145
openFileList()1146 void DkNoMacs::openFileList() {
1147
1148 QStringList openFilters;
1149 openFilters.append(tr("Text file (*.txt)"));
1150 openFilters.append(tr("All files (*.*)"));
1151
1152 // load system default open dialog
1153 QString fileName = QFileDialog::getOpenFileName(
1154 this,
1155 tr("Open Image"),
1156 getTabWidget()->getCurrentDir(),
1157 openFilters.join(";;"),
1158 nullptr,
1159 DkDialog::fileDialogOptions()
1160 );
1161
1162 if (fileName.isEmpty())
1163 return;
1164
1165 int count = getTabWidget()->getTabs().count();
1166 if (getTabWidget()->getTabs().at(0)->getMode() == DkTabInfo::tab_empty)
1167 count = 0;
1168
1169 QFile file(fileName);
1170 if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
1171 return;
1172
1173 while (!file.atEnd()) {
1174 QString line = file.readLine().simplified();
1175 if (QFileInfo::exists(line)) {
1176 getTabWidget()->loadFile(line, true);
1177 }
1178 }
1179
1180 getTabWidget()->setActiveTab(count);
1181 }
1182
saveFileList()1183 void DkNoMacs::saveFileList() {
1184
1185 QStringList saveFilters;
1186 saveFilters.append(tr("Text file (*.txt)"));
1187 saveFilters.append(tr("All files (*.*)"));
1188
1189 QString fileName = QFileDialog::getSaveFileName(
1190 this,
1191 tr("Save Tab List"),
1192 getTabWidget()->getCurrentDir(),
1193 saveFilters.join(";;"),
1194 nullptr,
1195 DkDialog::fileDialogOptions()
1196 );
1197
1198 if (fileName.isEmpty())
1199 return;
1200
1201 QFile file(fileName);
1202 if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate))
1203 return;
1204
1205 for (auto tab : getTabWidget()->getTabs()) {
1206 file.write(tab->getFilePath().toUtf8()+"\n");
1207 }
1208
1209 file.close();
1210 }
1211
openQuickLaunch()1212 void DkNoMacs::openQuickLaunch() {
1213
1214 DkMainToolBar* tb = DkToolBarManager::inst().defaultToolBar();
1215
1216 // create new model
1217 if (!mQuickAccess) {
1218 mQuickAccess = new DkQuickAccess(this);
1219
1220 // add all actions
1221 mQuickAccess->addActions(DkActionManager::instance().allActions());
1222
1223 connect(mQuickAccess, SIGNAL(loadFileSignal(const QString&)), getTabWidget(), SLOT(loadFile(const QString&)));
1224 }
1225
1226 if (tb)
1227 connect(tb->getQuickAccess(), SIGNAL(executeSignal(const QString&)), mQuickAccess, SLOT(execute(const QString&)), Qt::UniqueConnection);
1228
1229 mQuickAccess->addDirs(DkSettingsManager::param().global().recentFolders);
1230 mQuickAccess->addFiles(DkSettingsManager::param().global().recentFiles);
1231
1232 if (tb && tb->isVisible())
1233 tb->setQuickAccessModel(mQuickAccess->getModel());
1234 else {
1235
1236 if (!mQuickAccessEdit) {
1237 mQuickAccessEdit = new DkQuickAccessEdit(this);
1238 connect(mQuickAccessEdit, SIGNAL(executeSignal(const QString&)), mQuickAccess, SLOT(execute(const QString&)));
1239 }
1240
1241 int right = getTabWidget()->geometry().right();
1242 mQuickAccessEdit->setFixedWidth(qRound(width()/3.0f));
1243 mQuickAccessEdit->move(QPoint(right-mQuickAccessEdit->width()-10, qRound(height()*0.25)));
1244 mQuickAccessEdit->setModel(mQuickAccess->getModel());
1245 mQuickAccessEdit->show();
1246 }
1247 }
1248
loadFile(const QString & filePath)1249 void DkNoMacs::loadFile(const QString& filePath) {
1250
1251 if (!getTabWidget())
1252 return;
1253
1254 if (QFileInfo(filePath).isDir())
1255 getTabWidget()->loadDirToTab(filePath);
1256 else
1257 getTabWidget()->loadFile(filePath, false);
1258
1259 }
1260
1261 // TODO: move this
renameFile()1262 void DkNoMacs::renameFile() {
1263
1264 // TODO:ref move!
1265 QString filePath = getTabWidget()->getCurrentFilePath();
1266 QFileInfo file(filePath);
1267
1268 if (!file.absoluteDir().exists()) {
1269 getTabWidget()->setInfo(tr("Sorry, the directory: %1 does not exist\n").arg(file.absolutePath()));
1270 return;
1271 }
1272 if (file.exists() && !file.isWritable()) {
1273 getTabWidget()->setInfo(tr("Sorry, I can't write to the fileInfo: %1").arg(file.fileName()));
1274 return;
1275 }
1276
1277 QString fileName = file.fileName();
1278 int dotIdx = fileName.lastIndexOf(".");
1279 QString baseName = dotIdx != -1 ? fileName.left(dotIdx) : fileName;
1280
1281 bool ok = false;
1282 QString newFileName = QInputDialog::getText(this, baseName, tr("Rename:"), QLineEdit::Normal, baseName, &ok);
1283
1284 if (ok && !newFileName.isEmpty() && newFileName != baseName) {
1285
1286 if (!file.suffix().isEmpty())
1287 newFileName.append("." + file.suffix());
1288
1289 qDebug() << "renaming: " << file.fileName() << " -> " << newFileName;
1290 QFileInfo renamedFile = QFileInfo(file.absoluteDir(), newFileName);
1291
1292 // overwrite file?
1293 // the second comparison is important for windows (case insensitive filenames)
1294 if (renamedFile.exists() && renamedFile.absoluteFilePath().compare(file.absoluteFilePath(), Qt::CaseInsensitive) != 0) {
1295
1296 QMessageBox infoDialog(this);
1297 infoDialog.setWindowTitle(tr("Question"));
1298 infoDialog.setText(tr("The fileInfo: %1 already exists.\n Do you want to replace it?").arg(newFileName));
1299 infoDialog.setIcon(QMessageBox::Question);
1300 infoDialog.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
1301 infoDialog.setDefaultButton(QMessageBox::No);
1302 infoDialog.show();
1303 int choice = infoDialog.exec();
1304
1305 if (choice == QMessageBox::Yes) {
1306
1307 QFile oldFile(renamedFile.absoluteFilePath());
1308 bool removed = oldFile.remove();
1309
1310 // tell user that deleting went wrong, and stop the renaming
1311 if (!removed) {
1312 getTabWidget()->setInfo(tr("Sorry, I can't delete: %1").arg(file.fileName()));
1313 return;
1314 }
1315 }
1316 else
1317 return; // cancel renaming
1318 }
1319
1320 if (getTabWidget()->getViewPort())
1321 getTabWidget()->getViewPort()->unloadImage();
1322
1323 QFile newFile(file.absoluteFilePath());
1324 bool renamed = newFile.rename(renamedFile.absoluteFilePath());
1325
1326 // tell user that deleting went wrong, and stop the renaming
1327 if (!renamed)
1328 getTabWidget()->setInfo(tr("Sorry, I can't rename: %1").arg(file.fileName()));
1329 else if (DkSettingsManager::param().resources().loadSavedImage == DkSettings::ls_load)
1330 getTabWidget()->loadFile(renamedFile.absoluteFilePath());
1331 else if (getTabWidget()->getViewPort())
1332 getTabWidget()->getViewPort()->loadNextFileFast();
1333
1334 }
1335 }
1336
find(bool filterAction)1337 void DkNoMacs::find(bool filterAction) {
1338
1339 if (!getTabWidget()->getCurrentImageLoader())
1340 return;
1341
1342 if (filterAction) {
1343
1344 int db = (QObject::sender() == DkActionManager::instance().action(DkActionManager::menu_tools_filter)) ? DkSearchDialog::filter_button : DkSearchDialog::find_button;
1345
1346 qDebug() << "default button: " << db;
1347 DkSearchDialog* searchDialog = new DkSearchDialog(this);
1348 searchDialog->setDefaultButton(db);
1349
1350 searchDialog->setFiles(getTabWidget()->getCurrentImageLoader()->getFileNames());
1351 searchDialog->setPath(getTabWidget()->getCurrentImageLoader()->getDirPath());
1352
1353 connect(searchDialog, SIGNAL(filterSignal(const QString&)), getTabWidget()->getCurrentImageLoader().data(), SLOT(setFolderFilter(const QString&)));
1354 connect(searchDialog, SIGNAL(loadFileSignal(const QString&)), getTabWidget(), SLOT(loadFile(const QString&)));
1355 int answer = searchDialog->exec();
1356
1357 DkActionManager::instance().action(DkActionManager::menu_tools_filter)->setChecked(answer == DkSearchDialog::filter_button);
1358 }
1359 else {
1360 // remove the filter
1361 getTabWidget()->getCurrentImageLoader()->setFolderFilter(QString());
1362 }
1363
1364 }
1365
changeSorting(bool change)1366 void DkNoMacs::changeSorting(bool change) {
1367
1368 // TODO: move to image loader?!
1369
1370 if (change) {
1371
1372 QString senderName = QObject::sender()->objectName();
1373
1374 if (senderName == "menu_sort_filename")
1375 DkSettingsManager::param().global().sortMode = DkSettings::sort_filename;
1376 else if (senderName == "menu_sort_date_created")
1377 DkSettingsManager::param().global().sortMode = DkSettings::sort_date_created;
1378 else if (senderName == "menu_sort_date_modified")
1379 DkSettingsManager::param().global().sortMode = DkSettings::sort_date_modified;
1380 else if (senderName == "menu_sort_random")
1381 DkSettingsManager::param().global().sortMode = DkSettings::sort_random;
1382 else if (senderName == "menu_sort_ascending")
1383 DkSettingsManager::param().global().sortDir = DkSettings::sort_ascending;
1384 else if (senderName == "menu_sort_descending")
1385 DkSettingsManager::param().global().sortDir = DkSettings::sort_descending;
1386
1387 if (getTabWidget()->getCurrentImageLoader())
1388 getTabWidget()->getCurrentImageLoader()->sort();
1389 }
1390
1391 QVector<QAction*> sortActions = DkActionManager::instance().sortActions();
1392 for (int idx = 0; idx < sortActions.size(); idx++) {
1393
1394 if (idx < DkActionManager::menu_sort_ascending)
1395 sortActions[idx]->setChecked(idx == DkSettingsManager::param().global().sortMode);
1396 else if (idx >= DkActionManager::menu_sort_ascending)
1397 sortActions[idx]->setChecked(idx-DkActionManager::menu_sort_ascending == DkSettingsManager::param().global().sortDir);
1398 }
1399 }
1400
goTo()1401 void DkNoMacs::goTo() {
1402
1403 if (!getTabWidget()->getCurrentImageLoader())
1404 return;
1405
1406 QSharedPointer<DkImageLoader> loader = getTabWidget()->getCurrentImageLoader();
1407
1408 bool ok = false;
1409 int fileIdx = QInputDialog::getInt(this, tr("Go To Image"), tr("Image Index:"), 1, 1, loader->numFiles(), 1, &ok);
1410
1411 if (ok)
1412 loader->loadFileAt(fileIdx-1);
1413
1414 }
1415
trainFormat()1416 void DkNoMacs::trainFormat() {
1417
1418 if (!mTrainDialog)
1419 mTrainDialog = new DkTrainDialog(this);
1420
1421 mTrainDialog->setCurrentFile(getTabWidget()->getCurrentFilePath());
1422 bool okPressed = mTrainDialog->exec() != 0;
1423
1424 if (okPressed && getTabWidget()->getCurrentImageLoader()) {
1425 getTabWidget()->getCurrentImageLoader()->load(mTrainDialog->getAcceptedFile());
1426 getTabWidget()->restart(); // quick & dirty, but currently he messes up the filteredFileList if the same folder was already loaded
1427 }
1428
1429 }
1430
extractImagesFromArchive()1431 void DkNoMacs::extractImagesFromArchive() {
1432 #ifdef WITH_QUAZIP
1433
1434 if (!mArchiveExtractionDialog)
1435 mArchiveExtractionDialog = new DkArchiveExtractionDialog(this);
1436
1437 if (getTabWidget()->getCurrentImage()) {
1438 if (getTabWidget()->getCurrentImage()->isFromZip())
1439 mArchiveExtractionDialog->setCurrentFile(getTabWidget()->getCurrentImage()->getZipData()->getZipFilePath(), true);
1440 else
1441 mArchiveExtractionDialog->setCurrentFile(getTabWidget()->getCurrentFilePath(), false);
1442 }
1443 else
1444 mArchiveExtractionDialog->setCurrentFile(getTabWidget()->getCurrentFilePath(), false);
1445
1446 mArchiveExtractionDialog->exec();
1447 #endif
1448 }
1449
exportTiff()1450 void DkNoMacs::exportTiff() {
1451
1452 #ifdef WITH_LIBTIFF
1453 if (!mExportTiffDialog)
1454 mExportTiffDialog = new DkExportTiffDialog(this);
1455
1456 mExportTiffDialog->setFile(getTabWidget()->getCurrentFilePath());
1457 mExportTiffDialog->exec();
1458 #endif
1459 }
1460
computeThumbsBatch()1461 void DkNoMacs::computeThumbsBatch() {
1462
1463 if (!mForceDialog)
1464 mForceDialog = new DkForceThumbDialog(this);
1465 mForceDialog->setWindowTitle(tr("Save Thumbnails"));
1466 mForceDialog->setDir(getTabWidget()->getCurrentDir());
1467
1468 if (!mForceDialog->exec())
1469 return;
1470
1471 if (!mThumbSaver)
1472 mThumbSaver = new DkThumbsSaver(this);
1473
1474 if (getTabWidget()->getCurrentImageLoader())
1475 mThumbSaver->processDir(getTabWidget()->getCurrentImageLoader()->getImages(), mForceDialog->forceSave());
1476 }
1477
aboutDialog()1478 void DkNoMacs::aboutDialog() {
1479
1480 DkSplashScreen* spScreen = new DkSplashScreen(this, 0);
1481 spScreen->exec();
1482 spScreen->deleteLater();
1483 }
1484
openDocumentation()1485 void DkNoMacs::openDocumentation() {
1486
1487 QString url = QString("https://nomacs.org/documentation/");
1488 QDesktopServices::openUrl(QUrl(url));
1489 }
1490
bugReport()1491 void DkNoMacs::bugReport() {
1492
1493 QString url = "https://github.com/nomacs/nomacs/issues/new";
1494 QDesktopServices::openUrl(QUrl(url));
1495 }
1496
cleanSettings()1497 void DkNoMacs::cleanSettings() {
1498
1499 DefaultSettings settings;
1500 settings.clear();
1501
1502 readSettings();
1503 resize(400, 225);
1504 move(100, 100);
1505 }
1506
newInstance(const QString & filePath)1507 void DkNoMacs::newInstance(const QString& filePath) {
1508
1509 QString exe = QApplication::applicationFilePath();
1510 QStringList args;
1511
1512 QAction* a = static_cast<QAction*>(sender());
1513
1514 if (a && a == DkActionManager::instance().action(DkActionManager::menu_file_private_instance))
1515 args.append("-p");
1516
1517 if (filePath.isEmpty())
1518 args.append(getTabWidget()->getCurrentFilePath());
1519 else
1520 args.append(filePath);
1521
1522 QProcess::startDetached(exe, args);
1523 }
1524
tagWall(const std::list<std::string> & code)1525 void tagWall(const std::list<std::string>& code) {
1526 for (auto line : code)
1527 std::cout << line << std::endl;
1528 }
1529
loadRecursion()1530 void DkNoMacs::loadRecursion() {
1531
1532 std::list<std::string> code;
1533 code.push_back("void tagWall(const std::list<std::string>& code) {");
1534 code.push_back(" for (auto line : code)");
1535 code.push_back(" std::cout << line << std::endl;");
1536 code.push_back("}");
1537 tagWall(code);
1538
1539 QImage img = grab().toImage();
1540
1541 if (getTabWidget()->getViewPort())
1542 getTabWidget()->getViewPort()->setImage(img);
1543 }
1544
1545 // Added by fabian for transfer function:
1546
restartWithPseudoColor(bool contrast)1547 void DkNoMacs::restartWithPseudoColor(bool contrast) {
1548
1549 qDebug() << "contrast: " << contrast;
1550
1551 QString exe = QApplication::applicationFilePath();
1552 QStringList args;
1553
1554 if (contrast)
1555 args << "-m" << "pseudocolor";
1556 else
1557 args << "-m" << "default";
1558 args.append(getTabWidget()->getCurrentFilePath());
1559
1560 bool started = mProcess.startDetached(exe, args);
1561
1562 // close me if the new instance started
1563 if (started)
1564 close();
1565
1566 qDebug() << "contrast arguments: " << args;
1567 }
1568
onWindowLoaded()1569 void DkNoMacs::onWindowLoaded() {
1570
1571 DefaultSettings settings;
1572 bool firstTime = settings.value("AppSettings/firstTime.nomacs.3", true).toBool();
1573
1574 if (DkDockWidget::testDisplaySettings(DkSettingsManager::param().app().showExplorer))
1575 showExplorer(true);
1576 if (DkDockWidget::testDisplaySettings(DkSettingsManager::param().app().showMetaDataDock))
1577 showMetaDataDock(true);
1578 if (DkDockWidget::testDisplaySettings(DkSettingsManager::param().app().showEditDock))
1579 showEditDock(true);
1580 if (DkDockWidget::testDisplaySettings(DkSettingsManager::param().app().showHistoryDock))
1581 showHistoryDock(true);
1582 if (DkDockWidget::testDisplaySettings(DkSettingsManager::param().app().showLogDock))
1583 showLogDock(true);
1584
1585 if (firstTime) {
1586
1587 // here are some first time requests
1588 DkWelcomeDialog* wecomeDialog = new DkWelcomeDialog(this);
1589 wecomeDialog->exec();
1590
1591 settings.setValue("AppSettings/firstTime.nomacs.3", false);
1592
1593 if (wecomeDialog->isLanguageChanged()) {
1594 restartWithTranslationUpdate();
1595 }
1596 }
1597
1598 checkForUpdate(true);
1599
1600 // load settings AFTER everything is initialized
1601 getTabWidget()->loadSettings();
1602
1603 // init global taskbar
1604 #ifdef WIN32
1605 QWinTaskbarButton *button = new QWinTaskbarButton(this);
1606 button->setWindow(windowHandle());
1607
1608 DkGlobalProgress::instance().setProgressBar(button->progress());
1609 #endif
1610
1611 toggleDocks(DkSettingsManager::param().app().hideAllPanels);
1612 }
1613
keyPressEvent(QKeyEvent * event)1614 void DkNoMacs::keyPressEvent(QKeyEvent *event) {
1615
1616 if (event->key() == Qt::Key_Alt) {
1617 mPosGrabKey = QCursor::pos();
1618 mOtherKeyPressed = false;
1619 }
1620 else
1621 mOtherKeyPressed = true;
1622
1623 }
1624
keyReleaseEvent(QKeyEvent * event)1625 void DkNoMacs::keyReleaseEvent(QKeyEvent* event) {
1626
1627 if (event->key() == Qt::Key_Alt && !mOtherKeyPressed && (mPosGrabKey - QCursor::pos()).manhattanLength() == 0)
1628 mMenu->showMenu();
1629
1630 }
1631
1632 // >DIR diem: eating shortcut overrides (this allows us to use navigation keys like arrows)
eventFilter(QObject *,QEvent * event)1633 bool DkNoMacs::eventFilter(QObject*, QEvent* event) {
1634
1635 if (event->type() == QEvent::ShortcutOverride) {
1636 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
1637
1638 // consume esc key if fullscreen is on
1639 if (keyEvent->key() == Qt::Key_Escape && isFullScreen()) {
1640 exitFullScreen();
1641 return true;
1642 }
1643 else if (keyEvent->key() == Qt::Key_Escape && DkSettingsManager::param().app().closeOnEsc)
1644 close();
1645 }
1646 //if (event->type() == QEvent::Gesture) {
1647 // return gestureEvent(static_cast<QGestureEvent*>(event));
1648 //}
1649
1650 return false;
1651 }
1652
showMenuBar(bool show)1653 void DkNoMacs::showMenuBar(bool show) {
1654
1655 DkSettingsManager::param().app().showMenuBar = show;
1656
1657 QAction* mp = DkActionManager::instance().action(DkActionManager::menu_panel_menu);
1658 mp->blockSignals(true);
1659 mp->setChecked(DkSettingsManager::param().app().showMenuBar);
1660 mp->blockSignals(false);
1661
1662 int tts = (DkSettingsManager::param().app().showMenuBar) ? -1 : 5000;
1663 mMenu->setTimeToShow(tts);
1664
1665 if (show)
1666 mMenu->showMenu();
1667 else if (!show)
1668 mMenu->hide();
1669 }
1670
openFileWith(QAction * action)1671 void DkNoMacs::openFileWith(QAction* action) {
1672
1673 if (!action)
1674 return;
1675
1676 QFileInfo app(action->toolTip());
1677
1678 if (!app.exists())
1679 getTabWidget()->setInfo("Sorry, " % app.fileName() % " does not exist");
1680
1681 QStringList args;
1682
1683 QString filePath = getTabWidget()->getCurrentFilePath();
1684
1685 if (app.fileName() == "explorer.exe")
1686 args << "/select," << QDir::toNativeSeparators(filePath);
1687 else if (app.fileName().toLower() == "outlook.exe") {
1688 args << "/a" << QDir::toNativeSeparators(filePath);
1689 }
1690 else
1691 args << QDir::toNativeSeparators(filePath);
1692
1693 //bool started = process.startDetached("psOpenImages.exe", args); // already deprecated
1694 bool started = mProcess.startDetached(app.absoluteFilePath(), args);
1695
1696 if (started)
1697 qDebug() << "starting: " << app.fileName() << args;
1698 else
1699 getTabWidget()->setInfo("Sorry, I could not start: " % app.absoluteFilePath());
1700 }
1701
setWindowTitle(QSharedPointer<DkImageContainerT> imgC)1702 void DkNoMacs::setWindowTitle(QSharedPointer<DkImageContainerT> imgC) {
1703
1704 if (!imgC) {
1705 setWindowTitle(QString());
1706 return;
1707 }
1708
1709 setWindowTitle(imgC->filePath(), imgC->image().size(), imgC->isEdited(), imgC->getTitleAttribute());
1710 }
1711
setWindowTitle(const QString & filePath,const QSize & size,bool edited,const QString & attr)1712 void DkNoMacs::setWindowTitle(const QString& filePath, const QSize& size, bool edited, const QString& attr) {
1713
1714 QString title;
1715
1716 if (DkSettingsManager::param().global().extendedTabs && (getTabWidget()->getTabs().count() > 1)) {
1717 title.append(QString::number(getTabWidget()->getActiveTab() + 1) + "/" + QString::number(getTabWidget()->getTabs().count()) + " - ");
1718 }
1719
1720 QFileInfo fInfo = filePath;
1721 title.append(QFileInfo(filePath).fileName());
1722 title = title.remove(".lnk");
1723
1724 if (filePath.isEmpty()) {
1725 title = "nomacs - Image Lounge";
1726 if (DkSettingsManager::param().app().privateMode)
1727 title.append(tr(" [Private Mode]"));
1728 }
1729
1730 if (edited)
1731 title.append("[*]");
1732
1733 title.append(" ");
1734 title.append(attr); // append some attributes
1735
1736 QString attributes;
1737 auto vp = getTabWidget()->getViewPort();
1738
1739 if (!size.isEmpty())
1740 attributes.sprintf(" - %i x %i", size.width(), size.height());
1741 if (size.isEmpty() && vp && !vp->getImageSize().isEmpty())
1742 attributes.sprintf(" - %i x %i", vp->getImage().width(), vp->getImage().height());
1743 if (DkSettingsManager::param().app().privateMode)
1744 attributes.append(tr(" [Private Mode]"));
1745
1746 QMainWindow::setWindowTitle(title.append(attributes));
1747 setWindowFilePath(filePath);
1748 setWindowModified(edited);
1749
1750 auto cm = DkSyncManager::inst().client();
1751 if (cm)
1752 cm->sendTitle(windowTitle());
1753
1754 // TODO: move!
1755 DkStatusBar* bar = DkStatusBarManager::instance().statusbar();
1756
1757 if (((vp && !vp->getController()->getFileInfoLabel()->isVisible()) ||
1758 !DkSettingsManager::param().slideShow().display.testBit(DkSettings::display_creation_date)) && getTabWidget()->getCurrentImage()) {
1759
1760 // create statusbar info
1761 QSharedPointer<DkMetaDataT> metaData = getTabWidget()->getCurrentImage()->getMetaData();
1762 QString dateString = metaData->getExifValue("DateTimeOriginal");
1763 dateString = DkUtils::convertDateString(dateString, fInfo);
1764 bar->setMessage(dateString, DkStatusBar::status_time_info);
1765 }
1766 else
1767 bar->setMessage("", DkStatusBar::status_time_info); // hide label
1768
1769 if (fInfo.exists())
1770 bar->setMessage(DkUtils::readableByte((float)fInfo.size()), DkStatusBar::status_filesize_info);
1771 else
1772 bar->setMessage("", DkStatusBar::status_filesize_info);
1773
1774 }
1775
settingsChanged()1776 void DkNoMacs::settingsChanged() {
1777
1778 if (!isFullScreen()) {
1779 showMenuBar(DkSettingsManager::param().app().showMenuBar);
1780
1781 DkToolBarManager::inst().restore();
1782 DkStatusBarManager::instance().show(DkSettingsManager::param().app().showStatusBar);
1783 }
1784 }
1785
checkForUpdate(bool silent)1786 void DkNoMacs::checkForUpdate(bool silent) {
1787
1788 // updates are supported on windows only
1789 #ifndef Q_OS_LINUX
1790
1791 // do we really need to check for update?
1792 if (!silent ||
1793 (!DkSettingsManager::param().sync().updateDialogShown &&
1794 QDate::currentDate() > DkSettingsManager::param().sync().lastUpdateCheck &&
1795 DkSettingsManager::param().sync().checkForUpdates)) {
1796
1797 DkTimer dt;
1798
1799 if (!mUpdater) {
1800 mUpdater = new DkUpdater(this);
1801 connect(mUpdater, SIGNAL(displayUpdateDialog(QString, QString)), this, SLOT(showUpdateDialog(QString, QString)));
1802 connect(mUpdater, SIGNAL(showUpdaterMessage(QString, QString)), this, SLOT(showUpdaterMessage(QString, QString)));
1803 }
1804 mUpdater->silent = silent;
1805 mUpdater->checkForUpdates();
1806 qDebug() << "checking for updates takes: " << dt;
1807 }
1808 #endif // !#ifndef Q_OS_LINUX
1809 }
1810
showUpdaterMessage(QString msg,QString title)1811 void DkNoMacs::showUpdaterMessage(QString msg, QString title) {
1812
1813 QMessageBox infoDialog(this);
1814 infoDialog.setWindowTitle(title);
1815 infoDialog.setIcon(QMessageBox::Information);
1816 infoDialog.setText(msg);
1817 infoDialog.show();
1818
1819 infoDialog.exec();
1820 }
1821
showUpdateDialog(QString msg,QString title)1822 void DkNoMacs::showUpdateDialog(QString msg, QString title) {
1823
1824 if (mProgressDialog != 0 && !mProgressDialog->isHidden()) { // check if the progress bar is already open
1825 showUpdaterMessage(tr("Already downloading update"), "update");
1826 return;
1827 }
1828
1829 DkSettingsManager::param().sync().updateDialogShown = true;
1830 DkSettingsManager::param().save();
1831
1832 if (!mUpdateDialog) {
1833 mUpdateDialog = new DkUpdateDialog(this);
1834 mUpdateDialog->setWindowTitle(title);
1835 mUpdateDialog->upperLabel->setText(msg);
1836 connect(mUpdateDialog, SIGNAL(startUpdate()), this, SLOT(performUpdate()));
1837 }
1838
1839 mUpdateDialog->exec();
1840 }
1841
performUpdate()1842 void DkNoMacs::performUpdate() {
1843
1844 if (!mUpdater) {
1845 qDebug() << "WARNING updater is NULL where it should not be.";
1846 return;
1847 }
1848
1849 mUpdater->performUpdate();
1850
1851 if (!mProgressDialog) {
1852 mProgressDialog = new QProgressDialog(tr("Downloading update..."), tr("Cancel Update"), 0, 100, this);
1853 mProgressDialog->setWindowIcon(windowIcon());
1854 connect(mProgressDialog, SIGNAL(canceled()), mUpdater, SLOT(cancelUpdate()));
1855 connect(mUpdater, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(updateProgress(qint64, qint64)));
1856 connect(mUpdater, SIGNAL(downloadFinished(QString)), mProgressDialog, SLOT(close()));
1857 //connect(updater, SIGNAL(downloadFinished(QString)), progressDialog, SLOT(deleteLater()));
1858 connect(mUpdater, SIGNAL(downloadFinished(QString)), this, SLOT(startSetup(QString)));
1859 }
1860 //mProgressDialog->setWindowModality(Qt::ApplicationModal);
1861
1862 mProgressDialog->show();
1863 //progressDialog->raise();
1864 //progressDialog->activateWindow();
1865 //mProgressDialog->setWindowModality(Qt::NonModal);
1866 }
1867
updateProgress(qint64 received,qint64 total)1868 void DkNoMacs::updateProgress(qint64 received, qint64 total) {
1869 mProgressDialog->setMaximum((int)total);
1870 mProgressDialog->setValue((int)received);
1871 }
1872
updateProgressTranslations(qint64 received,qint64 total)1873 void DkNoMacs::updateProgressTranslations(qint64 received, qint64 total) {
1874 qDebug() << "rec:" << received << " total:" << total;
1875 mProgressDialogTranslations->setMaximum((int)total);
1876 mProgressDialogTranslations->setValue((int)received);
1877 }
1878
startSetup(QString filePath)1879 void DkNoMacs::startSetup(QString filePath) {
1880
1881 qDebug() << "starting setup filePath:" << filePath;
1882
1883 if (!QFile::exists(filePath))
1884 qDebug() << "file does not exist";
1885 if (!QDesktopServices::openUrl(QUrl::fromLocalFile(filePath))) {
1886 QString msg = tr("Unable to install new version<br>") +
1887 tr("You can download the new version from our web page") +
1888 "<br><a href=\"https://nomacs.org/download/\">www.nomacs.org</a><br>";
1889 showUpdaterMessage(msg, "update");
1890 }
1891 }
1892
updateTranslations()1893 void DkNoMacs::updateTranslations() {
1894
1895 if (!mTranslationUpdater) {
1896 mTranslationUpdater = new DkTranslationUpdater(false, this);
1897 connect(mTranslationUpdater, SIGNAL(showUpdaterMessage(QString, QString)), this, SLOT(showUpdaterMessage(QString, QString)));
1898 }
1899
1900 if (!mProgressDialogTranslations) {
1901 mProgressDialogTranslations = new QProgressDialog(tr("Downloading new translations..."), tr("Cancel"), 0, 100, this);
1902 mProgressDialogTranslations->setWindowIcon(windowIcon());
1903 connect(mProgressDialogTranslations, SIGNAL(canceled()), mTranslationUpdater, SLOT(cancelUpdate()));
1904 //connect(progressDialogTranslations, SIGNAL(canceled()), translationUpdater, SLOT(cancelUpdate()));
1905 connect(mTranslationUpdater, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(updateProgressTranslations(qint64, qint64)));
1906 connect(mTranslationUpdater, SIGNAL(downloadFinished()), mProgressDialogTranslations, SLOT(close()));
1907 }
1908 //mProgressDialogTranslations->setWindowModality(Qt::ApplicationModal);
1909
1910 mProgressDialogTranslations->show();
1911 //progressDialog->raise();
1912 //progressDialog->activateWindow();
1913 //mProgressDialogTranslations->setWindowModality(Qt::NonModal);
1914
1915 mTranslationUpdater->checkForUpdates();
1916 }
1917
restartWithTranslationUpdate()1918 void DkNoMacs::restartWithTranslationUpdate() {
1919
1920 if (!mTranslationUpdater) {
1921 mTranslationUpdater = new DkTranslationUpdater(false, this);
1922 connect(mTranslationUpdater, SIGNAL(showUpdaterMessage(QString, QString)), this, SLOT(showUpdaterMessage(QString, QString)));
1923 }
1924
1925 mTranslationUpdater->silent = true;
1926 connect(mTranslationUpdater, SIGNAL(downloadFinished()), this, SLOT(restart()));
1927 updateTranslations();
1928 }
1929
openPluginManager()1930 void DkNoMacs::openPluginManager() {
1931 #ifdef WITH_PLUGINS
1932
1933 if (getTabWidget()->getViewPort())
1934 getTabWidget()->getViewPort()->getController()->closePlugin(true);
1935
1936 if (DkPluginManager::instance().getRunningPlugin()) {
1937
1938 QMessageBox infoDialog(this);
1939 infoDialog.setWindowTitle("Close plugin");
1940 infoDialog.setIcon(QMessageBox::Information);
1941 infoDialog.setText("Please close the currently opened plugin first.");
1942 infoDialog.show();
1943
1944 infoDialog.exec();
1945 return;
1946 }
1947
1948 DkPluginManagerDialog* pluginDialog = new DkPluginManagerDialog(this);
1949 pluginDialog->exec();
1950 pluginDialog->deleteLater();
1951
1952 DkPluginActionManager* am = DkActionManager::instance().pluginActionManager();
1953 am->updateMenu();
1954
1955 #endif // WITH_PLUGINS
1956 }
1957
1958 // DkNoMacsSync --------------------------------------------------------------------
DkNoMacsSync(QWidget * parent,Qt::WindowFlags flags)1959 DkNoMacsSync::DkNoMacsSync(QWidget *parent, Qt::WindowFlags flags) : DkNoMacs(parent, flags) {
1960 }
1961
~DkNoMacsSync()1962 DkNoMacsSync::~DkNoMacsSync() {
1963 }
1964
createActions()1965 void DkNoMacsSync::createActions() {
1966
1967 DkNoMacs::createActions();
1968
1969 DkActionManager& am = DkActionManager::instance();
1970
1971 // sync menu
1972 connect(am.action(DkActionManager::menu_sync_pos), SIGNAL(triggered()), this, SLOT(tcpSendWindowRect()));
1973 connect(am.action(DkActionManager::menu_sync_arrange), SIGNAL(triggered()), this, SLOT(tcpSendArrange()));
1974
1975 auto cm = DkSyncManager::inst().client();
1976 assert(cm);
1977
1978 // just for local client
1979 connect(this, SIGNAL(sendArrangeSignal(bool)), cm, SLOT(sendArrangeInstances(bool)));
1980 connect(this, SIGNAL(sendQuitLocalClientsSignal()), cm, SLOT(sendQuitMessageToPeers()));
1981
1982 connect(cm, SIGNAL(clientConnectedSignal(bool)), this, SLOT(newClientConnected(bool)));
1983 connect(cm, SIGNAL(receivedPosition(QRect, bool, bool)), this, SLOT(tcpSetWindowRect(QRect, bool, bool)));
1984 }
1985
1986 // mouse events
mouseMoveEvent(QMouseEvent * event)1987 void DkNoMacsSync::mouseMoveEvent(QMouseEvent *event) {
1988
1989 int dist = QPoint(event->pos()-mMousePos).manhattanLength();
1990
1991 // create drag sync action
1992 if (event->buttons() == Qt::LeftButton && dist > QApplication::startDragDistance() &&
1993 event->modifiers() == (Qt::ControlModifier | Qt::AltModifier)) {
1994
1995 qDebug() << "generating a drag event...";
1996
1997 auto cm = dynamic_cast<DkLocalClientManager*>(DkSyncManager::inst().client());
1998 assert(cm);
1999 auto md = cm->mimeData();
2000
2001 QDrag* drag = new QDrag(this);
2002 drag->setMimeData(md);
2003 drag->exec(Qt::CopyAction | Qt::MoveAction);
2004 }
2005 else
2006 DkNoMacs::mouseMoveEvent(event);
2007
2008 }
2009
dragEnterEvent(QDragEnterEvent * event)2010 void DkNoMacsSync::dragEnterEvent(QDragEnterEvent *event) {
2011
2012 if (event->mimeData()->hasFormat("network/sync-dir")) {
2013 event->accept();
2014 }
2015
2016 QMainWindow::dragEnterEvent(event);
2017 }
2018
dropEvent(QDropEvent * event)2019 void DkNoMacsSync::dropEvent(QDropEvent *event) {
2020
2021 if (event->source() == this) {
2022 event->accept();
2023 return;
2024 }
2025
2026 if (event->mimeData()->hasFormat("network/sync-dir")) {
2027
2028 QByteArray connectionData = event->mimeData()->data("network/sync-dir");
2029 QDataStream dataStream(&connectionData, QIODevice::ReadOnly);
2030 quint16 peerId;
2031 dataStream >> peerId;
2032
2033 auto cm = DkSyncManager::inst().client();
2034 cm->synchronizeWithServerPort(peerId);
2035 }
2036 else
2037 QMainWindow::dropEvent(event);
2038 }
2039
DkNoMacsIpl(QWidget * parent,Qt::WindowFlags flags)2040 DkNoMacsIpl::DkNoMacsIpl(QWidget *parent, Qt::WindowFlags flags) : DkNoMacsSync(parent, flags) {
2041
2042 // init members
2043 DkCentralWidget* cw = new DkCentralWidget(this);
2044 setCentralWidget(cw);
2045
2046 init();
2047 setAcceptDrops(true);
2048 setMouseTracking (true); //receive mouse event everytime
2049
2050 DkSettingsManager::param().app().appMode = 0;
2051 DkSettingsManager::param().app().appMode = DkSettings::mode_default;
2052 }
2053
2054 // FramelessNoMacs --------------------------------------------------------------------
DkNoMacsFrameless(QWidget * parent,Qt::WindowFlags flags)2055 DkNoMacsFrameless::DkNoMacsFrameless(QWidget *parent, Qt::WindowFlags flags)
2056 : DkNoMacs(parent, flags) {
2057
2058 setObjectName("DkNoMacsFrameless");
2059 DkSettingsManager::param().app().appMode = DkSettings::mode_frameless;
2060
2061 setWindowFlags(Qt::FramelessWindowHint);
2062 setAttribute(Qt::WA_TranslucentBackground, true);
2063
2064 // init members
2065 DkCentralWidget* cw = new DkCentralWidget(this);
2066 setCentralWidget(cw);
2067
2068 init();
2069
2070 setAcceptDrops(true);
2071 setMouseTracking(true); //receive mouse event everytime
2072
2073 // in frameless, you cannot control if menu is visible...
2074 DkActionManager& am = DkActionManager::instance();
2075 am.action(DkActionManager::menu_panel_menu)->setEnabled(false);
2076 am.action(DkActionManager::menu_panel_statusbar)->setEnabled(false);
2077 am.action(DkActionManager::menu_panel_statusbar)->setChecked(false);
2078 am.action(DkActionManager::menu_panel_toolbar)->setChecked(false);
2079
2080 mMenu->setTimeToShow(5000);
2081 mMenu->hide();
2082
2083 am.action(DkActionManager::menu_view_frameless)->blockSignals(true);
2084 am.action(DkActionManager::menu_view_frameless)->setChecked(true);
2085 am.action(DkActionManager::menu_view_frameless)->blockSignals(false);
2086
2087 mDesktop = QApplication::desktop();
2088
2089 chooseMonitor(false);
2090 show();
2091
2092 connect(mDesktop, SIGNAL(workAreaResized(int)), this, SLOT(chooseMonitor()));
2093 connect(am.action(DkActionManager::menu_view_monitors), SIGNAL(triggered()), this, SLOT(chooseMonitor()));
2094
2095 setObjectName("DkNoMacsFrameless");
2096 DkStatusBarManager::instance().show(false); // fix
2097
2098 // actions that should always be disabled
2099 DkActionManager::instance().action(DkActionManager::menu_view_fit_frame)->setEnabled(false);
2100 }
2101
~DkNoMacsFrameless()2102 DkNoMacsFrameless::~DkNoMacsFrameless() {
2103 }
2104
createContextMenu()2105 void DkNoMacsFrameless::createContextMenu() {
2106
2107 DkNoMacs::createContextMenu();
2108
2109 DkActionManager& am = DkActionManager::instance();
2110 am.contextMenu()->addSeparator();
2111 am.contextMenu()->addAction(am.action(DkActionManager::menu_file_exit));
2112 }
2113
chooseMonitor(bool force)2114 void DkNoMacsFrameless::chooseMonitor(bool force) {
2115
2116 if (!mDesktop)
2117 return;
2118
2119 QRect screenRect = mDesktop->availableGeometry();
2120
2121 // ask the user which monitor to use
2122 if (mDesktop->screenCount() > 1) {
2123 DkChooseMonitorDialog* cmd = new DkChooseMonitorDialog(this);
2124 cmd->setWindowTitle(tr("Choose a Monitor"));
2125
2126 if (force || cmd->showDialog()) {
2127 int answer = cmd->exec();
2128 if (answer == QDialog::Accepted) {
2129 screenRect = cmd->screenRect();
2130 }
2131 }
2132 else {
2133 screenRect = cmd->screenRect();
2134 }
2135 }
2136
2137 setGeometry(screenRect);
2138 }
2139
2140 // >DIR diem: eating shortcut overrides
eventFilter(QObject *,QEvent * event)2141 bool DkNoMacsFrameless::eventFilter(QObject* , QEvent* event) {
2142
2143 if (event->type() == QEvent::ShortcutOverride) {
2144 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
2145
2146 // consume esc key if fullscreen is on
2147 if (keyEvent->key() == Qt::Key_Escape && isFullScreen()) {
2148 exitFullScreen();
2149 return true;
2150 }
2151 else if (keyEvent->key() == Qt::Key_Escape) {
2152 close();
2153 return true;
2154 }
2155 }
2156 //if (event->type() == QEvent::Gesture) {
2157 // return gestureEvent(static_cast<QGestureEvent*>(event));
2158 //}
2159
2160 return false;
2161 }
2162
closeEvent(QCloseEvent * event)2163 void DkNoMacsFrameless::closeEvent(QCloseEvent *event) {
2164
2165 // do not save the window size
2166 if (mSaveSettings)
2167 DkSettingsManager::param().save();
2168
2169 mSaveSettings = false;
2170
2171 DkNoMacs::closeEvent(event);
2172 }
2173
2174 // Transfer function:
2175
DkNoMacsContrast(QWidget * parent,Qt::WindowFlags flags)2176 DkNoMacsContrast::DkNoMacsContrast(QWidget *parent, Qt::WindowFlags flags)
2177 : DkNoMacsSync(parent, flags) {
2178
2179 setObjectName("DkNoMacsContrast");
2180
2181 // init members
2182 DkCentralWidget* cw = new DkCentralWidget(this);
2183 setCentralWidget(cw);
2184
2185 init();
2186
2187 DkToolBarManager::inst().createTransferToolBar();
2188
2189 setAcceptDrops(true);
2190 setMouseTracking (true); //receive mouse event everytime
2191
2192 DkSettingsManager::param().app().appMode = DkSettings::mode_contrast;
2193 setObjectName("DkNoMacsContrast");
2194
2195 // show it...
2196 show();
2197
2198 // TODO: this should be checked but no event should be called
2199 DkActionManager& am = DkActionManager::instance();
2200 am.action(DkActionManager::menu_panel_transfertoolbar)->blockSignals(true);
2201 am.action(DkActionManager::menu_panel_transfertoolbar)->setChecked(true);
2202 am.action(DkActionManager::menu_panel_transfertoolbar)->blockSignals(false);
2203 }
2204
~DkNoMacsContrast()2205 DkNoMacsContrast::~DkNoMacsContrast() {
2206 }
2207
2208 }
2209