diff --git a/AUTHORS.txt b/AUTHORS.txt index b245f676b..697abc497 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -26,4 +26,9 @@ Patch contributors: * Mac OS package. Peter Gsellmann * Testing - + Alex Zaharov + * Developing. + Valentina Zhuravska + * Developing. + * Testing. + * Translation. diff --git a/src/app/tape/mapplication.cpp b/src/app/tape/mapplication.cpp index 0533b44c9..87b529e9d 100644 --- a/src/app/tape/mapplication.cpp +++ b/src/app/tape/mapplication.cpp @@ -38,6 +38,8 @@ #include #include #include +#include +#include #if QT_VERSION < QT_VERSION_CHECK(5, 2, 0) # include "../../libs/vmisc/backport/qcommandlineparser.h" @@ -45,6 +47,91 @@ # include #endif +//--------------------------------------------------------------------------------------------------------------------- +inline void noisyFailureMsgHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) +{ + Q_UNUSED(context) + + // Why on earth didn't Qt want to make failed signal/slot connections qWarning? + if ((type == QtDebugMsg) && msg.contains("::connect")) + { + type = QtWarningMsg; + } + + // 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("QPainter::begin") && msg.contains("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) && QString(msg).contains("QClipboard::event") + && QString(msg).contains("Cowardly refusing")) + { + type = QtDebugMsg; + } + + // 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 (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 = (qApp->activeModalWidget() == nullptr) || + !qApp->activeModalWidget()->inherits("QFileDialog"); + QMessageBox messageBox; + switch (type) + { + case QtDebugMsg: + std::cerr << msg.toUtf8().constData() << std::endl; + return; + case QtWarningMsg: + messageBox.setIcon(QMessageBox::Warning); + break; + case QtCriticalMsg: + messageBox.setIcon(QMessageBox::Critical); + break; + case QtFatalMsg: + messageBox.setIcon(QMessageBox::Critical); + break; + default: + break; + } + + if (type == QtWarningMsg || type == QtCriticalMsg || type == QtFatalMsg) + { + if (topWinAllowsPop) + { + messageBox.setInformativeText(msg); + messageBox.setStandardButtons(QMessageBox::Ok); + messageBox.setWindowModality(Qt::ApplicationModal); + messageBox.setModal(true); + messageBox.exec(); + } + } + + if (QtFatalMsg == type) + { + abort(); + } + } + else + { + if (type != QtDebugMsg) + { + abort(); // be NOISY unless overridden! + } + } +} + //--------------------------------------------------------------------------------------------------------------------- MApplication::MApplication(int &argc, char **argv) :VAbstractApplication(argc, argv), @@ -138,6 +225,8 @@ QList MApplication::MainWindows() //--------------------------------------------------------------------------------------------------------------------- void MApplication::InitOptions() { + qInstallMessageHandler(noisyFailureMsgHandler); + OpenSettings(); qDebug()<<"Version:"< #include #include -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) -# include -#endif #define DIALOG_MAX_FORMULA_HEIGHT 64 @@ -70,9 +68,11 @@ TMainWindow::TMainWindow(QWidget *parent) gradationSizes(nullptr), comboBoxUnits(nullptr), formulaBaseHeight(0), - lock(nullptr) + lock(nullptr), + search() { ui->setupUi(this); + search = QSharedPointer(new VTableSearch(ui->tableWidget)); ui->tabWidget->setVisible(false); ui->mainToolBar->setContextMenuPolicy(Qt::PreventContextMenu); @@ -98,10 +98,6 @@ TMainWindow::~TMainWindow() delete m; } -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) - delete lock; // Unlock pattern file -#endif - delete ui; } @@ -182,18 +178,14 @@ void TMainWindow::LoadFile(const QString &path) } } -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) - lock = new QLockFile(QFileInfo(path).fileName()+".lock"); - lock->setStaleLockTime(0); - if (not MApplication::TryLock(lock)) + VlpCreateLock(lock, QFileInfo(path).fileName()+".lock"); + + if (lock->GetLockError() == QLockFile::LockFailedError) { - if (lock->error() == QLockFile::LockFailedError) - { - qCCritical(tMainWindow, "%s", tr("This file already opened in another window.").toUtf8().constData()); - return; - } + qCCritical(tMainWindow, "%s", tr("This file already opened in another window.").toUtf8().constData()); + lock.reset(); + return; } -#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) try { @@ -257,6 +249,7 @@ void TMainWindow::LoadFile(const QString &path) m = nullptr; delete data; data = nullptr; + lock.reset(); return; } } @@ -361,6 +354,24 @@ void TMainWindow::OpenTemplate() } } +//--------------------------------------------------------------------------------------------------------------------- +void TMainWindow::Find(const QString &term) +{ + search->Find(term); +} + +//--------------------------------------------------------------------------------------------------------------------- +void TMainWindow::FindPrevious() +{ + search->FindPrevious(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void TMainWindow::FindNext() +{ + search->FindNext(); +} + //--------------------------------------------------------------------------------------------------------------------- void TMainWindow::closeEvent(QCloseEvent *event) { @@ -462,6 +473,22 @@ void TMainWindow::FileSaveAs() { fileName += "." + suffix; } + + if (QFileInfo(fileName).exists()) + { + VLockGuard tmp(fileName + ".lock"); + + if (not tmp.IsLocked()) + { + if (lock->GetLockError() == QLockFile::LockFailedError) + { + qCCritical(tMainWindow, "%s", tr("Failed to lock. This file already opened in another window.") + .toUtf8().constData()); + return; + } + } + } + QString error; bool result = SaveMeasurements(fileName, error); if (result == false) @@ -473,6 +500,20 @@ void TMainWindow::FileSaveAs() messageBox.setDetailedText(error); messageBox.setStandardButtons(QMessageBox::Ok); messageBox.exec(); + + return; + } + + lock.reset(); + + VlpCreateLock(lock, fileName + ".lock"); + + if (lock->GetLockError() == QLockFile::LockFailedError) + { + qCCritical(tMainWindow, "%s", tr("Failed to lock. This file already opened in another window. " + "Expect collissions when run 2 copies of the program.").toUtf8().constData()); + lock.reset(); + return; } } @@ -613,7 +654,9 @@ void TMainWindow::Remove() MeasurementsWasSaved(false); + search->RemoveRow(row); RefreshData(); + search->RefreshList(ui->lineEditFind->text()); if (ui->tableWidget->rowCount() > 0) { @@ -679,6 +722,7 @@ void TMainWindow::MoveUp() m->MoveUp(nameField->text()); MeasurementsWasSaved(false); RefreshData(); + search->RefreshList(ui->lineEditFind->text()); ui->tableWidget->selectRow(row-1); } @@ -696,6 +740,7 @@ void TMainWindow::MoveDown() m->MoveDown(nameField->text()); MeasurementsWasSaved(false); RefreshData(); + search->RefreshList(ui->lineEditFind->text()); ui->tableWidget->selectRow(row+1); } @@ -730,6 +775,8 @@ void TMainWindow::Fx() RefreshData(); + search->RefreshList(ui->lineEditFind->text()); + ui->tableWidget->selectRow(row); } delete dialog; @@ -760,7 +807,9 @@ void TMainWindow::AddCustom() m->AddEmptyAfter(nameField->text(), name); } + search->AddRow(currentRow); RefreshData(); + search->RefreshList(ui->lineEditFind->text()); ui->tableWidget->selectRow(currentRow); @@ -789,6 +838,8 @@ void TMainWindow::AddKnown() { m->AddEmpty(list.at(i)); } + + search->AddRow(currentRow); } } else @@ -806,11 +857,13 @@ void TMainWindow::AddKnown() { m->AddEmptyAfter(after, list.at(i)); } + search->AddRow(currentRow); after = list.at(i); } } RefreshData(); + search->RefreshList(ui->lineEditFind->text()); ui->tableWidget->selectRow(currentRow); @@ -839,18 +892,13 @@ void TMainWindow::ImportFromPattern() return; } -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) - QLockFile *lock = new QLockFile(QFileInfo(mPath).fileName()+".lock"); - lock->setStaleLockTime(0); - if (not MApplication::TryLock(lock)) + VLockGuard tmp(QFileInfo(mPath).fileName()+".lock"); + + if (tmp.GetLockError() == QLockFile::LockFailedError) { - if (lock->error() == QLockFile::LockFailedError) - { - qCCritical(tMainWindow, "%s", tr("This file already opened in another window.").toUtf8().constData()); - return; - } + qCCritical(tMainWindow, "%s", tr("This file already opened in another window.").toUtf8().constData()); + return; } -#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) #ifdef Q_OS_WIN32 qt_ntfs_permission_lookup++; // turn checking on @@ -878,8 +926,6 @@ void TMainWindow::ImportFromPattern() qt_ntfs_permission_lookup--; // turn it off again #endif /*Q_OS_WIN32*/ - delete lock; // release a pattern file - measurements = FilterMeasurements(measurements, m->ListAll()); qint32 currentRow; @@ -906,6 +952,8 @@ void TMainWindow::ImportFromPattern() RefreshData(); + search->RefreshList(ui->lineEditFind->text()); + ui->tableWidget->selectRow(currentRow); MeasurementsWasSaved(false); @@ -917,6 +965,7 @@ void TMainWindow::ChangedSize(const QString &text) const int row = ui->tableWidget->currentRow(); data->SetSize(text.toInt()); RefreshData(); + search->RefreshList(ui->lineEditFind->text()); ui->tableWidget->selectRow(row); } @@ -926,6 +975,7 @@ void TMainWindow::ChangedHeight(const QString &text) const int row = ui->tableWidget->currentRow(); data->SetHeight(text.toInt()); RefreshData(); + search->RefreshList(ui->lineEditFind->text()); ui->tableWidget->selectRow(row); } @@ -1070,6 +1120,7 @@ void TMainWindow::SaveMName() m->SetMName(nameField->text(), newName); MeasurementsWasSaved(false); RefreshData(); + search->RefreshList(ui->lineEditFind->text()); ui->tableWidget->blockSignals(true); ui->tableWidget->selectRow(row); @@ -1139,6 +1190,7 @@ void TMainWindow::SaveMValue() const QTextCursor cursor = ui->plainTextEditFormula->textCursor(); RefreshData(); + search->RefreshList(ui->lineEditFind->text()); ui->tableWidget->blockSignals(true); ui->tableWidget->selectRow(row); @@ -1163,6 +1215,7 @@ void TMainWindow::SaveMBaseValue(double value) MeasurementsWasSaved(false); RefreshData(); + search->RefreshList(ui->lineEditFind->text()); ui->tableWidget->blockSignals(true); ui->tableWidget->selectRow(row); @@ -1185,6 +1238,7 @@ void TMainWindow::SaveMSizeIncrease(double value) MeasurementsWasSaved(false); RefreshData(); + search->RefreshList(ui->lineEditFind->text()); ui->tableWidget->blockSignals(true); ui->tableWidget->selectRow(row); @@ -1207,6 +1261,7 @@ void TMainWindow::SaveMHeightIncrease(double value) MeasurementsWasSaved(false); RefreshData(); + search->RefreshList(ui->lineEditFind->text()); ui->tableWidget->selectRow(row); } @@ -1464,6 +1519,10 @@ void TMainWindow::InitWindow() connect(ui->toolButtonExpr, &QToolButton::clicked, this, &TMainWindow::Fx); } + connect(ui->lineEditFind, &QLineEdit::textEdited, this, &TMainWindow::Find); + connect(ui->toolButtonFindPrevious, &QToolButton::clicked, this, &TMainWindow::FindPrevious); + connect(ui->toolButtonFindNext, &QToolButton::clicked, this, &TMainWindow::FindNext); + ui->plainTextEditNotes->setPlainText(m->Notes()); connect(ui->plainTextEditNotes, &QPlainTextEdit::textChanged, this, &TMainWindow::SaveNotes); @@ -1678,6 +1737,7 @@ void TMainWindow::SetDefaultSize(int value) //--------------------------------------------------------------------------------------------------------------------- void TMainWindow::RefreshData() { + data->ClearUniqueNames(); data->ClearVariables(VarType::Measurement); m->ReadMeasurements(); @@ -1817,6 +1877,10 @@ void TMainWindow::MFields(bool enabled) ui->pushButtonGrow->setEnabled(enabled); ui->toolButtonExpr->setEnabled(enabled); } + + ui->lineEditFind->setEnabled(enabled); + ui->toolButtonFindPrevious->setEnabled(enabled); + ui->toolButtonFindNext->setEnabled(enabled); } //--------------------------------------------------------------------------------------------------------------------- @@ -2003,6 +2067,8 @@ void TMainWindow::UpdatePatternUnit() ShowUnits(); RefreshTable(); + search->RefreshList(ui->lineEditFind->text()); + ui->tableWidget->selectRow(row); } diff --git a/src/app/tape/tmainwindow.h b/src/app/tape/tmainwindow.h index 889505403..3115d4127 100644 --- a/src/app/tape/tmainwindow.h +++ b/src/app/tape/tmainwindow.h @@ -33,7 +33,9 @@ #include #include "../vmisc/def.h" +#include "../vmisc/vlockguard.h" #include "../vformat/vmeasurements.h" +#include "vtablesearch.h" namespace Ui { @@ -43,9 +45,6 @@ namespace Ui class QComboBox; class QTableWidgetItem; class QLabel; -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) -class QLockFile; -#endif class TMainWindow : public QMainWindow { @@ -115,10 +114,11 @@ private slots: void SaveMFullName(); void NewWindow(); - void Preferences(); - void PatternUnitChanged(int index); + void Find(const QString &term); + void FindPrevious(); + void FindNext(); private: Q_DISABLE_COPY(TMainWindow) @@ -133,10 +133,8 @@ private: QComboBox *gradationSizes; QComboBox *comboBoxUnits; int formulaBaseHeight; - -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) - QLockFile *lock; -#endif + VLockGuardPtr lock; + QSharedPointer search; void SetupMenu(); void InitWindow(); diff --git a/src/app/tape/tmainwindow.ui b/src/app/tape/tmainwindow.ui index 6d9cd8037..d2ad073ef 100644 --- a/src/app/tape/tmainwindow.ui +++ b/src/app/tape/tmainwindow.ui @@ -7,7 +7,7 @@ 0 0 536 - 694 + 726 @@ -43,6 +43,69 @@ Measurements + + + + + + Find: + + + + + + + false + + + + + + + false + + + Find Previous + + + ... + + + + + + + + Ctrl+Shift+G + + + + + + + false + + + Find Next + + + ... + + + + + + + + Ctrl+G + + + false + + + + + diff --git a/src/app/tape/vtablesearch.cpp b/src/app/tape/vtablesearch.cpp new file mode 100644 index 000000000..330973824 --- /dev/null +++ b/src/app/tape/vtablesearch.cpp @@ -0,0 +1,208 @@ +/************************************************************************ + ** + ** @file vtablesearch.cpp + ** @author Roman Telezhynskyi + ** @date 15 9, 2015 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentine project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 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 . + ** + *************************************************************************/ + +#include "vtablesearch.h" +#include "../vmisc/def.h" + +//--------------------------------------------------------------------------------------------------------------------- +VTableSearch::VTableSearch(QTableWidget *table) + :table(table), + searchIndex(-1), + searchList() +{ +} + +//--------------------------------------------------------------------------------------------------------------------- +void VTableSearch::Clear() +{ + SCASSERT(table != nullptr); + + foreach(QTableWidgetItem *item, searchList) + { + if (item->row() % 2 != 0 && table->alternatingRowColors()) + { + item->setBackground(QPalette().alternateBase()); + } + else + { + item->setBackground(QPalette().base()); + } + } + searchIndex = -1; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VTableSearch::ShowNext(int newIndex) +{ + if (not searchList.isEmpty()) + { + QTableWidgetItem *item = searchList.at(searchIndex); + item->setBackground(Qt::yellow); + + item = searchList.at(newIndex); + item->setBackground(Qt::red); + table->scrollToItem(item); + searchIndex = newIndex; + } + else + { + Clear(); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VTableSearch::Find(const QString &term) +{ + SCASSERT(table != nullptr); + + const QList list = table->findItems(term, Qt::MatchContains); + + if (list.isEmpty() || term.isEmpty()) + { + Clear(); + } + else + { + Clear(); + + searchList = list; + foreach(QTableWidgetItem *item, searchList) + { + item->setBackground(Qt::yellow); + } + + searchIndex = 0; + QTableWidgetItem *item = searchList.at(searchIndex); + item->setBackground(Qt::red); + table->scrollToItem(item); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VTableSearch::FindPrevious() +{ + int newIndex = searchIndex - 1; + + if (newIndex < 0) + { + newIndex = searchList.size() - 1; + } + + ShowNext(newIndex); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VTableSearch::FindNext() +{ + int newIndex = searchIndex + 1; + + if (newIndex >= searchList.size()) + { + newIndex = 0; + } + + ShowNext(newIndex); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VTableSearch::RemoveRow(int row) +{ + if (searchIndex < 0 || searchIndex >= searchList.size()) + { + return; + } + + const int indexRow = searchList.at(searchIndex)->row(); + + if (row <= indexRow) + { + foreach(QTableWidgetItem *item, searchList) + { + if (item->row() == row) + { + --searchIndex; + } + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VTableSearch::AddRow(int row) +{ + if (searchIndex < 0 || searchIndex >= searchList.size()) + { + return; + } + + const int indexRow = searchList.at(searchIndex)->row(); + + if (row <= indexRow) + { + foreach(QTableWidgetItem *item, searchList) + { + if (item->row() == row) + { + ++searchIndex; + } + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VTableSearch::RefreshList(const QString &term) +{ + SCASSERT(table != nullptr); + + if (term.isEmpty()) + { + return; + } + + searchList = table->findItems(term, Qt::MatchContains); + + foreach(QTableWidgetItem *item, searchList) + { + item->setBackground(Qt::yellow); + } + + if (not searchList.isEmpty()) + { + if (searchIndex < 0) + { + searchIndex = searchList.size() - 1; + } + else if (searchIndex >= searchList.size()) + { + searchIndex = 0; + } + + QTableWidgetItem *item = searchList.at(searchIndex); + item->setBackground(Qt::red); + table->scrollToItem(item); + } +} diff --git a/src/app/tape/vtablesearch.h b/src/app/tape/vtablesearch.h new file mode 100644 index 000000000..187f5571d --- /dev/null +++ b/src/app/tape/vtablesearch.h @@ -0,0 +1,58 @@ +/************************************************************************ + ** + ** @file vtablesearch.h + ** @author Roman Telezhynskyi + ** @date 15 9, 2015 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentine project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 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 VTABLESEARCH_H +#define VTABLESEARCH_H + +#include +#include + +class VTableSearch +{ +public: + VTableSearch(QTableWidget *table); + + void Find(const QString &term); + void FindPrevious(); + void FindNext(); + void RemoveRow(int row); + void AddRow(int row); + void RefreshList(const QString &term); + +private: + Q_DISABLE_COPY(VTableSearch) + + QTableWidget *table; + int searchIndex; + QList searchList; + + void Clear(); + void ShowNext(int newIndex); +}; + +#endif // VTABLESEARCH_H diff --git a/src/app/valentina/core/vapplication.cpp b/src/app/valentina/core/vapplication.cpp index 549a73cc2..712c8f802 100644 --- a/src/app/valentina/core/vapplication.cpp +++ b/src/app/valentina/core/vapplication.cpp @@ -53,6 +53,8 @@ Q_LOGGING_CATEGORY(vApp, "v.application") +constexpr auto DAYS_TO_KEEP_LOGS = 3; + //--------------------------------------------------------------------------------------------------------------------- inline void noisyFailureMsgHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { @@ -170,12 +172,8 @@ const QString VApplication::GistFileName = QStringLiteral("gist.json"); VApplication::VApplication(int &argc, char **argv) : VAbstractApplication(argc, argv), trVars(nullptr), autoSaveTimer(nullptr), - log(nullptr), - #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) - out(nullptr), logLock(nullptr) - #else + lockLog(), out(nullptr) - #endif { VCommandLine::Reset(); // making sure will create new instance...just in case we will ever do 2 objects of VApplication VCommandLine::Get(*this); @@ -187,16 +185,6 @@ VApplication::~VApplication() { qCDebug(vApp, "Application closing."); qInstallMessageHandler(0); // Resore the message handler - delete out; - - if (log != nullptr) - { - log->close(); - delete log; -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) - delete logLock; -#endif - } delete trVars; VCommandLine::Reset(); } @@ -418,32 +406,25 @@ void VApplication::CreateLogDir() const //--------------------------------------------------------------------------------------------------------------------- void VApplication::BeginLogging() { - log = new QFile(LogPath()); - if (log->open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) - { - out = new QTextStream(log); - qInstallMessageHandler(noisyFailureMsgHandler); + VlpCreateLock(lockLog, LogPath()+".lock", [this](){return new QFile(LogPath());}); -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) - logLock = new QLockFile(LogPath()+".lock"); - logLock->setStaleLockTime(0); - if (TryLock(logLock)) + if (lockLog->IsLocked()) + { + if (lockLog->GetProtected()->open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { + out.reset(new QTextStream(lockLog->GetProtected().get())); + qInstallMessageHandler(noisyFailureMsgHandler); qCDebug(vApp, "Log file %s was locked.", LogPath().toUtf8().constData()); } else { - qCDebug(vApp, "Failed to lock %s", LogPath().toUtf8().constData()); - qCDebug(vApp, "Error type: %d", logLock->error()); + qCDebug(vApp, "Error opening log file \'%s\'. All debug output redirected to console.", + LogPath().toUtf8().constData()); } -#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) } else { - delete log; - log = nullptr; - qCDebug(vApp, "Error opening log file \'%s\'. All debug output redirected to console.", - LogPath().toUtf8().constData()); + qCDebug(vApp, "Failed to lock %s", LogPath().toUtf8().constData()); } } @@ -459,45 +440,29 @@ void VApplication::ClearOldLogs() const if (allFiles.isEmpty() == false) { qCDebug(vApp, "Clearing old logs"); - for (int i = 0; i < allFiles.size(); ++i) + for (int i = 0, sz = allFiles.size(); i < sz; ++i) { - QFileInfo info(allFiles.at(i)); -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) - QLockFile *lock = new QLockFile(info.absoluteFilePath() + ".lock"); - if (TryLock(lock)) + auto fn = allFiles.at(i); + QFileInfo info(fn); + if (info.created().daysTo(QDateTime::currentDateTime()) >= DAYS_TO_KEEP_LOGS) { - qCDebug(vApp, "Locked file %s", info.absoluteFilePath().toUtf8().constData()); - QFile oldLog(allFiles.at(i)); - if (oldLog.remove()) + VLockGuard tmp(info.absoluteFilePath() + ".lock", [&fn](){return new QFile(fn);}); + if (tmp.GetProtected() != nullptr) { - qCDebug(vApp, "Deleted %s", info.absoluteFilePath().toUtf8().constData()); + if (tmp.GetProtected()->remove()) + { + qCDebug(vApp, "Deleted %s", info.absoluteFilePath().toUtf8().constData()); + } + else + { + qCDebug(vApp, "Could not delete %s", info.absoluteFilePath().toUtf8().constData()); + } } else { - qCDebug(vApp, "Could not delete %s", info.absoluteFilePath().toUtf8().constData()); + qCDebug(vApp, "Failed to lock %s", info.absoluteFilePath().toUtf8().constData()); } } - else - { - qCDebug(vApp, "Failed to lock %s", info.absoluteFilePath().toUtf8().constData()); - } - - delete lock; - lock = nullptr; -#else - if (info.created().daysTo(QDateTime::currentDateTime()) >= 3) - { - QFile oldLog(allFiles.at(i)); - if (oldLog.remove()) - { - qCDebug(vApp, "Deleted %s", info.absoluteFilePath().toUtf8().constData()); - } - else - { - qCDebug(vApp, "Could not delete %s", info.absoluteFilePath().toUtf8().constData()); - } - } -#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) } } else @@ -614,7 +579,7 @@ void VApplication::StartLogging() //--------------------------------------------------------------------------------------------------------------------- QTextStream *VApplication::LogFile() { - return out; + return out.get(); } //--------------------------------------------------------------------------------------------------------------------- @@ -707,27 +672,28 @@ void VApplication::GatherLogs() const const QStringList allFiles = logsDir.entryList(QDir::NoDotAndDotDot | QDir::Files); if (allFiles.isEmpty() == false) { - for (int i = 0; i < allFiles.size(); ++i) + for (int i = 0, sz = allFiles.size(); i < sz; ++i) { - QFileInfo info(allFiles.at(i)); + auto fn = allFiles.at(i); + QFileInfo info(fn); if (info.fileName() == "valentina.log") { continue; } - QLockFile *logLock = new QLockFile(info.absoluteFilePath()+".lock"); - logLock->setStaleLockTime(0); - if (TryLock(logLock)) + + VLockGuard tmp(info.absoluteFilePath() + ".lock", [&fn](){return new QFile(fn);}); + + if (tmp.IsLocked()) { *out <<"--------------------------" << endl; - QFile logFile(info.absoluteFilePath()); - if (logFile.open(QIODevice::ReadOnly | QIODevice::Text)) + if (tmp.GetProtected()->open(QIODevice::ReadOnly | QIODevice::Text)) { - QTextStream in(&logFile); + QTextStream in(&tmp.GetProtected()); while (!in.atEnd()) { *out << in.readLine() << endl; } - logFile.close(); + tmp.GetProtected()->close(); } else { @@ -736,9 +702,8 @@ void VApplication::GatherLogs() const } else { - *out << "Could not lock" << info.absoluteFilePath() << "."; + qCDebug(vApp, "Failed to lock %s", info.absoluteFilePath().toUtf8().constData()); } - delete logLock; } } else @@ -924,7 +889,9 @@ void VApplication::SendReport(const QString &reportName) const const QString arg = QString("curl.exe -k -H \"Authorization: bearer ")+token.join("")+ QString("\" -H \"Accept: application/json\" -H \"Content-type: application/json\" -X POST " "--data @gist.json https://api.github.com/gists"); - QProcess::startDetached(arg); + QProcess proc; + proc.start(arg); + proc.waitForFinished(10000); // 10 sec reportFile.remove();// Clear after yourself } else diff --git a/src/app/valentina/core/vapplication.h b/src/app/valentina/core/vapplication.h index 8d522e6d3..28e24e84d 100644 --- a/src/app/valentina/core/vapplication.h +++ b/src/app/valentina/core/vapplication.h @@ -36,7 +36,6 @@ #include "vsettings.h" #include "vcmdexport.h" - class VApplication;// use in define class VMainGraphicsView; class VPattern; @@ -95,11 +94,9 @@ private: VTranslateVars *trVars; QTimer *autoSaveTimer; - QFile *log; - QTextStream *out; -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) - QLockFile *logLock; -#endif + VLockGuardPtr lockLog; + std::shared_ptr out; + void InitLineWidth(); #if defined(Q_OS_WIN) && defined(Q_CC_GNU) diff --git a/src/app/valentina/dialogs/dialogaboutapp.ui b/src/app/valentina/dialogs/dialogaboutapp.ui index 5806ee247..371e8d05f 100644 --- a/src/app/valentina/dialogs/dialogaboutapp.ui +++ b/src/app/valentina/dialogs/dialogaboutapp.ui @@ -214,7 +214,9 @@ Robert Martin Michaela Orth Rina Rivera Fritz Rometsch -Felix Ulber +Felix Ulber +Alex Zaharov +Valentina Zhuravska diff --git a/src/app/valentina/mainwindow.cpp b/src/app/valentina/mainwindow.cpp index fdac76a2c..d7dc7099d 100644 --- a/src/app/valentina/mainwindow.cpp +++ b/src/app/valentina/mainwindow.cpp @@ -46,6 +46,7 @@ #include "../vformat/vmeasurements.h" #include "../ifc/xml/vvstconverter.h" #include "../ifc/xml/vvitconverter.h" +#include "../vwidgets/vwidgetpopup.h" #include #include @@ -62,9 +63,6 @@ #include #include #include -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) -# include -#endif #include #include @@ -1162,13 +1160,16 @@ void MainWindow::SyncMeasurements() { if (mChanges) { - if(LoadMeasurements(doc->MPath())) + const QString path = AbsoluteMPath(curFile, doc->MPath()); + if(LoadMeasurements(path)) { - if (not watcher->files().contains(doc->MPath())) + if (not watcher->files().contains(path)) { - watcher->addPath(doc->MPath()); + watcher->addPath(path); } - helpLabel->setText(tr("Measurements updated")); + const QString msg = tr("Measurements was updated"); + helpLabel->setText(msg); + VWidgetPopup::PopupMessage(this, msg); doc->LiteParseTree(Document::LiteParse); mChanges = false; } @@ -1395,9 +1396,10 @@ void MainWindow::currentPPChanged(int index) */ void MainWindow::mouseMove(const QPointF &scenePos) { - QString string = QString("%1, %2 (%3)").arg(static_cast(qApp->fromPixel(scenePos.x()))) + //: Coords in status line: "X, Y (units)" + QString string = QString(tr("%1, %2 (%3)")).arg(static_cast(qApp->fromPixel(scenePos.x()))) .arg(static_cast(qApp->fromPixel(scenePos.y()))) - .arg(doc->UnitsToStr(qApp->patternUnit())); + .arg(doc->UnitsToStr(qApp->patternUnit(), true)); if (mouseCoordinate != nullptr) { mouseCoordinate->setText(string); @@ -1859,9 +1861,24 @@ bool MainWindow::SaveAs() { fileName += ".val"; } - const QString oldFileName = curFile; + + if (QFileInfo(fileName).exists()) + { + VLockGuard tmp(fileName + ".lock"); + + if (not tmp.IsLocked()) + { + if (lock->GetLockError() == QLockFile::LockFailedError) + { + qCCritical(vMainWindow, "%s", tr("Failed to lock. This file already opened in another window.") + .toUtf8().constData()); + return false; + } + } + } + QString error; - bool result = SavePattern(fileName, error); + const bool result = SavePattern(fileName, error); if (result == false) { QMessageBox messageBox; @@ -1871,14 +1888,33 @@ bool MainWindow::SaveAs() messageBox.setDetailedText(error); messageBox.setStandardButtons(QMessageBox::Ok); messageBox.exec(); + + return result; } - if (oldFileName != curFile) - {// Now we have new file name after save as. - // But still have previous name in restore list. We should delete them. - QStringList restoreFiles = qApp->ValentinaSettings()->GetRestoreFileList(); - restoreFiles.removeAll(oldFileName); - qApp->ValentinaSettings()->SetRestoreFileList(restoreFiles); + + qCDebug(vMainWindow, "Unlock old file"); + lock.reset(); + + qCDebug(vMainWindow, "Locking file"); + VlpCreateLock(lock, fileName+".lock"); + + if (lock->IsLocked()) + { + qCDebug(vMainWindow, "Pattern file %s was locked.", fileName.toUtf8().constData()); } + else + { + qCDebug(vMainWindow, "Failed to lock %s", fileName.toUtf8().constData()); + qCDebug(vMainWindow, "Error type: %d", lock->GetLockError()); + if (lock->GetLockError() == QLockFile::LockFailedError) + { + qCCritical(vMainWindow, "%s", tr("Failed to lock. This file already opened in another window. " + "Expect collissions when run 2 copies of the program.") + .toUtf8().constData()); + lock.reset(); + } + } + return result; } @@ -1983,13 +2019,8 @@ void MainWindow::OnlineHelp() void MainWindow::Clear() { qCDebug(vMainWindow, "Reseting main window."); - -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) - delete lock; // Unlock pattern file - lock = nullptr; + lock.reset(); qCDebug(vMainWindow, "Unlocked pattern file."); -#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) - ui->actionDetails->setChecked(true); ui->actionDraw->setChecked(true); ui->actionLayout->setEnabled(true); @@ -3060,9 +3091,6 @@ MainWindow::~MainWindow() CancelTool(); CleanLayout(); -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) - delete lock; // Unlock pattern file -#endif delete doc; delete sceneDetails; delete sceneDraw; @@ -3091,26 +3119,24 @@ bool MainWindow::LoadPattern(const QString &fileName, const QString& customMeasu return false; } -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) qCDebug(vMainWindow, "Loking file"); - lock = new QLockFile(fileName+".lock"); - lock->setStaleLockTime(0); - if (VApplication::TryLock(lock)) + VlpCreateLock(lock, fileName+".lock"); + + if (lock->IsLocked()) { qCDebug(vMainWindow, "Pattern file %s was locked.", fileName.toUtf8().constData()); } else { qCDebug(vMainWindow, "Failed to lock %s", fileName.toUtf8().constData()); - qCDebug(vMainWindow, "Error type: %d", lock->error()); - if (lock->error() == QLockFile::LockFailedError) + qCDebug(vMainWindow, "Error type: %d", lock->GetLockError()); + if (lock->GetLockError() == QLockFile::LockFailedError) { qCCritical(vMainWindow, "%s", tr("This file already opened in another window.").toUtf8().constData()); Clear(); return false; } } -#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) // On this stage scene empty. Fit scene size to view size VMainGraphicsView::NewSceneRect(sceneDraw, ui->view); @@ -3213,14 +3239,11 @@ QStringList MainWindow::GetUnlokedRestoreFileList() const for (int i = 0; i < files.size(); ++i) { // Seeking file that realy need reopen - QLockFile *lock = new QLockFile(files.at(i)+".lock"); - lock->setStaleLockTime(0); - if (VApplication::TryLock(lock)) + VLockGuard tmp(files.at(i)+".lock"); + if (tmp.IsLocked()) { restoreFiles.append(files.at(i)); } - delete lock; - lock = nullptr; } // Clearing list after filtering @@ -3230,7 +3253,6 @@ QStringList MainWindow::GetUnlokedRestoreFileList() const } qApp->ValentinaSettings()->SetRestoreFileList(files); - } return restoreFiles; #else diff --git a/src/app/valentina/mainwindow.h b/src/app/valentina/mainwindow.h index a71b6639e..b0d5e3f88 100644 --- a/src/app/valentina/mainwindow.h +++ b/src/app/valentina/mainwindow.h @@ -37,7 +37,7 @@ #include "tools/vtooluniondetails.h" #include "tools/drawTools/drawtools.h" #include "core/vcmdexport.h" -#include +#include "../vmisc/vlockguard.h" #include #include @@ -48,9 +48,6 @@ namespace Ui } class VToolOptionsPropertyBrowser; -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) -class QLockFile; -#endif /** * @brief The MainWindow class main windows. @@ -233,9 +230,7 @@ private: QPointer gradationHeightsLabel; QPointer gradationSizesLabel; VToolOptionsPropertyBrowser *toolOptions; -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) - QLockFile *lock; -#endif + VLockGuardPtr lock; void ToolBarOption(); void ToolBarStages(); diff --git a/src/app/valentina/valentina.pro b/src/app/valentina/valentina.pro index f64ed64d5..b25a4b603 100644 --- a/src/app/valentina/valentina.pro +++ b/src/app/valentina/valentina.pro @@ -344,7 +344,7 @@ INSTALL_TRANSLATIONS += \ $${TRANSLATIONS_PATH}/measurements_p9_fi_FI.qm \ $${TRANSLATIONS_PATH}/measurements_p9_en_US.qm -TRANSLATIONS += \ +INSTALL_TRANSLATIONS += \ $${TRANSLATIONS_PATH}/measurements_p10_ru_RU.qm \ $${TRANSLATIONS_PATH}/measurements_p10_uk_UA.qm \ $${TRANSLATIONS_PATH}/measurements_p10_de_DE.qm \ diff --git a/src/libs/ifc/schema/individual_measurements/v0.3.0.xsd b/src/libs/ifc/schema/individual_measurements/v0.3.0.xsd index dcb80e614..063c6a49e 100644 --- a/src/libs/ifc/schema/individual_measurements/v0.3.0.xsd +++ b/src/libs/ifc/schema/individual_measurements/v0.3.0.xsd @@ -34,6 +34,10 @@ + + + + diff --git a/src/libs/ifc/schema/pattern/v0.2.0.xsd b/src/libs/ifc/schema/pattern/v0.2.0.xsd index 72519bb93..65456be2a 100644 --- a/src/libs/ifc/schema/pattern/v0.2.0.xsd +++ b/src/libs/ifc/schema/pattern/v0.2.0.xsd @@ -74,6 +74,10 @@ + + + + diff --git a/src/libs/ifc/schema/standard_measurements/v0.4.0.xsd b/src/libs/ifc/schema/standard_measurements/v0.4.0.xsd index fa14bdda1..04b047f89 100644 --- a/src/libs/ifc/schema/standard_measurements/v0.4.0.xsd +++ b/src/libs/ifc/schema/standard_measurements/v0.4.0.xsd @@ -35,6 +35,10 @@ + + + + diff --git a/src/libs/ifc/xml/vabstractpattern.cpp b/src/libs/ifc/xml/vabstractpattern.cpp index 79ca5f56d..acb1113f2 100644 --- a/src/libs/ifc/xml/vabstractpattern.cpp +++ b/src/libs/ifc/xml/vabstractpattern.cpp @@ -1018,6 +1018,7 @@ QStringList VAbstractPattern::ListExpressions() const list << ListPointExpressions(); list << ListArcExpressions(); list << ListSplineExpressions(); + list << ListIncrementExpressions(); return list; } @@ -1176,6 +1177,28 @@ QStringList VAbstractPattern::ListPathPointExpressions() const return expressions; } +//--------------------------------------------------------------------------------------------------------------------- +QStringList VAbstractPattern::ListIncrementExpressions() const +{ + QStringList expressions; + const QDomNodeList list = elementsByTagName(TagIncrement); + for (int i=0; i < list.size(); ++i) + { + const QDomElement dom = list.at(i).toElement(); + + try + { + expressions.append(GetParametrString(dom, IncrementFormula)); + } + catch (VExceptionEmptyParameter &e) + { + Q_UNUSED(e) + } + } + + return expressions; +} + //--------------------------------------------------------------------------------------------------------------------- bool VAbstractPattern::IsVariable(const QString &token) const { diff --git a/src/libs/ifc/xml/vabstractpattern.h b/src/libs/ifc/xml/vabstractpattern.h index 4b03c80b0..e65a0d79c 100644 --- a/src/libs/ifc/xml/vabstractpattern.h +++ b/src/libs/ifc/xml/vabstractpattern.h @@ -248,6 +248,7 @@ private: QStringList ListArcExpressions() const; QStringList ListSplineExpressions() const; QStringList ListPathPointExpressions() const; + QStringList ListIncrementExpressions() const; bool IsVariable(const QString& token) const; bool IsPostfixOperator(const QString& token) const; diff --git a/src/libs/vmisc/debugbreak.h b/src/libs/vmisc/debugbreak.h new file mode 100644 index 000000000..9a1926bbd --- /dev/null +++ b/src/libs/vmisc/debugbreak.h @@ -0,0 +1,128 @@ +/* Copyright (c) 2011-2015, Scott Tsai + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DEBUG_BREAK_H +#define DEBUG_BREAK_H + +#ifdef _MSC_VER + +#define debug_break __debugbreak + +#else + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* gcc optimizers consider code after __builtin_trap() dead. + * Making __builtin_trap() unsuitable for breaking into the debugger */ + DEBUG_BREAK_PREFER_BUILTIN_TRAP_TO_SIGTRAP = 0, +}; + +#if defined(__i386__) || defined(__x86_64__) +enum { HAVE_TRAP_INSTRUCTION = 1, }; +__attribute__((gnu_inline, always_inline)) +static void __inline__ trap_instruction(void) +{ + __asm__ volatile("int $0x03"); +} +#elif defined(__thumb__) +enum { HAVE_TRAP_INSTRUCTION = 1, }; +/* FIXME: handle __THUMB_INTERWORK__ */ +__attribute__((gnu_inline, always_inline)) +static void __inline__ trap_instruction(void) +{ + /* See 'arm-linux-tdep.c' in GDB source. + * Both instruction sequences below work. */ +#if 1 + /* 'eabi_linux_thumb_le_breakpoint' */ + __asm__ volatile(".inst 0xde01"); +#else + /* 'eabi_linux_thumb2_le_breakpoint' */ + __asm__ volatile(".inst.w 0xf7f0a000"); +#endif + + /* Known problem: + * After a breakpoint hit, can't stepi, step, or continue in GDB. + * 'step' stuck on the same instruction. + * + * Workaround: a new GDB command, + * 'debugbreak-step' is defined in debugbreak-gdb.py + * that does: + * (gdb) set $instruction_len = 2 + * (gdb) tbreak *($pc + $instruction_len) + * (gdb) jump *($pc + $instruction_len) + */ +} +#elif defined(__arm__) && !defined(__thumb__) +enum { HAVE_TRAP_INSTRUCTION = 1, }; +__attribute__((gnu_inline, always_inline)) +static void __inline__ trap_instruction(void) +{ + /* See 'arm-linux-tdep.c' in GDB source, + * 'eabi_linux_arm_le_breakpoint' */ + __asm__ volatile(".inst 0xe7f001f0"); + /* Has same known problem and workaround + * as Thumb mode */ +} +#elif defined(__aarch64__) +enum { HAVE_TRAP_INSTRUCTION = 1, }; +__attribute__((gnu_inline, always_inline)) +static void __inline__ trap_instruction(void) +{ + /* See 'aarch64-tdep.c' in GDB source, + * 'aarch64_default_breakpoint' */ + __asm__ volatile(".inst 0xd4200000"); +} +#else +enum { HAVE_TRAP_INSTRUCTION = 0, }; +#endif + +__attribute__((gnu_inline, always_inline)) +static void __inline__ debug_break(void) +{ + if (HAVE_TRAP_INSTRUCTION) { + trap_instruction(); + } else if (DEBUG_BREAK_PREFER_BUILTIN_TRAP_TO_SIGTRAP) { + /* raises SIGILL on Linux x86{,-64}, to continue in gdb: + * (gdb) handle SIGILL stop nopass + * */ + __builtin_trap(); + } else { + raise(SIGTRAP); + } +} + +#ifdef __cplusplus +} +#endif + +#endif + +#endif diff --git a/src/libs/vmisc/def.cpp b/src/libs/vmisc/def.cpp index 51614c68a..1979f3f6a 100644 --- a/src/libs/vmisc/def.cpp +++ b/src/libs/vmisc/def.cpp @@ -193,7 +193,7 @@ const QString neckSideToBustSideB_M = QStringLiteral("neck_side_to_bus const QString shoulderTipToWaistB_1inOffset_M = QStringLiteral("shoulder_tip_to_waist_b_1in_offset"); // H13 // I const QString armShoulderTipToWristBent_M = QStringLiteral("arm_shoulder_tip_to_wrist_bent"); // I01 -const QString armShoulderTipToElbowBent_M = QStringLiteral(" arm_shoulder_tip_to_elbow_bent"); // I02 +const QString armShoulderTipToElbowBent_M = QStringLiteral("arm_shoulder_tip_to_elbow_bent"); // I02 const QString armElbowToWristBent_M = QStringLiteral("arm_elbow_to_wrist_bent"); // I03 const QString armElbowCircBent_M = QStringLiteral("arm_elbow_circ_bent"); // I04 const QString armShoulderTipToWrist_M = QStringLiteral("arm_shoulder_tip_to_wrist"); // I05 diff --git a/src/libs/vmisc/def.h b/src/libs/vmisc/def.h index 80b3ab5cd..d2b0cf9cd 100644 --- a/src/libs/vmisc/def.h +++ b/src/libs/vmisc/def.h @@ -36,6 +36,8 @@ #include #endif /* Q_OS_WIN */ +#include "debugbreak.h" + #define SceneSize 50000 #define DefPointRadius 1.5//mm @@ -160,43 +162,23 @@ enum class GSizes : unsigned char { ALL, * https://stackoverflow.com/questions/1721543/continue-to-debug-after-failed-assertion-on-linux-c-c */ #ifndef V_NO_ASSERT -#ifdef Q_OS_WIN32 + #ifdef Q_CC_MSVC -#define SCASSERT(cond) \ -{ \ - if (!(cond)) \ - { \ - qDebug("ASSERT: %s in %s (%s:%u)", \ - #cond, __FUNCSIG__, __FILE__, __LINE__); \ - DebugBreak(); \ - } \ -} \ - -#else // GCC (Windows) - -#define SCASSERT(cond) \ -{ \ - if (!(cond)) \ - { \ - qDebug("ASSERT: %s in %s (%s:%u)", \ - #cond, __PRETTY_FUNCTION__, __FILE__, __LINE__);\ - DebugBreak(); \ - } \ -} \ - +#define V_PRETTY_FUNCTION __FUNCSIG__ +#else // GCC/Clang +#define V_PRETTY_FUNCTION __PRETTY_FUNCTION__ #endif /*Q_CC_MSVC*/ -#else // UNIX + #define SCASSERT(cond) \ { \ if (!(cond)) \ { \ qDebug("ASSERT: %s in %s (%s:%u)", \ - #cond, __PRETTY_FUNCTION__, __FILE__, __LINE__);\ - std::raise(SIGTRAP); \ + #cond, V_PRETTY_FUNCTION, __FILE__, __LINE__); \ + debug_break(); \ } \ } \ -#endif /* Q_OS_WIN32 */ #else // define but disable this function if debugging is not set #define SCASSERT(cond) qt_noop(); #endif /* V_NO_ASSERT */ diff --git a/src/libs/vmisc/vabstractapplication.cpp b/src/libs/vmisc/vabstractapplication.cpp index 26d612620..d687acd66 100644 --- a/src/libs/vmisc/vabstractapplication.cpp +++ b/src/libs/vmisc/vabstractapplication.cpp @@ -29,10 +29,6 @@ #include "vabstractapplication.h" #include "../vmisc/def.h" -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) -# include -#endif - //--------------------------------------------------------------------------------------------------------------------- VAbstractApplication::VAbstractApplication(int &argc, char **argv) :QApplication(argc, argv), @@ -116,43 +112,3 @@ double VAbstractApplication::fromPixel(double pix) const { return FromPixel(pix, _patternUnit); } - -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) -//--------------------------------------------------------------------------------------------------------------------- -bool VAbstractApplication::TryLock(QLockFile *lock) -{ - if (lock == nullptr) - { - return false; - } - - if (lock->tryLock()) - { - return true; - } - else - { - if (lock->error() == QLockFile::LockFailedError) - { - // This happens if a stale lock file exists and another process uses that PID. - // Try removing the stale file, which will fail if a real process is holding a - // file-level lock. A false error is more problematic than not locking properly - // on corner-case systems. - if (lock->removeStaleLockFile() == false || lock->tryLock() == false) - { - return false; - } - else - { - return true; - } - } - else - { - return false; - } - return false; - } -} - -#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) diff --git a/src/libs/vmisc/vabstractapplication.h b/src/libs/vmisc/vabstractapplication.h index d8c7fec6e..2c687f7ee 100644 --- a/src/libs/vmisc/vabstractapplication.h +++ b/src/libs/vmisc/vabstractapplication.h @@ -33,15 +33,13 @@ #include #include "def.h" #include "vsettings.h" +#include "vlockguard.h" class VAbstractApplication;// use in define class VTranslateVars; class VAbstractPattern; class VMainGraphicsView; class QUndoStack; -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) -class QLockFile; -#endif #if defined(qApp) #undef qApp @@ -89,10 +87,6 @@ public: QUndoStack *getUndoStack() const; -#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) - static bool TryLock(QLockFile *lock); -#endif //QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) - protected: QUndoStack *undoStack; diff --git a/src/libs/vmisc/vlockguard.h b/src/libs/vmisc/vlockguard.h new file mode 100644 index 000000000..395a1a265 --- /dev/null +++ b/src/libs/vmisc/vlockguard.h @@ -0,0 +1,200 @@ +/************************************************************************ + ** + ** @file VLockGuard.h + ** @author Alex Zaharov + ** @author Roman Telezhynskyi + ** @date 14 9, 2015 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentine project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 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 VLOCKGUARD_H +#define VLOCKGUARD_H + +#include +#include +#include + +#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) +#include +#define PEDANT_COMPILER ,lock(nullptr) +#else +#define PEDANT_COMPILER +#warning To have lock-file support you must use Qt 5.1+. Expect collissions when run 2 copies of the program. +#endif + +/*@brief + * This class creates Guarded object if and only if lock file taken. It keeps shared_ptr to object and lock-file. + * Can use optional object allocator and deleter. + * + * On older Qt lock assumed always taken and compile-time warning is shown. + * +*/ +template +class VLockGuard +{ +public: + VLockGuard(const QString& lockName, int stale = 0, int timeout = 0); + + template + VLockGuard(const QString& lockName, Alloc a, int stale = 0, int timeout=0); + + template + VLockGuard(const QString& lockName, Alloc a, Delete d, int stale = 0, int timeout=0); + + const std::shared_ptr &GetProtected() const; + int GetLockError() const; + bool IsLocked() const; + +private: + Q_DISABLE_COPY(VLockGuard) + + std::shared_ptr holder; + int lockError; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) + std::shared_ptr lock; +#endif + + bool TryLock(const QString &lockName, int stale, int timeout); +}; + +//--------------------------------------------------------------------------------------------------------------------- +template +VLockGuard::VLockGuard(const QString &lockName, int stale, int timeout) + : holder(nullptr), lockError(0) PEDANT_COMPILER +{ + if (TryLock(lockName, stale, timeout)) + { + holder.reset(new Guarded()); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +//using allocator lambdas seems logically better than supplying pointer, because we will take ownership of allocated +//object +template template +VLockGuard::VLockGuard(const QString& lockName, Alloc a, int stale, int timeout) + : holder(nullptr), lockError(0) PEDANT_COMPILER +{ + if (TryLock(lockName, stale, timeout)) + { + holder.reset(a()); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +template template +VLockGuard::VLockGuard(const QString& lockName, Alloc a, Delete d, int stale, int timeout) + : holder(nullptr), lockError(0) PEDANT_COMPILER +{ + if (TryLock(lockName, stale, timeout)) + { + holder.reset(a(), d); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +template +const std::shared_ptr &VLockGuard::GetProtected() const +{ + return holder; +} + +//--------------------------------------------------------------------------------------------------------------------- +template +int VLockGuard::GetLockError() const +{ + return lockError; +} + +//--------------------------------------------------------------------------------------------------------------------- +template +bool VLockGuard::IsLocked() const +{ + return holder != nullptr; +} + +//--------------------------------------------------------------------------------------------------------------------- +template +bool VLockGuard::TryLock(const QString &lockName, int stale, int timeout) +{ + bool res = true; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) + + lock.reset(new QLockFile(lockName)); + lock->setStaleLockTime(stale); + + for (int i = 0; i < 2 && !lock->tryLock(timeout); i++) + { + if (QLockFile::LockFailedError != lock->error()) + { + break; + } + else + { + // This happens if a stale lock file exists and another process uses that PID. + // Try removing the stale file, which will fail if a real process is holding a + // file-level lock. A false error is more problematic than not locking properly + // on corner-case systems. + lock->removeStaleLockFile(); + lock->tryLock(timeout); + } + } + res = QLockFile::NoError == (lockError = lock->error()); + if (!res) + { + lock.reset(); + } +#endif + return res; +} + +#undef PEDANT_COMPILER + +//use pointer and function below to persistent things like class-member, because lock is taken by constructor +//helper functions allow to write shorter creating and setting new lock-pointer + +//new C++11 - "template typedef" http://stackoverflow.com/questions/2795023/c-template-typedef +template +using VLockGuardPtr = std::shared_ptr>; + +template +void VlpCreateLock(VLockGuardPtr& r, const QString& lockName, int stale = 0, int timeout = 0) +{ + r.reset(new VLockGuard(lockName, stale, timeout)); +} + +template +void VlpCreateLock(VLockGuardPtr& r, const QString& lockName, Alloc a, int stale = 0, int timeout = 0) +{ + r.reset(new VLockGuard(lockName, a, stale, timeout)); +} + +template +void VlpCreateLock(VLockGuardPtr& r, const QString& lockName, Alloc a, Del d, int stale = 0, int timeout = 0) +{ + r.reset(new VLockGuard(lockName, a, d, stale, timeout)); +} + +#endif // VLOCKGUARD_H diff --git a/src/libs/vmisc/vmisc.pri b/src/libs/vmisc/vmisc.pri index 4d29598c7..775357374 100644 --- a/src/libs/vmisc/vmisc.pri +++ b/src/libs/vmisc/vmisc.pri @@ -25,4 +25,6 @@ HEADERS += \ $$PWD/vabstractapplication.h \ $$PWD/projectversion.h \ $$PWD/vcommonsettings.h \ - $$PWD/vtapesettings.h + $$PWD/vtapesettings.h \ + $$PWD/debugbreak.h \ + $$PWD/vlockguard.h diff --git a/src/libs/vtools/undocommands/deletepatternpiece.cpp b/src/libs/vtools/undocommands/deletepatternpiece.cpp index 28a509b86..65e774f1e 100644 --- a/src/libs/vtools/undocommands/deletepatternpiece.cpp +++ b/src/libs/vtools/undocommands/deletepatternpiece.cpp @@ -31,14 +31,13 @@ //--------------------------------------------------------------------------------------------------------------------- DeletePatternPiece::DeletePatternPiece(VAbstractPattern *doc, const QString &namePP, QUndoCommand *parent) - : VUndoCommand(QDomElement(), doc, parent), namePP(namePP), patternPiece(QDomElement()), mPath(QString()), + : VUndoCommand(QDomElement(), doc, parent), namePP(namePP), patternPiece(QDomElement()), previousPPName(QString()) { setText(tr("delete pattern piece %1").arg(namePP)); QDomElement patternP = doc->GetPPElement(namePP); patternPiece = patternP.cloneNode().toElement(); - mPath = doc->MPath(); QDomNode previousPP = patternP.previousSibling();//find previous pattern piece previousPPName = doc->GetParametrString(previousPP.toElement(), VAbstractPattern::AttrName, ""); } diff --git a/src/libs/vtools/undocommands/deletepatternpiece.h b/src/libs/vtools/undocommands/deletepatternpiece.h index bc7af8efb..641ceecdf 100644 --- a/src/libs/vtools/undocommands/deletepatternpiece.h +++ b/src/libs/vtools/undocommands/deletepatternpiece.h @@ -43,7 +43,6 @@ private: Q_DISABLE_COPY(DeletePatternPiece) QString namePP; QDomElement patternPiece; - QString mPath; QString previousPPName; }; diff --git a/src/libs/vwidgets/vwidgetpopup.cpp b/src/libs/vwidgets/vwidgetpopup.cpp index 5329dafca..44f102a0b 100644 --- a/src/libs/vwidgets/vwidgetpopup.cpp +++ b/src/libs/vwidgets/vwidgetpopup.cpp @@ -31,6 +31,9 @@ #include #include #include +#include + +#include "../vmisc/def.h" //--------------------------------------------------------------------------------------------------------------------- VWidgetPopup::VWidgetPopup(QWidget *parent) @@ -77,6 +80,22 @@ void VWidgetPopup::SetWidget(QWidget *widget, bool own) } } +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetPopup::PopupMessage(QWidget *w, const QString &msg) +{ + SCASSERT(w != nullptr); + + VWidgetPopup *popup = new VWidgetPopup(); + QLabel *label = new QLabel(msg); + QFont f = label->font(); + f.setBold(true); + f.setPixelSize(16); + label->setFont(f); + popup->SetWidget(label); + popup->SetLifeTime(2000); + popup->Show(w->frameGeometry().center()); +} + //--------------------------------------------------------------------------------------------------------------------- void VWidgetPopup::Show(QPoint coord) { diff --git a/src/libs/vwidgets/vwidgetpopup.h b/src/libs/vwidgets/vwidgetpopup.h index eb6529435..aadb6cc19 100644 --- a/src/libs/vwidgets/vwidgetpopup.h +++ b/src/libs/vwidgets/vwidgetpopup.h @@ -67,6 +67,8 @@ public: int GetLifeTime() const; void SetLifeTime(int value); + static void PopupMessage(QWidget *w, const QString &msg); + public slots: /** Pops up the widget at global coordinates \a coord. */ void Show(QPoint coord); diff --git a/src/test/ValentinaTest/ValentinaTest.pro b/src/test/ValentinaTest/ValentinaTest.pro index 2678849d2..3eeac216d 100644 --- a/src/test/ValentinaTest/ValentinaTest.pro +++ b/src/test/ValentinaTest/ValentinaTest.pro @@ -42,7 +42,8 @@ SOURCES += \ tst_nameregexp.cpp \ tst_vlayoutdetail.cpp \ tst_varc.cpp \ - stable.cpp + stable.cpp \ + tst_measurementregexp.cpp HEADERS += \ tst_vposter.h \ @@ -52,7 +53,8 @@ HEADERS += \ tst_nameregexp.h \ tst_vlayoutdetail.h \ tst_varc.h \ - stable.h + stable.h \ + tst_measurementregexp.h # Set using ccache. Function enable_ccache() defined in common.pri. $$enable_ccache() @@ -115,6 +117,42 @@ CONFIG(debug, debug|release){ } } +#VPatternDB static library (depend on vgeometry, vmisc, VLayout) +unix|win32: LIBS += -L$$OUT_PWD/../../libs/vpatterndb/$${DESTDIR} -lvpatterndb + +INCLUDEPATH += $$PWD/../../libs/vpatterndb +DEPENDPATH += $$PWD/../../libs/vpatterndb + +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 + +#VMisc static library +unix|win32: LIBS += -L$$OUT_PWD/../../libs/vmisc/$${DESTDIR}/ -lvmisc + +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 + +# VGeometry static library (depend on ifc) +unix|win32: LIBS += -L$$OUT_PWD/../../libs/vgeometry/$${DESTDIR} -lvgeometry + +INCLUDEPATH += $$PWD/../../libs/vgeometry +DEPENDPATH += $$PWD/../../libs/vgeometry + +win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vgeometry/$${DESTDIR}/vgeometry.lib +else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vgeometry/$${DESTDIR}/libvgeometry.a + +# IFC static library (depend on QMuParser) +unix|win32: LIBS += -L$$OUT_PWD/../../libs/ifc/$${DESTDIR}/ -lifc + +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 + # VLayout static library unix|win32: LIBS += -L$$OUT_PWD/../../libs/vlayout/$${DESTDIR} -lvlayout @@ -124,11 +162,10 @@ DEPENDPATH += $$PWD/../../libs/vlayout win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vlayout/$${DESTDIR}/vlayout.lib else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vlayout/$${DESTDIR}/libvlayout.a -# VGeometry static library -unix|win32: LIBS += -L$$OUT_PWD/../../libs/vgeometry/$${DESTDIR} -lvgeometry +# QMuParser library +win32:CONFIG(release, debug|release): LIBS += -L$${OUT_PWD}/../../libs/qmuparser/$${DESTDIR} -lqmuparser2 +else:win32:CONFIG(debug, debug|release): LIBS += -L$${OUT_PWD}/../../libs/qmuparser/$${DESTDIR} -lqmuparser2 +else:unix: LIBS += -L$${OUT_PWD}/../../libs/qmuparser/$${DESTDIR} -lqmuparser -INCLUDEPATH += $$PWD/../../libs/vgeometry -DEPENDPATH += $$PWD/../../libs/vgeometry - -win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vgeometry/$${DESTDIR}/vgeometry.lib -else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vgeometry/$${DESTDIR}/libvgeometry.a +INCLUDEPATH += $${PWD}/../../libs/qmuparser +DEPENDPATH += $${PWD}/../../libs/qmuparser diff --git a/src/test/ValentinaTest/qttestmainlambda.cpp b/src/test/ValentinaTest/qttestmainlambda.cpp index 08a415890..53346a4e0 100644 --- a/src/test/ValentinaTest/qttestmainlambda.cpp +++ b/src/test/ValentinaTest/qttestmainlambda.cpp @@ -34,6 +34,7 @@ #include "tst_nameregexp.h" #include "tst_vlayoutdetail.h" #include "tst_varc.h" +#include "tst_measurementregexp.h" int main(int argc, char** argv) { @@ -52,6 +53,7 @@ int main(int argc, char** argv) ASSERT_TEST(new TST_NameRegExp()); ASSERT_TEST(new TST_VLayoutDetail()); ASSERT_TEST(new TST_VArc()); + ASSERT_TEST(new TST_MeasurementRegExp()); return status; } diff --git a/src/test/ValentinaTest/tst_measurementregexp.cpp b/src/test/ValentinaTest/tst_measurementregexp.cpp new file mode 100644 index 000000000..8d94bc86c --- /dev/null +++ b/src/test/ValentinaTest/tst_measurementregexp.cpp @@ -0,0 +1,234 @@ +/************************************************************************ + ** + ** @file tst_measurementregexp.cpp + ** @author Roman Telezhynskyi + ** @date 16 9, 2015 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentine project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 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 . + ** + *************************************************************************/ + +#include "tst_measurementregexp.h" +#include "../qmuparser/qmudef.h" +#include "../vmisc/def.h" +#include "../vpatterndb/vtranslatemeasurements.h" + +#include +#include + +enum ErrorState {ErrorLoad = 0, ErrorInstall, ErrorSize, NoError}; + +//--------------------------------------------------------------------------------------------------------------------- +TST_MeasurementRegExp::TST_MeasurementRegExp(QObject *parent) + :QObject(parent), + pmsTranslator(nullptr), + trMs(nullptr) +{ +} + +//--------------------------------------------------------------------------------------------------------------------- +TST_MeasurementRegExp::~TST_MeasurementRegExp() +{ + delete pmsTranslator; + delete trMs; +} + +//--------------------------------------------------------------------------------------------------------------------- +// cppcheck-suppress unusedFunction +void TST_MeasurementRegExp::TestOriginalMeasurementNamesRegExp() +{ + const QStringList originalNames = OriginalNames(); + const QRegularExpression re(NameRegExp()); + + foreach(const QString &str, originalNames) + { + QCOMPARE(re.match(str).hasMatch(), true); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +// cppcheck-suppress unusedFunction +void TST_MeasurementRegExp::TestMeasurementRegExp() +{ + const int systemCounts = 55; + const QStringList locales {"ru_RU", "uk_UA", "de_DE", "cs_CZ", "he_IL", "fr_FR", "it_IT", "nl_NL", "id_ID", + "es_ES", "fi_FI", "en_US"}; + + { + const int combinations = systemCounts * locales.size(); // 55*12=660 + + QDir dir(TranslationsPath()); + const QStringList fileNames = dir.entryList(QStringList("measurements_p*_*.qm")); + + QVERIFY2(combinations == fileNames.size(), "Unexpected count of files."); + } + + for(int s = 0; s < systemCounts; ++s) + { + for(int l = 0, sz = locales.size(); l < sz; ++l) + { + const int res = LoadTranslation(QString("p%1").arg(s), locales.at(l)); + + switch(res) + { + case ErrorInstall: + case ErrorSize: + case ErrorLoad: + { + const QString message = QString("Failed to check translation for system = p%1 and locale = %2") + .arg(s) + .arg(locales.at(l)); + QFAIL(message.toUtf8().constData()); + break; + } + case NoError: + { + CheckNames(); + + if (not pmsTranslator.isNull()) + { + const bool result = QCoreApplication::removeTranslator(pmsTranslator); + + if (result == false) + { + const QString message = QString("Can't remove translation for system = p%1 and locale = %2") + .arg(s) + .arg(locales.at(l)); + QWARN(message.toUtf8().constData()); + } + delete pmsTranslator; + } + } + default: + QWARN("Unexpected state"); + } + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +QString TST_MeasurementRegExp::TranslationsPath() const +{ + return QApplication::applicationDirPath() + QStringLiteral("/../../../app/valentina/bin/translations"); +} + +//--------------------------------------------------------------------------------------------------------------------- +int TST_MeasurementRegExp::LoadTranslation(const QString &checkedSystem, const QString &checkedLocale) +{ + const QString path = TranslationsPath(); + const QString file = QString("measurements_%1_%2.qm").arg(checkedSystem).arg(checkedLocale); + + if (QFileInfo(path+"/"+file).size() <= 34) + { + const QString message = QString("Translation for system = %1 and locale = %2 is empty. \nFull path: %3/%4") + .arg(checkedSystem) + .arg(checkedLocale) + .arg(path) + .arg(file); + QWARN(message.toUtf8().constData()); + + return ErrorSize; + } + + pmsTranslator = new QTranslator(this); + + if (not pmsTranslator->load(file, path)) + { + const QString message = QString("Can't load translation for system = %1 and locale = %2. \nFull path: %3/%4") + .arg(checkedSystem) + .arg(checkedLocale) + .arg(path) + .arg(file); + QWARN(message.toUtf8().constData()); + + delete pmsTranslator; + + return ErrorLoad; + } + + if (not QCoreApplication::installTranslator(pmsTranslator)) + { + const QString message = QString("Can't install translation for system = %1 and locale = %2. \nFull path: %3/%4") + .arg(checkedSystem) + .arg(checkedLocale) + .arg(path) + .arg(file); + QWARN(message.toUtf8().constData()); + + delete pmsTranslator; + + return ErrorInstall; + } + + InitTrMs();//Very important do it after load QM file. + + return NoError; +} + +//--------------------------------------------------------------------------------------------------------------------- +void TST_MeasurementRegExp::InitTrMs() +{ + if (trMs != nullptr) + { + trMs->Retranslate(); + } + else + { + trMs = new VTranslateMeasurements(); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void TST_MeasurementRegExp::CheckNames() const +{ + const QStringList originalNames = OriginalNames(); + const QRegularExpression re(NameRegExp()); + + foreach(const QString &str, originalNames) + { + const QString translated = trMs->MToUser(str); + QCOMPARE(re.match(translated).hasMatch(), true); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +QStringList TST_MeasurementRegExp::OriginalNames() const +{ + const QStringList originalNames = QStringList() << ListGroupA() + << ListGroupB() + << ListGroupC() + << ListGroupD() + << ListGroupE() + << ListGroupF() + << ListGroupG() + << ListGroupH() + << ListGroupI() + << ListGroupJ() + << ListGroupK() + << ListGroupL() + << ListGroupM() + << ListGroupN() + << ListGroupO() + << ListGroupP() + << ListGroupQ(); + + return originalNames; +} diff --git a/src/test/ValentinaTest/tst_measurementregexp.h b/src/test/ValentinaTest/tst_measurementregexp.h new file mode 100644 index 000000000..0385bd847 --- /dev/null +++ b/src/test/ValentinaTest/tst_measurementregexp.h @@ -0,0 +1,61 @@ +/************************************************************************ + ** + ** @file tst_measurementregexp.h + ** @author Roman Telezhynskyi + ** @date 16 9, 2015 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentine project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 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 TST_MEASUREMENTREGEXP_H +#define TST_MEASUREMENTREGEXP_H + +#include + +class QTranslator; +class VTranslateMeasurements; + +class TST_MeasurementRegExp : public QObject +{ + Q_OBJECT +public: + explicit TST_MeasurementRegExp(QObject *parent = 0); + virtual ~TST_MeasurementRegExp() Q_DECL_OVERRIDE; + +private slots: + void TestOriginalMeasurementNamesRegExp(); + void TestMeasurementRegExp(); + +private: + Q_DISABLE_COPY(TST_MeasurementRegExp) + + QPointer pmsTranslator; + VTranslateMeasurements *trMs; + + QString TranslationsPath() const; + int LoadTranslation(const QString &checkedSystem, const QString &checkedLocale); + void InitTrMs(); + void CheckNames() const; + QStringList OriginalNames() const; +}; + +#endif // TST_MEASUREMENTREGEXP_H