diff --git a/src/app/puzzle/main.cpp b/src/app/puzzle/main.cpp
index f214dd3a0..86d126b18 100644
--- a/src/app/puzzle/main.cpp
+++ b/src/app/puzzle/main.cpp
@@ -25,14 +25,67 @@
** along with Valentina. If not, see .
**
*************************************************************************/
-#include "puzzlemainwindow.h"
-#include
+
+#include // For QT_REQUIRE_VERSION
+#include
+
+#include "puzzleapplication.h"
+#include "../fervor/fvupdater.h"
+#include "../vmisc/vsysexits.h"
+#include "../vmisc/def.h"
+
+
+#if defined(APPIMAGE) && defined(Q_OS_LINUX)
+#if QT_VERSION < QT_VERSION_CHECK(5, 12, 0)
+# include "../vmisc/backport/qscopeguard.h"
+#else
+# include
+#endif
+# include "../vmisc/appimage.h"
+#endif // defined(APPIMAGE) && defined(Q_OS_LINUX)
int main(int argc, char *argv[])
{
- QApplication a(argc, argv);
- PuzzleMainWindow w;
- w.show();
+#if defined(APPIMAGE) && defined(Q_OS_LINUX)
+ /* Fix path to ICU_DATA when run AppImage.*/
+ char *exe_dir = IcuDataPath("/../share/icu");
+ auto FreeMemory = qScopeGuard([exe_dir] {free(exe_dir);});
+#endif // defined(APPIMAGE) && defined(Q_OS_LINUX)
- return a.exec();
+ Q_INIT_RESOURCE(puzzleicon);
+
+ QT_REQUIRE_VERSION(argc, argv, "5.4.0")// clazy:exclude=qstring-arg,qstring-allocations
+
+#if defined(Q_OS_WIN)
+ VAbstractApplication::WinAttachConsole();
+#endif
+
+#ifndef Q_OS_MAC // supports natively
+ InitHighDpiScaling(argc, argv);
+#endif //Q_OS_MAC
+
+ PuzzleApplication app(argc, argv);
+ app.InitOptions();
+
+ if (FvUpdater::IsStaledTestBuild())
+ {
+ qWarning() << QApplication::translate("Puzzle",
+ "This test build is older than %1 days. To provide you with better "
+ "quality service we restrict the lifetime you can use a test build. "
+ "To continue using Puzzle please update to newer test build. The "
+ "application will be shut down.")
+ .arg(FvUpdater::testBuildLifetime);
+ return V_EX_UNAVAILABLE;
+ }
+
+ QTimer::singleShot(0, &app, &PuzzleApplication::ProcessCMD);
+
+#if defined(APPIMAGE) && defined(Q_OS_LINUX)
+ if (exe_dir)
+ {
+ qDebug() << "Path to ICU folder:" << exe_dir;
+ }
+#endif // defined(APPIMAGE) && defined(Q_OS_LINUX)
+
+ return app.exec();
}
diff --git a/src/app/puzzle/puzzle.pri b/src/app/puzzle/puzzle.pri
index 863a4d1a2..101fff4e3 100644
--- a/src/app/puzzle/puzzle.pri
+++ b/src/app/puzzle/puzzle.pri
@@ -3,13 +3,15 @@
SOURCES += \
$$PWD/main.cpp \
- $$PWD/puzzlemainwindow.cpp
+ $$PWD/puzzlemainwindow.cpp \
+ $$PWD/puzzleapplication.cpp
*msvc*:SOURCES += $$PWD/stable.cpp
HEADERS += \
$$PWD/puzzlemainwindow.h \
- $$PWD/stable.h
+ $$PWD/stable.h \
+ $$PWD/puzzleapplication.h
FORMS += \
$$PWD/puzzlemainwindow.ui
diff --git a/src/app/puzzle/puzzle.pro b/src/app/puzzle/puzzle.pro
index b0255b2c2..7463ba832 100644
--- a/src/app/puzzle/puzzle.pro
+++ b/src/app/puzzle/puzzle.pro
@@ -7,7 +7,7 @@
# File with common stuff for whole project
include(../../../common.pri)
-QT += core gui widgets
+QT += core gui widgets network xml xmlpatterns printsupport
# Name of binary file
TARGET = puzzle
@@ -224,32 +224,32 @@ noRunPath{ # For enable run qmake with CONFIG+=noRunPath
#win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vpatterndb/$${DESTDIR}/vpatterndb.lib
#else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vpatterndb/$${DESTDIR}/libvpatterndb.a
-## Fervor static library (depend on VMisc, IFC)
-#unix|win32: LIBS += -L$$OUT_PWD/../../libs/fervor/$${DESTDIR}/ -lfervor
+# Fervor static library (depend on VMisc, IFC)
+unix|win32: LIBS += -L$$OUT_PWD/../../libs/fervor/$${DESTDIR}/ -lfervor
-#INCLUDEPATH += $$PWD/../../libs/fervor
-#DEPENDPATH += $$PWD/../../libs/fervor
+INCLUDEPATH += $$PWD/../../libs/fervor
+DEPENDPATH += $$PWD/../../libs/fervor
-#win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/fervor/$${DESTDIR}/fervor.lib
-#else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/fervor/$${DESTDIR}/libfervor.a
+win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/fervor/$${DESTDIR}/fervor.lib
+else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/fervor/$${DESTDIR}/libfervor.a
-## IFC static library (depend on QMuParser, VMisc)
-#unix|win32: LIBS += -L$$OUT_PWD/../../libs/ifc/$${DESTDIR}/ -lifc
+# IFC static library (depend on QMuParser, VMisc)
+unix|win32: LIBS += -L$$OUT_PWD/../../libs/ifc/$${DESTDIR}/ -lifc
-#INCLUDEPATH += $$PWD/../../libs/ifc
-#DEPENDPATH += $$PWD/../../libs/ifc
+INCLUDEPATH += $$PWD/../../libs/ifc
+DEPENDPATH += $$PWD/../../libs/ifc
-#win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/ifc/$${DESTDIR}/ifc.lib
-#else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/ifc/$${DESTDIR}/libifc.a
+win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/ifc/$${DESTDIR}/ifc.lib
+else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/ifc/$${DESTDIR}/libifc.a
-##VMisc static library
-#unix|win32: LIBS += -L$$OUT_PWD/../../libs/vmisc/$${DESTDIR}/ -lvmisc
+#VMisc static library
+unix|win32: LIBS += -L$$OUT_PWD/../../libs/vmisc/$${DESTDIR}/ -lvmisc
-#INCLUDEPATH += $$PWD/../../libs/vmisc
-#DEPENDPATH += $$PWD/../../libs/vmisc
+INCLUDEPATH += $$PWD/../../libs/vmisc
+DEPENDPATH += $$PWD/../../libs/vmisc
-#win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vmisc/$${DESTDIR}/vmisc.lib
-#else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vmisc/$${DESTDIR}/libvmisc.a
+win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vmisc/$${DESTDIR}/vmisc.lib
+else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vmisc/$${DESTDIR}/libvmisc.a
## VLayout static library (depend on VGeometry)
#unix|win32: LIBS += -L$$OUT_PWD/../../libs/vlayout/$${DESTDIR}/ -lvlayout
diff --git a/src/app/puzzle/puzzleapplication.cpp b/src/app/puzzle/puzzleapplication.cpp
new file mode 100644
index 000000000..a0a749d85
--- /dev/null
+++ b/src/app/puzzle/puzzleapplication.cpp
@@ -0,0 +1,635 @@
+/************************************************************************
+ **
+ ** @file puzzleapplication.cpp
+ ** @author Roman Telezhynskyi
+ ** @date 16 2, 2020
+ **
+ ** @brief
+ ** @copyright
+ ** This source code is part of the Valentina project, a pattern making
+ ** program, whose allow create and modeling patterns of clothing.
+ ** Copyright (C) 2020 Valentina project
+ ** All Rights Reserved.
+ **
+ ** Valentina is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** Valentina is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with Valentina. If not, see .
+ **
+ *************************************************************************/
+
+#include "puzzleapplication.h"
+#include "version.h"
+#include "puzzlemainwindow.h"
+#include "../ifc/exception/vexceptionobjecterror.h"
+#include "../ifc/exception/vexceptionbadid.h"
+#include "../ifc/exception/vexceptionconversionerror.h"
+#include "../ifc/exception/vexceptionemptyparameter.h"
+#include "../ifc/exception/vexceptionwrongid.h"
+#include "../vmisc/vsysexits.h"
+#include "../vmisc/diagnostic.h"
+#include "../vmisc/qt_dispatch/qt_dispatch.h"
+
+#include
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_CLANG("-Wmissing-prototypes")
+QT_WARNING_DISABLE_INTEL(1418)
+
+Q_LOGGING_CATEGORY(mApp, "m.application")
+
+QT_WARNING_POP
+
+#include
+#include
+#include
+
+//---------------------------------------------------------------------------------------------------------------------
+inline void noisyFailureMsgHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
+{
+ // only the GUI thread should display message boxes. If you are
+ // writing a multithreaded application and the error happens on
+ // a non-GUI thread, you'll have to queue the message to the GUI
+ QCoreApplication *instance = QCoreApplication::instance();
+ const bool isGuiThread = instance && (QThread::currentThread() == instance->thread());
+
+ if (not isGuiThread)
+ {
+ auto Handler = [](QtMsgType type, const QMessageLogContext &context, const QString &msg)
+ {
+ noisyFailureMsgHandler(type, context, msg);
+ };
+
+ q_dispatch_async_main(Handler, type, context, msg);
+ return;
+ }
+
+ // Why on earth didn't Qt want to make failed signal/slot connections qWarning?
+ if ((type == QtDebugMsg) && msg.contains(QStringLiteral("::connect")))
+ {
+ type = QtWarningMsg;
+ }
+
+#if defined(V_NO_ASSERT)
+ // I have decided to hide this annoing message for release builds.
+ if ((type == QtWarningMsg) && msg.contains(QStringLiteral("QSslSocket: cannot resolve")))
+ {
+ type = QtDebugMsg;
+ }
+
+ if ((type == QtWarningMsg) && msg.contains(QStringLiteral("setGeometry: Unable to set geometry")))
+ {
+ type = QtDebugMsg;
+ }
+#endif //defined(V_NO_ASSERT)
+
+#if defined(Q_OS_MAC)
+# if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) && QT_VERSION < QT_VERSION_CHECK(5, 7, 0)
+ // Try hide very annoying, Qt related, warnings in Mac OS X
+ // QNSView mouseDragged: Internal mouse button tracking invalid (missing Qt::LeftButton)
+ // https://bugreports.qt.io/browse/QTBUG-42846
+ if ((type == QtWarningMsg) && msg.contains(QStringLiteral("QNSView")))
+ {
+ type = QtDebugMsg;
+ }
+# endif
+
+ // Hide Qt bug 'Assertion when reading an icns file'
+ // https://bugreports.qt.io/browse/QTBUG-45537
+ // Remove after Qt fix will be released
+ if ((type == QtWarningMsg) && msg.contains(QStringLiteral("QICNSHandler::read()")))
+ {
+ type = QtDebugMsg;
+ }
+
+ // See issue #568
+ if (msg.contains(QStringLiteral("Error receiving trust for a CA certificate")))
+ {
+ type = QtDebugMsg;
+ }
+#endif
+
+ // this is another one that doesn't make sense as just a debug message. pretty serious
+ // sign of a problem
+ // http://www.developer.nokia.com/Community/Wiki/QPainter::begin:Paint_device_returned_engine_%3D%3D_0_(Known_Issue)
+ if ((type == QtDebugMsg) && msg.contains(QStringLiteral("QPainter::begin"))
+ && msg.contains(QStringLiteral("Paint device returned engine")))
+ {
+ type = QtWarningMsg;
+ }
+
+ // This qWarning about "Cowardly refusing to send clipboard message to hung application..."
+ // is something that can easily happen if you are debugging and the application is paused.
+ // As it is so common, not worth popping up a dialog.
+ if ((type == QtWarningMsg) && msg.contains(QStringLiteral("QClipboard::event"))
+ && msg.contains(QStringLiteral("Cowardly refusing")))
+ {
+ type = QtDebugMsg;
+ }
+
+ switch (type)
+ {
+ case QtDebugMsg:
+ vStdOut() << QApplication::translate("mNoisyHandler", "DEBUG:") << msg << "\n";
+ return;
+ case QtWarningMsg:
+ vStdErr() << QApplication::translate("mNoisyHandler", "WARNING:") << msg << "\n";
+ break;
+ case QtCriticalMsg:
+ vStdErr() << QApplication::translate("mNoisyHandler", "CRITICAL:") << msg << "\n";
+ break;
+ case QtFatalMsg:
+ vStdErr() << QApplication::translate("mNoisyHandler", "FATAL:") << msg << "\n";
+ break;
+ #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
+ case QtInfoMsg:
+ vStdOut() << QApplication::translate("mNoisyHandler", "INFO:") << msg << "\n";
+ break;
+ #endif
+ default:
+ break;
+ }
+
+ vStdOut().flush();
+ vStdErr().flush();
+
+ if (isGuiThread)
+ {
+ //fixme: trying to make sure there are no save/load dialogs are opened, because error message during them will
+ //lead to crash
+ const bool topWinAllowsPop = (QApplication::activeModalWidget() == nullptr) ||
+ !QApplication::activeModalWidget()->inherits("QFileDialog");
+ QMessageBox messageBox;
+ switch (type)
+ {
+ case QtWarningMsg:
+ messageBox.setWindowTitle(QApplication::translate("mNoisyHandler", "Warning"));
+ messageBox.setIcon(QMessageBox::Warning);
+ break;
+ case QtCriticalMsg:
+ messageBox.setWindowTitle(QApplication::translate("mNoisyHandler", "Critical error"));
+ messageBox.setIcon(QMessageBox::Critical);
+ break;
+ case QtFatalMsg:
+ messageBox.setWindowTitle(QApplication::translate("mNoisyHandler", "Fatal error"));
+ messageBox.setIcon(QMessageBox::Critical);
+ break;
+ #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
+ case QtInfoMsg:
+ messageBox.setWindowTitle(QApplication::translate("mNoisyHandler", "Information"));
+ messageBox.setIcon(QMessageBox::Information);
+ break;
+ #endif
+ case QtDebugMsg:
+ Q_UNREACHABLE(); //-V501
+ break;
+ default:
+ break;
+ }
+
+ if (type == QtWarningMsg || type == QtCriticalMsg || type == QtFatalMsg)
+ {
+ if (not qApp->IsTestMode())
+ {
+ if (topWinAllowsPop)
+ {
+ messageBox.setText(VAbstractApplication::ClearMessage(msg));
+ messageBox.setStandardButtons(QMessageBox::Ok);
+ messageBox.setWindowModality(Qt::ApplicationModal);
+ messageBox.setModal(true);
+ #ifndef QT_NO_CURSOR
+ QGuiApplication::setOverrideCursor(Qt::ArrowCursor);
+ #endif
+ messageBox.exec();
+ #ifndef QT_NO_CURSOR
+ QGuiApplication::restoreOverrideCursor();
+ #endif
+ }
+ }
+ }
+
+ if (QtFatalMsg == type)
+ {
+ abort();
+ }
+ }
+ else
+ {
+ if (type != QtDebugMsg)
+ {
+ abort(); // be NOISY unless overridden!
+ }
+ }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+PuzzleApplication::PuzzleApplication(int &argc, char **argv)
+ :VAbstractApplication(argc, argv),
+ mainWindows(),
+ localServer(nullptr),
+ testMode(false)
+{
+ setApplicationDisplayName(VER_PRODUCTNAME_STR);
+ setApplicationName(VER_INTERNALNAME_STR);
+ setOrganizationName(VER_COMPANYNAME_STR);
+ setOrganizationDomain(VER_COMPANYDOMAIN_STR);
+ // Setting the Application version
+ setApplicationVersion(APP_VERSION_STR);
+ // We have been running Puzzle in two different cases.
+ // The first inside own bundle where info.plist is works fine, but the second,
+ // when we run inside Valentina's bundle, require direct setting the icon.
+ setWindowIcon(QIcon(":/puzzleicon/64x64/logo.png"));
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+PuzzleApplication::~PuzzleApplication()
+{
+ qDeleteAll(mainWindows);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief notify Reimplemented from QApplication::notify().
+ * @param receiver receiver.
+ * @param event event.
+ * @return value that is returned from the receiver's event handler.
+ */
+// reimplemented from QApplication so we can throw exceptions in slots
+bool PuzzleApplication::notify(QObject *receiver, QEvent *event)
+{
+ try
+ {
+ return QApplication::notify(receiver, event);
+ }
+ catch (const VExceptionObjectError &e)
+ {
+ qCCritical(mApp, "%s\n\n%s\n\n%s", qUtf8Printable(tr("Error parsing file. Program will be terminated.")), //-V807
+ qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
+ exit(V_EX_DATAERR);
+ }
+ catch (const VExceptionBadId &e)
+ {
+ qCCritical(mApp, "%s\n\n%s\n\n%s", qUtf8Printable(tr("Error bad id. Program will be terminated.")),
+ qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
+ exit(V_EX_DATAERR);
+ }
+ catch (const VExceptionConversionError &e)
+ {
+ qCCritical(mApp, "%s\n\n%s\n\n%s", qUtf8Printable(tr("Error can't convert value. Program will be terminated.")),
+ qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
+ exit(V_EX_DATAERR);
+ }
+ catch (const VExceptionEmptyParameter &e)
+ {
+ qCCritical(mApp, "%s\n\n%s\n\n%s", qUtf8Printable(tr("Error empty parameter. Program will be terminated.")),
+ qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
+ exit(V_EX_DATAERR);
+ }
+ catch (const VExceptionWrongId &e)
+ {
+ qCCritical(mApp, "%s\n\n%s\n\n%s", qUtf8Printable(tr("Error wrong id. Program will be terminated.")),
+ qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
+ exit(V_EX_DATAERR);
+ }
+ catch (const VExceptionToolWasDeleted &e)
+ {
+ qCCritical(mApp, "%s\n\n%s\n\n%s",
+ qUtf8Printable("Unhadled deleting tool. Continue use object after deleting!"),
+ qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
+ exit(V_EX_DATAERR);
+ }
+ catch (const VException &e)
+ {
+ qCCritical(mApp, "%s\n\n%s\n\n%s", qUtf8Printable(tr("Something's wrong!!")),
+ qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation()));
+ return true;
+ }
+ catch (std::exception &e)
+ {
+ qCCritical(mApp, "%s", qUtf8Printable(tr("Exception thrown: %1. Program will be terminated.").arg(e.what())));
+ exit(V_EX_SOFTWARE);
+ }
+ return false;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool PuzzleApplication::IsTestMode() const
+{
+ return testMode;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+/**
+ * @brief IsAppInGUIMode little hack that allow to have access to application state from VAbstractApplication class.
+ */
+bool PuzzleApplication::IsAppInGUIMode() const
+{
+ return IsTestMode();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+PuzzleMainWindow *PuzzleApplication::MainWindow()
+{
+ Clean();
+ if (mainWindows.isEmpty())
+ {
+ NewMainWindow();
+ }
+ return mainWindows[0];
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+QList PuzzleApplication::MainWindows()
+{
+ Clean();
+ QList list;
+ for (auto &w : mainWindows)
+ {
+ list.append(w);
+ }
+ return list;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+PuzzleMainWindow *PuzzleApplication::NewMainWindow()
+{
+ PuzzleMainWindow *puzzle = new PuzzleMainWindow();
+ mainWindows.prepend(puzzle);
+ if (not qApp->IsTestMode())
+ {
+ puzzle->show();
+ }
+ return puzzle;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void PuzzleApplication::InitOptions()
+{
+ qInstallMessageHandler(noisyFailureMsgHandler);
+
+ OpenSettings();
+
+ qCDebug(mApp, "Version: %s", qUtf8Printable(APP_VERSION_STR));
+ qCDebug(mApp, "Build revision: %s", BUILD_REVISION);
+ qCDebug(mApp, "%s", qUtf8Printable(buildCompatibilityString()));
+ qCDebug(mApp, "Built on %s at %s", __DATE__, __TIME__);
+ qCDebug(mApp, "Command-line arguments: %s", qUtf8Printable(arguments().join(", ")));
+ qCDebug(mApp, "Process ID: %s", qUtf8Printable(QString().setNum(applicationPid())));
+
+ LoadTranslation(QLocale().name());// By default the console version uses system locale
+
+ static const char * GENERIC_ICON_TO_CHECK = "document-open";
+ if (QIcon::hasThemeIcon(GENERIC_ICON_TO_CHECK) == false)
+ {
+ //If there is no default working icon theme then we should
+ //use an icon theme that we provide via a .qrc file
+ //This case happens under Windows and Mac OS X
+ //This does not happen under GNOME or KDE
+ QIcon::setThemeName("win.icon.theme");
+ }
+ ActivateDarkMode();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+const VTranslateVars *PuzzleApplication::TrVars()
+{
+ return nullptr;
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void PuzzleApplication::OpenSettings()
+{
+ settings = new VPuzzleSettings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(),
+ QCoreApplication::applicationName(), this);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+VPuzzleSettings *PuzzleApplication::PuzzleSettings()
+{
+ SCASSERT(settings != nullptr)
+ return qobject_cast(settings);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void PuzzleApplication::ActivateDarkMode()
+{
+ VPuzzleSettings *settings = qApp->PuzzleSettings();
+ if (settings->GetDarkMode())
+ {
+ QFile f(":qdarkstyle/style.qss");
+ if (!f.exists())
+ {
+ qDebug()<<"Unable to set stylesheet, file not found\n";
+ }
+ else
+ {
+ f.open(QFile::ReadOnly | QFile::Text);
+ QTextStream ts(&f);
+ qApp->setStyleSheet(ts.readAll());
+ }
+ }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void PuzzleApplication::ParseCommandLine(const SocketConnection &connection, const QStringList &arguments)
+{
+ QCommandLineParser parser;
+ parser.setApplicationDescription(tr("Valentina's manual layout editor."));
+ parser.addHelpOption();
+ parser.addVersionOption();
+ parser.addPositionalArgument("filename", tr("The raw layout file."));
+ //-----
+ QCommandLineOption testOption(QStringList() << "test",
+ tr("Use for unit testing. Run the program and open a file without showing the main window."));
+ parser.addOption(testOption);
+ //-----
+ QCommandLineOption scalingOption(QStringList() << LONG_OPTION_NO_HDPI_SCALING,
+ tr("Disable high dpi scaling. Call this option if has problem with scaling (by default scaling enabled). "
+ "Alternatively you can use the %1 environment variable.").arg("QT_AUTO_SCREEN_SCALE_FACTOR=0"));
+ parser.addOption(scalingOption);
+ //-----
+ parser.process(arguments);
+
+ testMode = parser.isSet(testOption);
+
+ if (not testMode && connection == SocketConnection::Client)
+ {
+ const QString serverName = QCoreApplication::applicationName();
+ QLocalSocket socket;
+ socket.connectToServer(serverName);
+ if (socket.waitForConnected(1000))
+ {
+ qCDebug(mApp, "Connected to the server '%s'", qUtf8Printable(serverName));
+ QTextStream stream(&socket);
+ stream << QCoreApplication::arguments().join(";;");
+ stream.flush();
+ socket.waitForBytesWritten();
+ qApp->exit(V_EX_OK);
+ return;
+ }
+
+ qCDebug(mApp, "Can't establish connection to the server '%s'", qUtf8Printable(serverName));
+
+ localServer = new QLocalServer(this);
+ connect(localServer, &QLocalServer::newConnection, this, &PuzzleApplication::NewLocalSocketConnection);
+ if (not localServer->listen(serverName))
+ {
+ qCDebug(mApp, "Can't begin to listen for incoming connections on name '%s'",
+ qUtf8Printable(serverName));
+ if (localServer->serverError() == QAbstractSocket::AddressInUseError)
+ {
+ QLocalServer::removeServer(serverName);
+ if (not localServer->listen(serverName))
+ {
+ qCWarning(mApp, "%s",
+ qUtf8Printable(tr("Can't begin to listen for incoming connections on name '%1'").arg(serverName)));
+ }
+ }
+ }
+
+ LoadTranslation(PuzzleSettings()->GetLocale());
+ }
+
+ const QStringList args = parser.positionalArguments();
+ if (args.count() > 0)
+ {
+ if (testMode && args.count() > 1)
+ {
+ qCCritical(mApp, "%s\n", qPrintable(tr("Test mode doesn't support openning several files.")));
+ parser.showHelp(V_EX_USAGE);
+ }
+
+ for (auto &arg : args)
+ {
+ NewMainWindow();
+ if (not MainWindow()->LoadFile(arg))
+ {
+ if (testMode)
+ {
+ return; // process only one input file
+ }
+ delete MainWindow();
+ continue;
+ }
+ }
+ }
+ else
+ {
+ if (not testMode)
+ {
+ NewMainWindow();
+ }
+ else
+ {
+ qCCritical(mApp, "%s\n", qPrintable(tr("Please, provide one input file.")));
+ parser.showHelp(V_EX_USAGE);
+ }
+ }
+
+ if (testMode)
+ {
+ qApp->exit(V_EX_OK); // close program after processing in console mode
+ }
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void PuzzleApplication::ProcessCMD()
+{
+ ParseCommandLine(SocketConnection::Client, arguments());
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool PuzzleApplication::event(QEvent *e)
+{
+ switch(e->type())
+ {
+ // In Mac OS X the QFileOpenEvent event is generated when user perform "Open With" from Finder (this event is
+ // Mac specific).
+ case QEvent::FileOpen:
+ {
+ QFileOpenEvent *fileOpenEvent = static_cast(e);
+ const QString macFileOpen = fileOpenEvent->file();
+ if(not macFileOpen.isEmpty())
+ {
+ PuzzleMainWindow *mw = MainWindow();
+ if (mw)
+ {
+ mw->LoadFile(macFileOpen); // open file in existing window
+ }
+ return true;
+ }
+ break;
+ }
+#if defined(Q_OS_MAC)
+ case QEvent::ApplicationActivate:
+ {
+ Clean();
+ PuzzleMainWindow *mw = PuzzleMainWindow();
+ if (mw && not mw->isMinimized())
+ {
+ mw->show();
+ }
+ return true;
+ }
+#endif //defined(Q_OS_MAC)
+ default:
+ return VAbstractApplication::event(e);
+ }
+ return VAbstractApplication::event(e);
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void PuzzleApplication::InitTrVars()
+{
+ // do nothing
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void PuzzleApplication::AboutToQuit()
+{
+ // If try to use the method QApplication::exit program can't sync settings and show warning about QApplication
+ // instance. Solution is to call sync() before quit.
+ // Connect this slot with VApplication::aboutToQuit.
+ Settings()->sync();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void PuzzleApplication::NewLocalSocketConnection()
+{
+ QLocalSocket *socket = localServer->nextPendingConnection();
+ if (not socket)
+ {
+ return;
+ }
+ socket->waitForReadyRead(1000);
+ QTextStream stream(socket);
+ const QString arg = stream.readAll();
+ if (not arg.isEmpty())
+ {
+ ParseCommandLine(SocketConnection::Server, arg.split(";;"));
+ }
+ delete socket;
+ MainWindow()->raise();
+ MainWindow()->activateWindow();
+}
+
+//---------------------------------------------------------------------------------------------------------------------
+void PuzzleApplication::Clean()
+{
+ // cleanup any deleted main windows first
+ for (int i = mainWindows.count() - 1; i >= 0; --i)
+ {
+ if (mainWindows.at(i).isNull())
+ {
+ mainWindows.removeAt(i);
+ }
+ }
+}
diff --git a/src/app/puzzle/puzzleapplication.h b/src/app/puzzle/puzzleapplication.h
new file mode 100644
index 000000000..9f2b15760
--- /dev/null
+++ b/src/app/puzzle/puzzleapplication.h
@@ -0,0 +1,94 @@
+/************************************************************************
+ **
+ ** @file puzzleapplication.h
+ ** @author Roman Telezhynskyi
+ ** @date 16 2, 2020
+ **
+ ** @brief
+ ** @copyright
+ ** This source code is part of the Valentina project, a pattern making
+ ** program, whose allow create and modeling patterns of clothing.
+ ** Copyright (C) 2020 Valentina project
+ ** All Rights Reserved.
+ **
+ ** Valentina is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** Valentina is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with Valentina. If not, see .
+ **
+ *************************************************************************/
+#ifndef PUZZLEAPPLICATION_H
+#define PUZZLEAPPLICATION_H
+
+#include "../vmisc/def.h"
+#include "../vmisc/vpuzzlesettings.h"
+#include "../vmisc/vabstractapplication.h"
+
+class PuzzleApplication;// use in define
+class PuzzleMainWindow;
+class QLocalServer;
+
+#if defined(qApp)
+#undef qApp
+#endif
+#define qApp (static_cast(VAbstractApplication::instance()))
+
+enum class SocketConnection : bool {Client = false, Server = true};
+
+class PuzzleApplication : public VAbstractApplication
+{
+ Q_OBJECT
+public:
+ PuzzleApplication(int &argc, char **argv);
+ virtual ~PuzzleApplication() override;
+
+ virtual bool notify(QObject * receiver, QEvent * event) override;
+
+ bool IsTestMode() const;
+ virtual bool IsAppInGUIMode() const override;
+ PuzzleMainWindow *MainWindow();
+ QList MainWindows();
+ PuzzleMainWindow *NewMainWindow();
+
+ void InitOptions();
+
+
+ virtual const VTranslateVars *TrVars() override;
+
+ virtual void OpenSettings() override;
+ VPuzzleSettings *PuzzleSettings();
+ void ActivateDarkMode();
+
+ void ParseCommandLine(const SocketConnection &connection, const QStringList &arguments);
+
+public slots:
+ void ProcessCMD();
+
+protected:
+ virtual void InitTrVars() override;
+ virtual bool event(QEvent *e) override;
+
+protected slots:
+ virtual void AboutToQuit() override;
+
+private slots:
+ void NewLocalSocketConnection();
+
+private:
+ Q_DISABLE_COPY(PuzzleApplication)
+ QList > mainWindows;
+ QLocalServer *localServer;
+ bool testMode;
+
+ void Clean();
+};
+
+#endif // PUZZLEAPPLICATION_H
diff --git a/src/app/puzzle/puzzlemainwindow.cpp b/src/app/puzzle/puzzlemainwindow.cpp
index 2c0321e4c..d690f7918 100644
--- a/src/app/puzzle/puzzlemainwindow.cpp
+++ b/src/app/puzzle/puzzlemainwindow.cpp
@@ -28,6 +28,7 @@
#include "puzzlemainwindow.h"
#include "ui_puzzlemainwindow.h"
+//---------------------------------------------------------------------------------------------------------------------
PuzzleMainWindow::PuzzleMainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::PuzzleMainWindow)
@@ -35,7 +36,14 @@ PuzzleMainWindow::PuzzleMainWindow(QWidget *parent) :
ui->setupUi(this);
}
+//---------------------------------------------------------------------------------------------------------------------
PuzzleMainWindow::~PuzzleMainWindow()
{
delete ui;
}
+
+//---------------------------------------------------------------------------------------------------------------------
+bool PuzzleMainWindow::LoadFile(const QString &path)
+{
+
+}
diff --git a/src/app/puzzle/puzzlemainwindow.h b/src/app/puzzle/puzzlemainwindow.h
index bf1943946..8f489647d 100644
--- a/src/app/puzzle/puzzlemainwindow.h
+++ b/src/app/puzzle/puzzlemainwindow.h
@@ -42,6 +42,8 @@ public:
explicit PuzzleMainWindow(QWidget *parent = nullptr);
virtual ~PuzzleMainWindow();
+ bool LoadFile(const QString &path);
+
private:
Q_DISABLE_COPY(PuzzleMainWindow)
Ui::PuzzleMainWindow *ui;
diff --git a/src/app/puzzle/stable.cpp b/src/app/puzzle/stable.cpp
new file mode 100644
index 000000000..460b5cb9c
--- /dev/null
+++ b/src/app/puzzle/stable.cpp
@@ -0,0 +1,30 @@
+/************************************************************************
+ **
+ ** @file stable.cpp
+ ** @author Roman Telezhynskyi
+ ** @date November 15, 2013
+ **
+ ** @brief
+ ** @copyright
+ ** This source code is part of the Valentina project, a pattern making
+ ** program, whose allow create and modeling patterns of clothing.
+ ** Copyright (C) 2013-2015 Valentina project
+ ** All Rights Reserved.
+ **
+ ** Valentina is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** Valentina is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with Valentina. If not, see .
+ **
+ *************************************************************************/
+
+// Build the precompiled headers.
+#include "stable.h"
diff --git a/src/app/puzzle/stable.h b/src/app/puzzle/stable.h
new file mode 100644
index 000000000..4611a10a7
--- /dev/null
+++ b/src/app/puzzle/stable.h
@@ -0,0 +1,72 @@
+/************************************************************************
+ **
+ ** @file stable.h
+ ** @author Roman Telezhynskyi
+ ** @date November 15, 2013
+ **
+ ** @brief
+ ** @copyright
+ ** This source code is part of the Valentina project, a pattern making
+ ** program, whose allow create and modeling patterns of clothing.
+ ** Copyright (C) 2013-2015 Valentina project
+ ** All Rights Reserved.
+ **
+ ** Valentina is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** Valentina is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with Valentina. If not, see .
+ **
+ *************************************************************************/
+
+#ifndef STABLE_H
+#define STABLE_H
+
+/* I like to include this pragma too, so the build log indicates if pre-compiled headers were in use. */
+#pragma message("Compiling precompiled headers for tape utility.\n")
+
+/* Add C includes here */
+
+#if defined __cplusplus
+/* Add C++ includes here */
+#include
+
+/*In all cases we need include core header for getting defined values*/
+#ifdef QT_CORE_LIB
+# include
+#endif
+
+#ifdef QT_GUI_LIB
+# include
+#endif
+
+#ifdef QT_XML_LIB
+# include
+#endif
+
+//In Windows you can't use same header in all modes.
+#if !defined(Q_OS_WIN)
+# ifdef QT_WIDGETS_LIB
+# include
+# endif
+
+ //Build doesn't work, if include this headers on Windows.
+# ifdef QT_XMLPATTERNS_LIB
+# include
+# endif
+
+# ifdef QT_NETWORK_LIB
+# include
+# endif
+#endif/*Q_OS_WIN*/
+
+#endif /*__cplusplus*/
+
+#endif // STABLE_H
diff --git a/src/app/puzzle/version.h b/src/app/puzzle/version.h
new file mode 100644
index 000000000..76e256844
--- /dev/null
+++ b/src/app/puzzle/version.h
@@ -0,0 +1,39 @@
+/************************************************************************
+ **
+ ** @file version.h
+ ** @author Roman Telezhynskyi
+ ** @date November 15, 2013
+ **
+ ** @brief
+ ** @copyright
+ ** This source code is part of the Valentina project, a pattern making
+ ** program, whose allow create and modeling patterns of clothing.
+ ** Copyright (C) 2013-2015 Valentina project
+ ** All Rights Reserved.
+ **
+ ** Valentina is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** Valentina is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with Valentina. If not, see .
+ **
+ *************************************************************************/
+
+#ifndef VERSION_H
+#define VERSION_H
+
+#include "../../libs/vmisc/projectversion.h"
+
+#define VER_INTERNALNAME_STR "Puzzle"
+#define VER_ORIGINALFILENAME_STR "puzzle.exe"
+#define VER_PRODUCTNAME_STR "Tape"
+#define VER_FILEDESCRIPTION_STR "Valentina's manual layout creator."
+
+#endif // VERSION_H
diff --git a/src/app/tape/mapplication.cpp b/src/app/tape/mapplication.cpp
index 385ea06b8..2eb7d73e9 100644
--- a/src/app/tape/mapplication.cpp
+++ b/src/app/tape/mapplication.cpp
@@ -412,8 +412,9 @@ void MApplication::InitOptions()
ActivateDarkMode();
QResource::registerResource(diagramsPath());
}
-// Dark mode
+//---------------------------------------------------------------------------------------------------------------------
+// Dark mode
void MApplication::ActivateDarkMode()
{
VTapeSettings *settings = qApp->TapeSettings();
diff --git a/src/app/tape/mapplication.h b/src/app/tape/mapplication.h
index dc8cea765..a121ced88 100644
--- a/src/app/tape/mapplication.h
+++ b/src/app/tape/mapplication.h
@@ -68,7 +68,7 @@ public:
virtual void OpenSettings() override;
VTapeSettings *TapeSettings();
- void ActivateDarkMode();
+ void ActivateDarkMode();
QString diagramsPath() const;
diff --git a/src/libs/vmisc/vmisc.pri b/src/libs/vmisc/vmisc.pri
index e62231411..c91baa68f 100644
--- a/src/libs/vmisc/vmisc.pri
+++ b/src/libs/vmisc/vmisc.pri
@@ -13,7 +13,8 @@ SOURCES += \
$$PWD/vtablesearch.cpp \
$$PWD/dialogs/dialogexporttocsv.cpp \
$$PWD/literals.cpp \
- $$PWD/vmodifierkey.cpp
+ $$PWD/vmodifierkey.cpp \
+ $$PWD/vpuzzlesettings.cpp
*msvc*:SOURCES += $$PWD/stable.cpp
@@ -50,7 +51,8 @@ HEADERS += \
$$PWD/vdatastreamenum.h \
$$PWD/vmodifierkey.h \
$$PWD/typedef.h \
- $$PWD/backport/qscopeguard.h
+ $$PWD/backport/qscopeguard.h \
+ $$PWD/vpuzzlesettings.h
contains(DEFINES, APPIMAGE) {
SOURCES += \
diff --git a/src/libs/vmisc/vpuzzlesettings.cpp b/src/libs/vmisc/vpuzzlesettings.cpp
new file mode 100644
index 000000000..337fcb69a
--- /dev/null
+++ b/src/libs/vmisc/vpuzzlesettings.cpp
@@ -0,0 +1,37 @@
+/************************************************************************
+ **
+ ** @file vpuzzlesettings.cpp
+ ** @author Roman Telezhynskyi
+ ** @date 16 2, 2020
+ **
+ ** @brief
+ ** @copyright
+ ** This source code is part of the Valentina project, a pattern making
+ ** program, whose allow create and modeling patterns of clothing.
+ ** Copyright (C) 2020 Valentina project
+ ** All Rights Reserved.
+ **
+ ** Valentina is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** Valentina is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with Valentina. If not, see .
+ **
+ *************************************************************************/
+#include "vpuzzlesettings.h"
+
+
+//---------------------------------------------------------------------------------------------------------------------
+VPuzzleSettings::VPuzzleSettings(Format format, Scope scope, const QString &organization, const QString &application,
+ QObject *parent)
+ :VCommonSettings(format, scope, organization, application, parent)
+{
+
+}
diff --git a/src/libs/vmisc/vpuzzlesettings.h b/src/libs/vmisc/vpuzzlesettings.h
new file mode 100644
index 000000000..f4ab19b01
--- /dev/null
+++ b/src/libs/vmisc/vpuzzlesettings.h
@@ -0,0 +1,46 @@
+/************************************************************************
+ **
+ ** @file vpuzzlesettings.h
+ ** @author Roman Telezhynskyi
+ ** @date 16 2, 2020
+ **
+ ** @brief
+ ** @copyright
+ ** This source code is part of the Valentina project, a pattern making
+ ** program, whose allow create and modeling patterns of clothing.
+ ** Copyright (C) 2020 Valentina project
+ ** All Rights Reserved.
+ **
+ ** Valentina is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** Valentina is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with Valentina. If not, see .
+ **
+ *************************************************************************/
+#ifndef VPUZZLESETTINGS_H
+#define VPUZZLESETTINGS_H
+
+#include
+
+#include "vcommonsettings.h"
+
+class VPuzzleSettings : public VCommonSettings
+{
+ Q_OBJECT
+public:
+ VPuzzleSettings(Format format, Scope scope, const QString &organization, const QString &application = QString(),
+ QObject *parent = nullptr);
+
+private:
+ Q_DISABLE_COPY(VPuzzleSettings)
+};
+
+#endif // VPUZZLESETTINGS_H