File indexing completed on 2024-04-28 04:32:04
0001 /* 0002 * Copyright (C) 2010-2022 by Stephen Allewell 0003 * steve.allewell@gmail.com 0004 * 0005 * This program is free software; you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation; either version 2 of the License, or 0008 * (at your option) any later version. 0009 */ 0010 0011 #include "MainWindow.h" 0012 0013 #include <QAction> 0014 #include <QActionGroup> 0015 #include <QClipboard> 0016 #include <QDataStream> 0017 #include <QDockWidget> 0018 #include <QFileDialog> 0019 #include <QGridLayout> 0020 #include <QMenu> 0021 #include <QMimeData> 0022 #include <QPaintEngine> 0023 #include <QPainter> 0024 #include <QPrintDialog> 0025 #include <QPrintEngine> 0026 #include <QPrintPreviewDialog> 0027 #include <QPrinter> 0028 #include <QProgressDialog> 0029 #include <QSaveFile> 0030 #include <QScrollArea> 0031 #include <QTemporaryFile> 0032 #include <QUndoView> 0033 #include <QUrl> 0034 0035 #include <KActionCollection> 0036 #include <KConfigDialog> 0037 #include <KIO/FileCopyJob> 0038 #include <KIO/StatJob> 0039 #include <KLocalizedString> 0040 #include <KMessageBox> 0041 #include <KRecentFilesAction> 0042 #include <KSelectAction> 0043 #include <KXMLGUIFactory> 0044 #include <kwidgetsaddons_version.h> 0045 0046 #include "BackgroundImage.h" 0047 #include "Commands.h" 0048 #include "ConfigurationDialogs.h" 0049 #include "Document.h" 0050 #include "Editor.h" 0051 #include "ExtendPatternDlg.h" 0052 #include "FilePropertiesDlg.h" 0053 #include "Floss.h" 0054 #include "FlossScheme.h" 0055 #include "ImportImageDlg.h" 0056 #include "Palette.h" 0057 #include "PaletteManagerDlg.h" 0058 #include "PaperSizes.h" 0059 #include "Preview.h" 0060 #include "PrintSetupDlg.h" 0061 #include "Scale.h" 0062 #include "ScaledPixmapLabel.h" 0063 #include "SchemeManager.h" 0064 #include "SymbolLibrary.h" 0065 #include "SymbolManager.h" 0066 #include "configuration.h" 0067 0068 MainWindow::MainWindow() 0069 : m_printer(nullptr) 0070 { 0071 setupActions(); 0072 } 0073 0074 MainWindow::MainWindow(const QUrl &url) 0075 : m_printer(nullptr) 0076 { 0077 setupMainWindow(); 0078 setupLayout(); 0079 setupDockWindows(); 0080 setupActions(); 0081 setupDocument(); 0082 setupConnections(); 0083 setupActionDefaults(); 0084 loadSettings(); 0085 fileOpen(url); 0086 setupActionsFromDocument(); 0087 setCaption(m_document->url().fileName(), !m_document->undoStack().isClean()); 0088 this->findChild<QDockWidget *>(QStringLiteral("ImportedImage#"))->hide(); 0089 } 0090 0091 MainWindow::MainWindow(const QString &source) 0092 : m_printer(nullptr) 0093 { 0094 setupMainWindow(); 0095 setupLayout(); 0096 setupDockWindows(); 0097 setupActions(); 0098 setupDocument(); 0099 setupConnections(); 0100 setupActionDefaults(); 0101 loadSettings(); 0102 convertImage(source); 0103 setupActionsFromDocument(); 0104 setCaption(m_document->url().fileName(), !m_document->undoStack().isClean()); 0105 this->findChild<QDockWidget *>(QStringLiteral("ImportedImage#"))->show(); 0106 } 0107 0108 void MainWindow::setupMainWindow() 0109 { 0110 setObjectName(QStringLiteral("MainWindow#")); 0111 setAutoSaveSettings(); 0112 } 0113 0114 void MainWindow::setupLayout() 0115 { 0116 QScrollArea *scrollArea = new QScrollArea(); 0117 scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); 0118 scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); 0119 m_editor = new Editor(scrollArea); 0120 scrollArea->installEventFilter(m_editor); 0121 scrollArea->setWidget(m_editor); 0122 0123 m_horizontalScale = m_editor->horizontalScale(); 0124 m_verticalScale = m_editor->verticalScale(); 0125 0126 QWidget *layout = new QWidget(); 0127 0128 QGridLayout *gridLayout = new QGridLayout(layout); 0129 gridLayout->addWidget(m_horizontalScale, 0, 1); 0130 gridLayout->addWidget(m_verticalScale, 1, 0); 0131 gridLayout->addWidget(scrollArea, 1, 1); 0132 0133 setCentralWidget(layout); 0134 0135 setStatusBar(nullptr); 0136 } 0137 0138 void MainWindow::setupDocument() 0139 { 0140 m_document = new Document(); 0141 0142 m_editor->setDocument(m_document); 0143 m_editor->setPreview(m_preview); 0144 m_palette->setDocument(m_document); 0145 m_preview->setDocument(m_document); 0146 m_history->setStack(&(m_document->undoStack())); 0147 0148 m_document->addView(m_editor); 0149 m_document->addView(m_preview); 0150 m_document->addView(m_palette); 0151 } 0152 0153 void MainWindow::setupConnections() 0154 { 0155 KActionCollection *actions = actionCollection(); 0156 0157 connect(&(m_document->undoStack()), &QUndoStack::canUndoChanged, actions->action(QStringLiteral("edit_undo")), &QAction::setEnabled); 0158 connect(&(m_document->undoStack()), &QUndoStack::canUndoChanged, actions->action(QStringLiteral("file_revert")), &QAction::setEnabled); 0159 connect(&(m_document->undoStack()), &QUndoStack::canRedoChanged, actions->action(QStringLiteral("edit_redo")), &QAction::setEnabled); 0160 connect(QApplication::clipboard(), &QClipboard::dataChanged, this, &MainWindow::clipboardDataChanged); 0161 connect(m_editor, &Editor::selectionMade, actionCollection()->action(QStringLiteral("edit_cut")), &QAction::setEnabled); 0162 connect(m_editor, &Editor::selectionMade, actionCollection()->action(QStringLiteral("edit_copy")), &QAction::setEnabled); 0163 connect(m_editor, &Editor::selectionMade, actionCollection()->action(QStringLiteral("mirrorHorizontal")), &QAction::setEnabled); 0164 connect(m_editor, &Editor::selectionMade, actionCollection()->action(QStringLiteral("mirrorVertical")), &QAction::setEnabled); 0165 connect(m_editor, &Editor::selectionMade, actionCollection()->action(QStringLiteral("rotate90")), &QAction::setEnabled); 0166 connect(m_editor, &Editor::selectionMade, actionCollection()->action(QStringLiteral("rotate180")), &QAction::setEnabled); 0167 connect(m_editor, &Editor::selectionMade, actionCollection()->action(QStringLiteral("rotate270")), &QAction::setEnabled); 0168 connect(m_editor, &Editor::selectionMade, actionCollection()->action(QStringLiteral("patternCropToSelection")), &QAction::setEnabled); 0169 connect(m_editor, &Editor::selectionMade, actionCollection()->action(QStringLiteral("insertColumns")), &QAction::setEnabled); 0170 connect(m_editor, &Editor::selectionMade, actionCollection()->action(QStringLiteral("insertRows")), &QAction::setEnabled); 0171 connect(&(m_document->undoStack()), &QUndoStack::undoTextChanged, this, &MainWindow::undoTextChanged); 0172 connect(&(m_document->undoStack()), &QUndoStack::redoTextChanged, this, &MainWindow::redoTextChanged); 0173 connect(&(m_document->undoStack()), &QUndoStack::cleanChanged, this, &MainWindow::documentModified); 0174 connect(m_palette, &Palette::colorSelected, m_editor, static_cast<void (Editor::*)()>(&Editor::drawContents)); 0175 connect(m_palette, static_cast<void (Palette::*)(int, int)>(&Palette::swapColors), this, &MainWindow::paletteSwapColors); 0176 connect(m_palette, static_cast<void (Palette::*)(int, int)>(&Palette::replaceColor), this, &MainWindow::paletteReplaceColor); 0177 connect(m_palette, &Palette::signalStateChanged, this, static_cast<void (KXmlGuiWindow::*)(const QString &, bool)>(&KXmlGuiWindow::slotStateChanged)); 0178 connect(m_palette, &Palette::customContextMenuRequested, this, &MainWindow::paletteContextMenu); 0179 connect(m_editor, &Editor::changedVisibleCells, m_preview, &Preview::setVisibleCells); 0180 connect(m_preview, 0181 static_cast<void (Preview::*)(QPoint)>(&Preview::clicked), 0182 m_editor, 0183 static_cast<void (Editor::*)(const QPoint &)>(&Editor::previewClicked)); 0184 connect(m_preview, 0185 static_cast<void (Preview::*)(QRect)>(&Preview::clicked), 0186 m_editor, 0187 static_cast<void (Editor::*)(const QRect &)>(&Editor::previewClicked)); 0188 } 0189 0190 void MainWindow::setupActionDefaults() 0191 { 0192 KActionCollection *actions = actionCollection(); 0193 0194 actions->action(QStringLiteral("maskStitch"))->setChecked(false); 0195 actions->action(QStringLiteral("maskColor"))->setChecked(false); 0196 actions->action(QStringLiteral("maskBackstitch"))->setChecked(false); 0197 actions->action(QStringLiteral("maskKnot"))->setChecked(false); 0198 0199 actions->action(QStringLiteral("stitchFull"))->trigger(); // Select full stitch 0200 0201 actions->action(QStringLiteral("toolPaint"))->trigger(); // Select paint tool 0202 0203 clipboardDataChanged(); 0204 } 0205 0206 MainWindow::~MainWindow() 0207 { 0208 delete m_printer; 0209 } 0210 0211 Editor *MainWindow::editor() 0212 { 0213 return m_editor; 0214 } 0215 0216 Preview *MainWindow::preview() 0217 { 0218 return m_preview; 0219 } 0220 0221 Palette *MainWindow::palette() 0222 { 0223 return m_palette; 0224 } 0225 0226 bool MainWindow::queryClose() 0227 { 0228 if (m_document->undoStack().isClean()) { 0229 return true; 0230 } 0231 0232 while (true) { 0233 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0234 int messageBoxResult = KMessageBox::warningTwoActionsCancel(this, 0235 #else 0236 int messageBoxResult = KMessageBox::warningYesNoCancel(this, 0237 #endif 0238 i18n("Save changes to document?"), 0239 QString(), 0240 KStandardGuiItem::save(), 0241 KStandardGuiItem::discard(), 0242 KStandardGuiItem::cancel()); 0243 0244 switch (messageBoxResult) { 0245 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0246 case KMessageBox::PrimaryAction: 0247 #else 0248 case KMessageBox::Yes: 0249 #endif 0250 fileSave(); 0251 0252 if (m_document->undoStack().isClean()) { 0253 return true; 0254 } else { 0255 KMessageBox::error(this, i18n("Unable to save the file")); 0256 } 0257 0258 break; 0259 0260 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0261 case KMessageBox::SecondaryAction: 0262 #else 0263 case KMessageBox::No: 0264 #endif 0265 return true; 0266 0267 case KMessageBox::Cancel: 0268 return false; 0269 } 0270 } 0271 } 0272 0273 void MainWindow::setupActionsFromDocument() 0274 { 0275 KActionCollection *actions = actionCollection(); 0276 0277 actions->action(QStringLiteral("file_revert"))->setEnabled(!m_document->undoStack().isClean()); 0278 actions->action(QStringLiteral("edit_undo"))->setEnabled(m_document->undoStack().canUndo()); 0279 actions->action(QStringLiteral("edit_redo"))->setEnabled(m_document->undoStack().canRedo()); 0280 0281 updateBackgroundImageActionLists(); 0282 } 0283 0284 void MainWindow::fileNew() 0285 { 0286 MainWindow *window = new MainWindow(QUrl()); 0287 window->show(); 0288 } 0289 0290 void MainWindow::fileOpen() 0291 { 0292 fileOpen(QFileDialog::getOpenFileUrl(this, 0293 i18n("Open file"), 0294 QUrl::fromLocalFile(QDir::homePath()), 0295 i18n("KXStitch Patterns (*.kxs);;PC Stitch Patterns (*.pat);;All Files (*)"))); 0296 } 0297 0298 void MainWindow::fileOpen(const QUrl &url) 0299 { 0300 MainWindow *window; 0301 bool docEmpty = (m_document->undoStack().isClean() && (m_document->url().toString() == i18n("Untitled"))); 0302 0303 if (url.isValid()) { 0304 if (docEmpty) { 0305 QTemporaryFile tmpFile; 0306 0307 if (tmpFile.open()) { 0308 tmpFile.close(); 0309 0310 KIO::FileCopyJob *job = KIO::file_copy(url, QUrl::fromLocalFile(tmpFile.fileName()), -1, KIO::Overwrite); 0311 0312 if (job->exec()) { 0313 /* In earlier versions of KDE/Qt creating a QDataStream on tmpFile allowed reading the data from the copied file. 0314 * Somewhere after KDE 5.55.0/Qt 5.9.7 this no longer possible as tmpFile size() is reported with a length of 0 0315 * whereas previously tmpFile size() was reported as the size of the copied file. 0316 * Therefore open a new QFile on the temporary file after downloading to allow reading. 0317 */ 0318 QFile reader(tmpFile.fileName()); 0319 if (reader.open(QIODevice::ReadOnly)) { 0320 QDataStream stream(&reader); 0321 0322 try { 0323 m_document->readKXStitch(stream); 0324 m_document->setUrl(url); 0325 KRecentFilesAction *action = static_cast<KRecentFilesAction *>(actionCollection()->action(QStringLiteral("file_open_recent"))); 0326 action->addUrl(url); 0327 action->saveEntries(KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("RecentFiles"))); 0328 } catch (const InvalidFile &e) { 0329 stream.device()->seek(0); 0330 0331 try { 0332 m_document->readPCStitch(stream); 0333 } catch (const InvalidFile &e) { 0334 KMessageBox::error(nullptr, i18n("The file does not appear to be a recognized cross stitch file.")); 0335 } 0336 } catch (const InvalidFileVersion &e) { 0337 KMessageBox::error(nullptr, i18n("This version of the file is not supported.\n%1", e.version)); 0338 } catch (const FailedReadFile &e) { 0339 KMessageBox::error(nullptr, i18n("Failed to read the file.\n%1.", e.status)); 0340 m_document->initialiseNew(); 0341 } 0342 0343 setupActionsFromDocument(); 0344 m_editor->readDocumentSettings(); 0345 m_preview->readDocumentSettings(); 0346 m_palette->update(); 0347 documentModified(true); // this is the clean value true 0348 0349 reader.close(); 0350 } else { 0351 KMessageBox::error(nullptr, reader.errorString()); 0352 } 0353 } else { 0354 KMessageBox::error(nullptr, job->errorString()); 0355 } 0356 0357 tmpFile.close(); 0358 } else { 0359 KMessageBox::error(nullptr, tmpFile.errorString()); 0360 } 0361 } else { 0362 window = new MainWindow(url); 0363 window->show(); 0364 } 0365 } 0366 } 0367 0368 void MainWindow::fileSave() 0369 { 0370 QUrl url = m_document->url(); 0371 0372 if (url.toString() == i18n("Untitled")) { 0373 fileSaveAs(); 0374 } else { 0375 // ### Why use QUrl everywhere if this only supports local files? 0376 QSaveFile file(url.toLocalFile()); 0377 0378 if (file.open(QIODevice::WriteOnly)) { 0379 QDataStream stream(&file); 0380 0381 try { 0382 m_document->write(stream); 0383 0384 if (!file.commit()) { 0385 throw FailedWriteFile(stream.status()); 0386 } 0387 0388 m_document->undoStack().setClean(); 0389 } catch (const FailedWriteFile &e) { 0390 KMessageBox::error(nullptr, QString(i18n("Failed to save the file.\n%1", file.errorString()))); 0391 file.cancelWriting(); 0392 } 0393 } else { 0394 KMessageBox::error(nullptr, QString(i18n("Failed to open the file.\n%1", file.errorString()))); 0395 } 0396 } 0397 } 0398 0399 void MainWindow::fileSaveAs() 0400 { 0401 QUrl url = QFileDialog::getSaveFileUrl(this, i18n("Save As..."), QUrl::fromLocalFile(QDir::homePath()), i18n("Cross Stitch Patterns (*.kxs)")); 0402 0403 if (url.isValid()) { 0404 m_document->setUrl(url); 0405 fileSave(); 0406 KRecentFilesAction *action = static_cast<KRecentFilesAction *>(actionCollection()->action(QStringLiteral("file_open_recent"))); 0407 action->addUrl(url); 0408 action->saveEntries(KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("RecentFiles"))); 0409 } 0410 } 0411 0412 void MainWindow::fileRevert() 0413 { 0414 if (!m_document->undoStack().isClean()) { 0415 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0416 if (KMessageBox::warningTwoActions(this, 0417 #else 0418 if (KMessageBox::warningYesNo(this, 0419 #endif 0420 i18n("Revert changes to document?"), 0421 QString(), 0422 KGuiItem(i18nc("@action:button", "Revert"), QStringLiteral("document-revert")), 0423 KStandardGuiItem::cancel()) 0424 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0425 == KMessageBox::PrimaryAction) { 0426 #else 0427 == KMessageBox::Yes) { 0428 #endif 0429 m_document->undoStack().setIndex(m_document->undoStack().cleanIndex()); 0430 } 0431 } 0432 } 0433 0434 void MainWindow::filePrintSetup() 0435 { 0436 if (m_printer == nullptr) { 0437 m_printer = new QPrinter(); 0438 } 0439 0440 QPointer<PrintSetupDlg> printSetupDlg = new PrintSetupDlg(this, m_document, m_printer); 0441 0442 if (printSetupDlg->exec() == QDialog::Accepted) { 0443 m_document->undoStack().push(new UpdatePrinterConfigurationCommand(m_document, printSetupDlg->printerConfiguration())); 0444 } 0445 0446 delete printSetupDlg; 0447 } 0448 0449 void MainWindow::filePrint() 0450 { 0451 if (m_printer == nullptr) { 0452 filePrintSetup(); 0453 } 0454 0455 if (!m_document->printerConfiguration().pages().isEmpty()) { 0456 m_printer->setFullPage(true); 0457 m_printer->setPrintRange(QPrinter::AllPages); 0458 m_printer->setFromTo(1, m_document->printerConfiguration().pages().count()); 0459 0460 QPointer<QPrintDialog> printDialog = new QPrintDialog(m_printer, this); 0461 0462 if (printDialog->exec() == QDialog::Accepted) { 0463 printPages(); 0464 } 0465 0466 delete printDialog; 0467 } else { 0468 KMessageBox::information(this, i18n("There is nothing to print")); 0469 } 0470 } 0471 0472 void MainWindow::printPages() 0473 { 0474 QList<Page *> pages = m_document->printerConfiguration().pages(); 0475 0476 int fromPage = 1; 0477 int toPage = pages.count(); 0478 0479 if (m_printer->printRange() == QPrinter::PageRange) { 0480 fromPage = m_printer->fromPage(); 0481 toPage = m_printer->toPage(); 0482 } 0483 0484 while (toPage < pages.count()) 0485 pages.removeLast(); 0486 while (--fromPage) 0487 pages.removeFirst(); 0488 0489 int totalPages = pages.count(); 0490 0491 const Page *page = (m_printer->pageOrder() == QPrinter::FirstPageFirst) ? pages.takeFirst() : pages.takeLast(); 0492 0493 m_printer->setPageSize(page->pageSize()); 0494 m_printer->setPageOrientation(page->orientation()); 0495 0496 QPainter painter; 0497 painter.begin(m_printer); 0498 painter.setRenderHint(QPainter::Antialiasing, true); 0499 0500 for (int p = 0; p < totalPages;) { 0501 int paperWidth = PageSizes::width(page->pageSize().id(), page->orientation()); 0502 int paperHeight = PageSizes::height(page->pageSize().id(), page->orientation()); 0503 0504 painter.setWindow(0, 0, paperWidth, paperHeight); 0505 0506 page->render(m_document, &painter); 0507 0508 if (++p < totalPages) { 0509 page = (m_printer->pageOrder() == QPrinter::FirstPageFirst) ? pages.takeFirst() : pages.takeLast(); 0510 0511 m_printer->setPageSize(page->pageSize()); 0512 m_printer->setPageOrientation(page->orientation()); 0513 0514 m_printer->newPage(); 0515 } 0516 } 0517 0518 painter.end(); 0519 } 0520 0521 void MainWindow::fileImportImage() 0522 { 0523 MainWindow *window; 0524 bool docEmpty = ((m_document->undoStack().isClean()) && (m_document->url().toString() == i18n("Untitled"))); 0525 QUrl url = QFileDialog::getOpenFileUrl(this, 0526 i18n("Import Image"), 0527 QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)), 0528 i18n("Images (*.bmp *.gif *.jpg *.png *.pbm *.pgm *.ppm *.xbm *.xpm *.svg)")); 0529 0530 if (url.isValid()) { 0531 QTemporaryFile tmpFile; 0532 0533 if (tmpFile.open()) { 0534 KIO::FileCopyJob *job = KIO::file_copy(url, QUrl::fromLocalFile(tmpFile.fileName()), -1, KIO::Overwrite); 0535 0536 if (job->exec()) { 0537 if (docEmpty) { 0538 convertImage(tmpFile.fileName()); 0539 this->findChild<QDockWidget *>(QStringLiteral("ImportedImage#"))->show(); 0540 } else { 0541 window = new MainWindow(tmpFile.fileName()); 0542 window->show(); 0543 } 0544 } else { 0545 KMessageBox::error(nullptr, job->errorString()); 0546 } 0547 } 0548 } 0549 } 0550 0551 void MainWindow::convertImage(const QString &source) 0552 { 0553 Magick::Image image(source.toStdString()); 0554 0555 QMap<int, QColor> documentFlosses; 0556 QList<qint16> symbolIndexes = SymbolManager::library(Configuration::palette_DefaultSymbolLibrary())->indexes(); 0557 0558 QPointer<ImportImageDlg> importImageDlg = new ImportImageDlg(this, image); 0559 0560 if (importImageDlg->exec()) { 0561 Magick::Image convertedImage = importImageDlg->convertedImage(); 0562 0563 int imageWidth = convertedImage.columns(); 0564 int imageHeight = convertedImage.rows(); 0565 int documentWidth = imageWidth; 0566 int documentHeight = imageHeight; 0567 0568 bool useFractionals = importImageDlg->useFractionals(); 0569 0570 /* 0571 * ImageMagick prior to V7 used matte (opacity) to determine if an image has transparency. 0572 * 0.0 for transparent to 1.0 for opaque 0573 * 0574 * ImageMagick V7 now uses alpha (transparency). 0575 * 1.0 for transparent to 0.0 for opaque 0576 * 0577 * Access to pixels has changed too, V7 can use pixelColor to access the color of a particular 0578 * pixel, but although this was available in V6, it doesn't appear to produce the same result 0579 * and has resulted in black images when importing. 0580 */ 0581 #if MagickLibVersion < 0x700 0582 bool hasTransparency = convertedImage.matte(); 0583 double transparent = 1.0; 0584 const Magick::PixelPacket *pixels = convertedImage.getConstPixels(0, 0, imageWidth, imageHeight); 0585 #else 0586 bool hasTransparency = convertedImage.alpha(); 0587 double transparent = 0.0; 0588 #endif 0589 0590 bool ignoreColor = importImageDlg->ignoreColor(); 0591 Magick::Color ignoreColorValue = importImageDlg->ignoreColorValue(); 0592 0593 int pixelCount = imageWidth * imageHeight; 0594 0595 if (useFractionals) { 0596 documentWidth /= 2; 0597 documentHeight /= 2; 0598 } 0599 0600 QString schemeName = importImageDlg->flossScheme(); 0601 FlossScheme *flossScheme = SchemeManager::scheme(schemeName); 0602 0603 QUndoCommand *importImageCommand = new ImportImageCommand(m_document); 0604 new ResizeDocumentCommand(m_document, documentWidth, documentHeight, importImageCommand); 0605 new ChangeSchemeCommand(m_document, schemeName, importImageCommand); 0606 0607 QProgressDialog progress(i18n("Converting to stitches"), i18n("Cancel"), 0, pixelCount, this); 0608 progress.setWindowModality(Qt::WindowModal); 0609 0610 for (int dy = 0; dy < imageHeight; dy++) { 0611 progress.setValue(dy * imageWidth); 0612 QApplication::processEvents(); 0613 0614 if (progress.wasCanceled()) { 0615 delete importImageDlg; 0616 delete importImageCommand; 0617 return; 0618 } 0619 0620 for (int dx = 0; dx < imageWidth; dx++) { 0621 #if MagickLibVersion < 0x700 0622 Magick::ColorRGB rgb = Magick::Color(*pixels++); 0623 #else 0624 Magick::ColorRGB rgb = convertedImage.pixelColor(dx, dy); 0625 #endif 0626 0627 if (hasTransparency && (rgb.alpha() == transparent)) { 0628 // ignore this pixel as it is transparent 0629 } else { 0630 if (!(ignoreColor && (rgb == ignoreColorValue))) { 0631 int flossIndex; 0632 QColor color((int)(255 * rgb.red()), (int)(255 * rgb.green()), (int)(255 * rgb.blue())); 0633 0634 for (flossIndex = 0; flossIndex < documentFlosses.count(); ++flossIndex) { 0635 if (documentFlosses[flossIndex] == color) { 0636 break; 0637 } 0638 } 0639 0640 if (flossIndex == documentFlosses.count()) { // reached the end of the list 0641 qint16 stitchSymbol = symbolIndexes.takeFirst(); 0642 Qt::PenStyle backstitchSymbol(Qt::SolidLine); 0643 Floss *floss = flossScheme->find(color); 0644 0645 DocumentFloss *documentFloss = new DocumentFloss(floss->name(), 0646 stitchSymbol, 0647 backstitchSymbol, 0648 Configuration::palette_StitchStrands(), 0649 Configuration::palette_BackstitchStrands()); 0650 documentFloss->setFlossColor(floss->color()); 0651 new AddDocumentFlossCommand(m_document, flossIndex, documentFloss, importImageCommand); 0652 documentFlosses.insert(flossIndex, color); 0653 } 0654 0655 // at this point 0656 // flossIndex will be the index for the found color 0657 if (useFractionals) { 0658 int zone = (dy % 2) * 2 + (dx % 2); 0659 new AddStitchCommand(m_document, QPoint(dx / 2, dy / 2), stitchMap[0][zone], flossIndex, importImageCommand); 0660 } else { 0661 new AddStitchCommand(m_document, QPoint(dx, dy), Stitch::Full, flossIndex, importImageCommand); 0662 } 0663 } 0664 } 0665 } 0666 } 0667 0668 new SetPropertyCommand(m_document, QStringLiteral("horizontalClothCount"), importImageDlg->horizontalClothCount(), importImageCommand); 0669 new SetPropertyCommand(m_document, QStringLiteral("verticalClothCount"), importImageDlg->verticalClothCount(), importImageCommand); 0670 m_document->undoStack().push(importImageCommand); 0671 0672 convertPreview(source, importImageDlg->croppedArea()); 0673 } 0674 0675 delete importImageDlg; 0676 } 0677 0678 void MainWindow::convertPreview(const QString &source, const QRect &croppedArea) 0679 { 0680 QPixmap pixmap; 0681 pixmap.load(source); 0682 pixmap = pixmap.copy(croppedArea); 0683 m_imageLabel->setPixmap(pixmap); 0684 } 0685 0686 void MainWindow::fileProperties() 0687 { 0688 QPointer<FilePropertiesDlg> filePropertiesDlg = new FilePropertiesDlg(this, m_document); 0689 0690 if (filePropertiesDlg->exec()) { 0691 QUndoCommand *cmd = new FilePropertiesCommand(m_document); 0692 0693 if ((filePropertiesDlg->documentWidth() != m_document->pattern()->stitches().width()) 0694 || (filePropertiesDlg->documentHeight() != m_document->pattern()->stitches().height())) { 0695 new ResizeDocumentCommand(m_document, filePropertiesDlg->documentWidth(), filePropertiesDlg->documentHeight(), cmd); 0696 } 0697 0698 if (filePropertiesDlg->unitsFormat() 0699 != static_cast<Configuration::EnumDocument_UnitsFormat::type>(m_document->property(QStringLiteral("unitsFormat")).toInt())) { 0700 new SetPropertyCommand(m_document, QStringLiteral("unitsFormat"), QVariant(filePropertiesDlg->unitsFormat()), cmd); 0701 } 0702 0703 if (filePropertiesDlg->horizontalClothCount() != m_document->property(QStringLiteral("horizontalClothCount")).toDouble()) { 0704 new SetPropertyCommand(m_document, QStringLiteral("horizontalClothCount"), QVariant(filePropertiesDlg->horizontalClothCount()), cmd); 0705 } 0706 0707 if (filePropertiesDlg->clothCountLink() != m_document->property(QStringLiteral("clothCountLink")).toBool()) { 0708 new SetPropertyCommand(m_document, QStringLiteral("clothCountLink"), QVariant(filePropertiesDlg->clothCountLink()), cmd); 0709 } 0710 0711 if (filePropertiesDlg->verticalClothCount() != m_document->property(QStringLiteral("verticalClothCount")).toDouble()) { 0712 new SetPropertyCommand(m_document, QStringLiteral("verticalClothCount"), QVariant(filePropertiesDlg->verticalClothCount()), cmd); 0713 } 0714 0715 if (filePropertiesDlg->clothCountUnits() 0716 != static_cast<Configuration::EnumEditor_ClothCountUnits::type>(m_document->property(QStringLiteral("clothCountUnits")).toInt())) { 0717 new SetPropertyCommand(m_document, QStringLiteral("clothCountUnits"), QVariant(filePropertiesDlg->clothCountUnits()), cmd); 0718 } 0719 0720 if (filePropertiesDlg->title() != m_document->property(QStringLiteral("title")).toString()) { 0721 new SetPropertyCommand(m_document, QStringLiteral("title"), QVariant(filePropertiesDlg->title()), cmd); 0722 } 0723 0724 if (filePropertiesDlg->author() != m_document->property(QStringLiteral("author")).toString()) { 0725 new SetPropertyCommand(m_document, QStringLiteral("author"), QVariant(filePropertiesDlg->author()), cmd); 0726 } 0727 0728 if (filePropertiesDlg->copyright() != m_document->property(QStringLiteral("copyright")).toString()) { 0729 new SetPropertyCommand(m_document, QStringLiteral("copyright"), QVariant(filePropertiesDlg->copyright()), cmd); 0730 } 0731 0732 if (filePropertiesDlg->fabric() != m_document->property(QStringLiteral("fabric")).toString()) { 0733 new SetPropertyCommand(m_document, QStringLiteral("fabric"), QVariant(filePropertiesDlg->fabric()), cmd); 0734 } 0735 0736 if (filePropertiesDlg->fabricColor() != m_document->property(QStringLiteral("fabricColor")).value<QColor>()) { 0737 new SetPropertyCommand(m_document, QStringLiteral("fabricColor"), QVariant(filePropertiesDlg->fabricColor()), cmd); 0738 } 0739 0740 if (filePropertiesDlg->instructions() != m_document->property(QStringLiteral("instructions")).toString()) { 0741 new SetPropertyCommand(m_document, QStringLiteral("instructions"), QVariant(filePropertiesDlg->instructions()), cmd); 0742 } 0743 0744 if (filePropertiesDlg->flossScheme() != m_document->pattern()->palette().schemeName()) { 0745 new ChangeSchemeCommand(m_document, filePropertiesDlg->flossScheme(), cmd); 0746 } 0747 0748 if (cmd->childCount()) { 0749 m_document->undoStack().push(cmd); 0750 } else { 0751 delete cmd; 0752 } 0753 } 0754 0755 delete filePropertiesDlg; 0756 } 0757 0758 void MainWindow::fileAddBackgroundImage() 0759 { 0760 QUrl url = QFileDialog::getOpenFileUrl(this, 0761 i18n("Background Image"), 0762 QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)), 0763 i18n("Images (*.bmp *.gif *.jpg *.png *.pbm *.pgm *.ppm *.xbm *.xpm *.svg)")); 0764 0765 if (!url.isEmpty()) { 0766 QRect patternArea(0, 0, m_document->pattern()->stitches().width(), m_document->pattern()->stitches().height()); 0767 QRect selectionArea = m_editor->selectionArea(); 0768 QSharedPointer<BackgroundImage> backgroundImage(new BackgroundImage(url, (selectionArea.isValid() ? selectionArea : patternArea))); 0769 0770 if (backgroundImage->isValid()) { 0771 m_document->undoStack().push(new AddBackgroundImageCommand(m_document, backgroundImage, this)); 0772 } 0773 } 0774 } 0775 0776 void MainWindow::fileRemoveBackgroundImage() 0777 { 0778 QAction *action = qobject_cast<QAction *>(sender()); 0779 m_document->undoStack().push(new RemoveBackgroundImageCommand(m_document, action->data().value<QSharedPointer<BackgroundImage>>(), this)); 0780 } 0781 0782 void MainWindow::fileClose() 0783 { 0784 if (queryClose()) { 0785 m_document->initialiseNew(); 0786 setupActionsFromDocument(); 0787 m_editor->readDocumentSettings(); 0788 m_preview->readDocumentSettings(); 0789 } 0790 0791 close(); 0792 } 0793 0794 void MainWindow::fileQuit() 0795 { 0796 close(); 0797 } 0798 0799 void MainWindow::editUndo() 0800 { 0801 m_document->undoStack().undo(); 0802 } 0803 0804 void MainWindow::editRedo() 0805 { 0806 m_document->undoStack().redo(); 0807 } 0808 0809 void MainWindow::undoTextChanged(const QString &text) 0810 { 0811 actionCollection()->action(QStringLiteral("edit_undo"))->setText(i18n("Undo %1", text)); 0812 } 0813 0814 void MainWindow::redoTextChanged(const QString &text) 0815 { 0816 actionCollection()->action(QStringLiteral("edit_redo"))->setText(i18n("Redo %1", text)); 0817 } 0818 0819 void MainWindow::clipboardDataChanged() 0820 { 0821 actionCollection() 0822 ->action(QStringLiteral("edit_paste")) 0823 ->setEnabled(QApplication::clipboard()->mimeData()->hasFormat(QStringLiteral("application/kxstitch"))); 0824 } 0825 0826 void MainWindow::paletteManager() 0827 { 0828 QPointer<PaletteManagerDlg> paletteManagerDlg = new PaletteManagerDlg(this, m_document); 0829 0830 if (paletteManagerDlg->exec()) { 0831 DocumentPalette palette = paletteManagerDlg->palette(); 0832 0833 if (palette != m_document->pattern()->palette()) { 0834 m_document->undoStack().push(new UpdateDocumentPaletteCommand(m_document, palette)); 0835 } 0836 } 0837 0838 delete paletteManagerDlg; 0839 } 0840 0841 void MainWindow::paletteShowSymbols(bool show) 0842 { 0843 m_palette->showSymbols(show); 0844 } 0845 0846 void MainWindow::paletteClearUnused() 0847 { 0848 QMap<int, FlossUsage> flossUsage = m_document->pattern()->stitches().flossUsage(); 0849 QMapIterator<int, DocumentFloss *> flosses(m_document->pattern()->palette().flosses()); 0850 ClearUnusedFlossesCommand *clearUnusedFlossesCommand = new ClearUnusedFlossesCommand(m_document); 0851 0852 while (flosses.hasNext()) { 0853 flosses.next(); 0854 0855 if (flossUsage[flosses.key()].totalStitches() == 0) { 0856 new RemoveDocumentFlossCommand(m_document, flosses.key(), flosses.value(), clearUnusedFlossesCommand); 0857 } 0858 } 0859 0860 if (clearUnusedFlossesCommand->childCount()) { 0861 m_document->undoStack().push(clearUnusedFlossesCommand); 0862 } else { 0863 delete clearUnusedFlossesCommand; 0864 } 0865 } 0866 0867 void MainWindow::paletteCalibrateScheme() 0868 { 0869 } 0870 0871 void MainWindow::paletteSwapColors(int originalIndex, int replacementIndex) 0872 { 0873 if (originalIndex != replacementIndex) { 0874 m_document->undoStack().push(new PaletteSwapColorCommand(m_document, originalIndex, replacementIndex)); 0875 } 0876 } 0877 0878 void MainWindow::paletteReplaceColor(int originalIndex, int replacementIndex) 0879 { 0880 if (originalIndex != replacementIndex) { 0881 m_document->undoStack().push(new PaletteReplaceColorCommand(m_document, originalIndex, replacementIndex)); 0882 } 0883 } 0884 0885 void MainWindow::viewFitBackgroundImage() 0886 { 0887 QAction *action = qobject_cast<QAction *>(sender()); 0888 m_document->undoStack().push(new FitBackgroundImageCommand(m_document, action->data().value<QSharedPointer<BackgroundImage>>(), m_editor->selectionArea())); 0889 } 0890 0891 void MainWindow::paletteContextMenu(const QPoint &pos) 0892 { 0893 static_cast<QMenu *>(guiFactory()->container(QStringLiteral("PalettePopup"), this))->popup(qobject_cast<QWidget *>(sender())->mapToGlobal(pos)); 0894 } 0895 0896 void MainWindow::viewShowBackgroundImage() 0897 { 0898 QAction *action = qobject_cast<QAction *>(sender()); 0899 m_document->undoStack().push(new ShowBackgroundImageCommand(m_document, action->data().value<QSharedPointer<BackgroundImage>>(), action->isChecked())); 0900 } 0901 0902 void MainWindow::patternExtend() 0903 { 0904 QPointer<ExtendPatternDlg> extendPatternDlg = new ExtendPatternDlg(this); 0905 0906 if (extendPatternDlg->exec()) { 0907 int top = extendPatternDlg->top(); 0908 int left = extendPatternDlg->left(); 0909 int right = extendPatternDlg->right(); 0910 int bottom = extendPatternDlg->bottom(); 0911 0912 if (top || left || right || bottom) { 0913 m_document->undoStack().push(new ExtendPatternCommand(m_document, top, left, right, bottom)); 0914 } 0915 } 0916 0917 delete extendPatternDlg; 0918 } 0919 0920 void MainWindow::patternCentre() 0921 { 0922 m_document->undoStack().push(new CentrePatternCommand(m_document)); 0923 } 0924 0925 void MainWindow::patternCrop() 0926 { 0927 m_document->undoStack().push(new CropToPatternCommand(m_document)); 0928 } 0929 0930 void MainWindow::patternCropToSelection() 0931 { 0932 m_document->undoStack().push(new CropToSelectionCommand(m_document, m_editor->selectionArea())); 0933 } 0934 0935 void MainWindow::insertColumns() 0936 { 0937 m_document->undoStack().push(new InsertColumnsCommand(m_document, m_editor->selectionArea())); 0938 } 0939 0940 void MainWindow::insertRows() 0941 { 0942 m_document->undoStack().push(new InsertRowsCommand(m_document, m_editor->selectionArea())); 0943 } 0944 0945 void MainWindow::preferences() 0946 { 0947 if (KConfigDialog::showDialog(QStringLiteral("preferences"))) { 0948 return; 0949 } 0950 0951 KConfigDialog *dialog = new KConfigDialog(this, QStringLiteral("preferences"), Configuration::self()); 0952 dialog->setFaceType(KPageDialog::List); 0953 0954 dialog->addPage(new EditorConfigPage(nullptr, QStringLiteral("EditorConfigPage")), 0955 i18nc("The Editor config page", "Editor"), 0956 QStringLiteral("preferences-desktop")); 0957 dialog->addPage(new PatternConfigPage(nullptr, QStringLiteral("PatternConfigPage")), i18n("Pattern"), QStringLiteral("ksnapshot")); 0958 PaletteConfigPage *paletteConfigPage = new PaletteConfigPage(nullptr, QStringLiteral("PaletteConfigPage")); 0959 dialog->addPage(paletteConfigPage, i18n("Palette"), QStringLiteral("preferences-desktop-color")); 0960 dialog->addPage(new ImportConfigPage(nullptr, QStringLiteral("ImportConfigPage")), i18n("Import"), QStringLiteral("insert-image")); 0961 dialog->addPage(new LibraryConfigPage(nullptr, QStringLiteral("LibraryConfigPage")), i18n("Library"), QStringLiteral("accessories-dictionary")); 0962 dialog->addPage(new PrinterConfigPage(nullptr, QStringLiteral("PrinterConfigPage")), 0963 i18n("Printer Configuration"), 0964 QStringLiteral("preferences-desktop-printer")); 0965 0966 connect(dialog, &KConfigDialog::settingsChanged, this, &MainWindow::settingsChanged); 0967 0968 dialog->show(); 0969 } 0970 0971 void MainWindow::settingsChanged() 0972 { 0973 QList<QUndoCommand *> documentChanges; 0974 ConfigurationCommand *configurationCommand = new ConfigurationCommand(this); 0975 0976 if (m_document->property(QStringLiteral("cellHorizontalGrouping")) != Configuration::editor_CellHorizontalGrouping()) { 0977 documentChanges.append( 0978 new SetPropertyCommand(m_document, QStringLiteral("cellHorizontalGrouping"), Configuration::editor_CellHorizontalGrouping(), configurationCommand)); 0979 } 0980 0981 if (m_document->property(QStringLiteral("cellVerticalGrouping")) != Configuration::editor_CellVerticalGrouping()) { 0982 documentChanges.append( 0983 new SetPropertyCommand(m_document, QStringLiteral("cellVerticalGrouping"), Configuration::editor_CellVerticalGrouping(), configurationCommand)); 0984 } 0985 0986 if (m_document->property(QStringLiteral("thickLineColor")) != Configuration::editor_ThickLineColor()) { 0987 documentChanges.append( 0988 new SetPropertyCommand(m_document, QStringLiteral("thickLineColor"), Configuration::editor_ThickLineColor(), configurationCommand)); 0989 } 0990 0991 if (m_document->property(QStringLiteral("thinLineColor")) != Configuration::editor_ThinLineColor()) { 0992 documentChanges.append( 0993 new SetPropertyCommand(m_document, QStringLiteral("thinLineColor"), Configuration::editor_ThinLineColor(), configurationCommand)); 0994 } 0995 0996 if (documentChanges.count()) { 0997 m_document->undoStack().push(configurationCommand); 0998 } else { 0999 delete configurationCommand; 1000 } 1001 1002 loadSettings(); 1003 } 1004 1005 void MainWindow::loadSettings() 1006 { 1007 m_horizontalScale->setMinimumSize(0, Configuration::editor_HorizontalScaleHeight()); 1008 m_verticalScale->setMinimumSize(Configuration::editor_VerticalScaleWidth(), 0); 1009 m_horizontalScale->setCellGrouping(Configuration::editor_CellHorizontalGrouping()); 1010 m_verticalScale->setCellGrouping(Configuration::editor_CellVerticalGrouping()); 1011 1012 m_editor->loadSettings(); 1013 m_preview->loadSettings(); 1014 m_palette->loadSettings(); 1015 1016 KActionCollection *actions = actionCollection(); 1017 1018 actions->action(QStringLiteral("makesCopies"))->setChecked(Configuration::tool_MakesCopies()); 1019 1020 actions->action(QStringLiteral("colorHighlight"))->setChecked(Configuration::renderer_ColorHilight()); 1021 1022 actions->action(QStringLiteral("renderStitches"))->setChecked(Configuration::renderer_RenderStitches()); 1023 actions->action(QStringLiteral("renderBackstitches"))->setChecked(Configuration::renderer_RenderBackstitches()); 1024 actions->action(QStringLiteral("renderFrenchKnots"))->setChecked(Configuration::renderer_RenderFrenchKnots()); 1025 actions->action(QStringLiteral("renderGrid"))->setChecked(Configuration::renderer_RenderGrid()); 1026 actions->action(QStringLiteral("renderBackgroundImages"))->setChecked(Configuration::renderer_RenderBackgroundImages()); 1027 1028 switch (Configuration::editor_FormatScalesAs()) { 1029 case Configuration::EnumEditor_FormatScalesAs::Stitches: 1030 actions->action(QStringLiteral("formatScalesAsStitches"))->trigger(); 1031 break; 1032 1033 case Configuration::EnumEditor_FormatScalesAs::Inches: 1034 actions->action(QStringLiteral("formatScalesAsInches"))->trigger(); 1035 break; 1036 1037 case Configuration::EnumEditor_FormatScalesAs::Centimeters: 1038 actions->action(QStringLiteral("formatScalesAsCentimeters"))->trigger(); 1039 break; 1040 1041 default: 1042 break; 1043 } 1044 1045 switch (Configuration::renderer_RenderStitchesAs()) { 1046 case Configuration::EnumRenderer_RenderStitchesAs::Stitches: 1047 actions->action(QStringLiteral("renderStitchesAsRegularStitches"))->trigger(); 1048 break; 1049 1050 case Configuration::EnumRenderer_RenderStitchesAs::BlackWhiteSymbols: 1051 actions->action(QStringLiteral("renderStitchesAsBlackWhiteSymbols"))->trigger(); 1052 break; 1053 1054 case Configuration::EnumRenderer_RenderStitchesAs::ColorSymbols: 1055 actions->action(QStringLiteral("renderStitchesAsColorSymbols"))->trigger(); 1056 break; 1057 1058 case Configuration::EnumRenderer_RenderStitchesAs::ColorBlocks: 1059 actions->action(QStringLiteral("renderStitchesAsColorBlocks"))->trigger(); 1060 break; 1061 1062 case Configuration::EnumRenderer_RenderStitchesAs::ColorBlocksSymbols: 1063 actions->action(QStringLiteral("renderStitchesAsColorBlocksSymbols"))->trigger(); 1064 break; 1065 1066 default: 1067 break; 1068 } 1069 1070 switch (Configuration::renderer_RenderBackstitchesAs()) { 1071 case Configuration::EnumRenderer_RenderBackstitchesAs::ColorLines: 1072 actions->action(QStringLiteral("renderBackstitchesAsColorLines"))->trigger(); 1073 break; 1074 1075 case Configuration::EnumRenderer_RenderBackstitchesAs::BlackWhiteSymbols: 1076 actions->action(QStringLiteral("renderBackstitchesAsBlackWhiteSymbols"))->trigger(); 1077 break; 1078 1079 default: 1080 break; 1081 } 1082 1083 switch (Configuration::renderer_RenderKnotsAs()) { 1084 case Configuration::EnumRenderer_RenderKnotsAs::ColorBlocks: 1085 actions->action(QStringLiteral("renderKnotsAsColorBlocks"))->trigger(); 1086 break; 1087 1088 case Configuration::EnumRenderer_RenderKnotsAs::ColorBlocksSymbols: 1089 actions->action(QStringLiteral("renderKnotsAsColorBlocksSymbols"))->trigger(); 1090 break; 1091 1092 case Configuration::EnumRenderer_RenderKnotsAs::ColorSymbols: 1093 actions->action(QStringLiteral("renderKnotsAsColorSymbols"))->trigger(); 1094 break; 1095 1096 case Configuration::EnumRenderer_RenderKnotsAs::BlackWhiteSymbols: 1097 actions->action(QStringLiteral("renderKnotsAsBlackWhiteSymbols"))->trigger(); 1098 break; 1099 1100 default: 1101 break; 1102 } 1103 1104 actions->action(QStringLiteral("paletteShowSymbols"))->setChecked(Configuration::palette_ShowSymbols()); 1105 } 1106 1107 void MainWindow::documentModified(bool clean) 1108 { 1109 setCaption(m_document->url().fileName(), !clean); 1110 } 1111 1112 void MainWindow::setupActions() 1113 { 1114 QAction *action; 1115 QActionGroup *actionGroup; 1116 1117 KActionCollection *actions = actionCollection(); 1118 1119 // File menu 1120 KStandardAction::openNew(this, &MainWindow::fileNew, actions); 1121 KStandardAction::open(this, static_cast<void (MainWindow::*)()>(&MainWindow::fileOpen), actions); 1122 KStandardAction::openRecent(this, static_cast<void (MainWindow::*)(const QUrl &)>(&MainWindow::fileOpen), actions) 1123 ->loadEntries(KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("RecentFiles"))); 1124 KStandardAction::save(this, &MainWindow::fileSave, actions); 1125 KStandardAction::saveAs(this, &MainWindow::fileSaveAs, actions); 1126 KStandardAction::revert(this, &MainWindow::fileRevert, actions); 1127 1128 action = new QAction(this); 1129 action->setText(i18n("Print Setup...")); 1130 connect(action, &QAction::triggered, this, &MainWindow::filePrintSetup); 1131 actions->addAction(QStringLiteral("filePrintSetup"), action); 1132 1133 KStandardAction::print(this, &MainWindow::filePrint, actions); 1134 1135 action = new QAction(this); 1136 action->setText(i18n("Import Image")); 1137 connect(action, &QAction::triggered, this, &MainWindow::fileImportImage); 1138 actions->addAction(QStringLiteral("fileImportImage"), action); 1139 1140 action = new QAction(this); 1141 action->setText(i18n("File Properties")); 1142 connect(action, &QAction::triggered, this, &MainWindow::fileProperties); 1143 actions->addAction(QStringLiteral("fileProperties"), action); 1144 1145 action = new QAction(this); 1146 action->setText(i18n("Add Background Image...")); 1147 connect(action, &QAction::triggered, this, &MainWindow::fileAddBackgroundImage); 1148 actions->addAction(QStringLiteral("fileAddBackgroundImage"), action); 1149 1150 KStandardAction::close(this, &MainWindow::fileClose, actions); 1151 KStandardAction::quit(this, &MainWindow::fileQuit, actions); 1152 1153 // Edit menu 1154 KStandardAction::undo(this, &MainWindow::editUndo, actions); 1155 KStandardAction::redo(this, &MainWindow::editRedo, actions); 1156 KStandardAction::cut(m_editor, &Editor::editCut, actions); 1157 actions->action(QStringLiteral("edit_cut"))->setEnabled(false); 1158 KStandardAction::copy(m_editor, &Editor::editCopy, actions); 1159 actions->action(QStringLiteral("edit_copy"))->setEnabled(false); 1160 KStandardAction::paste(m_editor, &Editor::editPaste, actions); 1161 1162 action = new QAction(this); 1163 action->setText(i18n("Mirror/Rotate makes copies")); 1164 action->setCheckable(true); 1165 connect(action, &QAction::triggered, m_editor, &Editor::setMakesCopies); 1166 actions->addAction(QStringLiteral("makesCopies"), action); 1167 1168 action = new QAction(this); 1169 action->setText(i18n("Horizontally")); 1170 action->setData(Qt::Horizontal); 1171 connect(action, &QAction::triggered, m_editor, &Editor::mirrorSelection); 1172 action->setEnabled(false); 1173 actions->addAction(QStringLiteral("mirrorHorizontal"), action); 1174 1175 action = new QAction(this); 1176 action->setText(i18n("Vertically")); 1177 action->setData(Qt::Vertical); 1178 connect(action, &QAction::triggered, m_editor, &Editor::mirrorSelection); 1179 action->setEnabled(false); 1180 actions->addAction(QStringLiteral("mirrorVertical"), action); 1181 1182 action = new QAction(this); 1183 action->setText(i18n("90 Degrees")); 1184 action->setData(StitchData::Rotate90); 1185 connect(action, &QAction::triggered, m_editor, &Editor::rotateSelection); 1186 action->setEnabled(false); 1187 actions->addAction(QStringLiteral("rotate90"), action); 1188 1189 action = new QAction(this); 1190 action->setText(i18n("180 Degrees")); 1191 action->setData(StitchData::Rotate180); 1192 connect(action, &QAction::triggered, m_editor, &Editor::rotateSelection); 1193 action->setEnabled(false); 1194 actions->addAction(QStringLiteral("rotate180"), action); 1195 1196 action = new QAction(this); 1197 action->setText(i18n("270 Degrees")); 1198 action->setData(StitchData::Rotate270); 1199 connect(action, &QAction::triggered, m_editor, &Editor::rotateSelection); 1200 action->setEnabled(false); 1201 actions->addAction(QStringLiteral("rotate270"), action); 1202 1203 // Selection mask sub menu 1204 action = new QAction(this); 1205 action->setText(i18n("Stitch Mask")); 1206 action->setCheckable(true); 1207 connect(action, &QAction::triggered, m_editor, &Editor::setMaskStitch); 1208 actions->addAction(QStringLiteral("maskStitch"), action); 1209 1210 action = new QAction(this); 1211 action->setText(i18n("Color Mask")); 1212 action->setCheckable(true); 1213 connect(action, &QAction::triggered, m_editor, &Editor::setMaskColor); 1214 actions->addAction(QStringLiteral("maskColor"), action); 1215 1216 action = new QAction(this); 1217 action->setText(i18n("Exclude Backstitches")); 1218 action->setCheckable(true); 1219 connect(action, &QAction::triggered, m_editor, &Editor::setMaskBackstitch); 1220 actions->addAction(QStringLiteral("maskBackstitch"), action); 1221 1222 action = new QAction(this); 1223 action->setText(i18n("Exclude Knots")); 1224 action->setCheckable(true); 1225 connect(action, &QAction::triggered, m_editor, &Editor::setMaskKnot); 1226 actions->addAction(QStringLiteral("maskKnot"), action); 1227 1228 // View menu 1229 KStandardAction::zoomIn(m_editor, &Editor::zoomIn, actions); 1230 KStandardAction::zoomOut(m_editor, &Editor::zoomOut, actions); 1231 KStandardAction::actualSize(m_editor, &Editor::actualSize, actions); 1232 action = KStandardAction::fitToPage(m_editor, &Editor::fitToPage, actions); 1233 action->setIcon(QIcon::fromTheme(QStringLiteral("zoom-fit-best"))); 1234 action = KStandardAction::fitToWidth(m_editor, &Editor::fitToWidth, actions); 1235 action->setIcon(QIcon::fromTheme(QStringLiteral("zoom-fit-width"))); 1236 action = KStandardAction::fitToHeight(m_editor, &Editor::fitToHeight, actions); 1237 action->setIcon(QIcon::fromTheme(QStringLiteral("zoom-fit-height"))); 1238 1239 // Entries for Show/Hide Preview and Palette dock windows are added dynamically 1240 // Entries for Show/Hide and Remove background images are added dynamically 1241 1242 // Stitches Menu 1243 actionGroup = new QActionGroup(this); 1244 actionGroup->setExclusive(true); 1245 1246 action = new QAction(this); 1247 action->setText(i18n("Quarter Stitch")); 1248 action->setIcon(QIcon::fromTheme(QStringLiteral("kxs-quarter-stitch"))); 1249 action->setCheckable(true); 1250 connect(action, &QAction::triggered, m_editor, [=]() { 1251 m_editor->selectStitch(Editor::StitchQuarter); 1252 }); 1253 actions->addAction(QStringLiteral("stitchQuarter"), action); 1254 actionGroup->addAction(action); 1255 1256 action = new QAction(this); 1257 action->setText(i18n("Half Stitch")); 1258 action->setIcon(QIcon::fromTheme(QStringLiteral("kxs-half-stitch"))); 1259 action->setCheckable(true); 1260 connect(action, &QAction::triggered, m_editor, [=]() { 1261 m_editor->selectStitch(Editor::StitchHalf); 1262 }); 1263 actions->addAction(QStringLiteral("stitchHalf"), action); 1264 actionGroup->addAction(action); 1265 1266 action = new QAction(this); 1267 action->setText(i18n("3 Quarter Stitch")); 1268 action->setIcon(QIcon::fromTheme(QStringLiteral("kxs-3quarter-stitch"))); 1269 action->setCheckable(true); 1270 connect(action, &QAction::triggered, m_editor, [=]() { 1271 m_editor->selectStitch(Editor::Stitch3Quarter); 1272 }); 1273 actions->addAction(QStringLiteral("stitch3Quarter"), action); 1274 actionGroup->addAction(action); 1275 1276 action = new QAction(this); 1277 action->setText(i18n("Full Stitch")); 1278 action->setIcon(QIcon::fromTheme(QStringLiteral("kxs-full-stitch"))); 1279 action->setCheckable(true); 1280 connect(action, &QAction::triggered, m_editor, [=]() { 1281 m_editor->selectStitch(Editor::StitchFull); 1282 }); 1283 actions->addAction(QStringLiteral("stitchFull"), action); 1284 actionGroup->addAction(action); 1285 1286 action = new QAction(this); 1287 action->setText(i18n("Small Half Stitch")); 1288 action->setIcon(QIcon::fromTheme(QStringLiteral("kxs-small-half-stitch"))); 1289 action->setCheckable(true); 1290 connect(action, &QAction::triggered, m_editor, [=]() { 1291 m_editor->selectStitch(Editor::StitchSmallHalf); 1292 }); 1293 actions->addAction(QStringLiteral("stitchSmallHalf"), action); 1294 actionGroup->addAction(action); 1295 1296 action = new QAction(this); 1297 action->setText(i18n("Small Full Stitch")); 1298 action->setIcon(QIcon::fromTheme(QStringLiteral("kxs-small-full-stitch"))); 1299 action->setCheckable(true); 1300 connect(action, &QAction::triggered, m_editor, [=]() { 1301 m_editor->selectStitch(Editor::StitchSmallFull); 1302 }); 1303 actions->addAction(QStringLiteral("stitchSmallFull"), action); 1304 actionGroup->addAction(action); 1305 1306 action = new QAction(this); 1307 action->setText(i18n("French Knot")); 1308 action->setIcon(QIcon::fromTheme(QStringLiteral("kxs-frenchknot"))); 1309 action->setCheckable(true); 1310 connect(action, &QAction::triggered, m_editor, [=]() { 1311 m_editor->selectStitch(Editor::StitchFrenchKnot); 1312 }); 1313 actions->addAction(QStringLiteral("stitchFrenchKnot"), action); 1314 actionGroup->addAction(action); 1315 1316 // Tools Menu 1317 actionGroup = new QActionGroup(this); 1318 actionGroup->setExclusive(true); 1319 1320 action = new QAction(this); 1321 action->setText(i18n("Paint")); 1322 action->setIcon(QIcon::fromTheme(QStringLiteral("draw-brush"))); 1323 action->setCheckable(true); 1324 connect(action, &QAction::triggered, m_editor, [=]() { 1325 m_editor->selectTool(Editor::ToolPaint); 1326 }); 1327 actions->addAction(QStringLiteral("toolPaint"), action); 1328 actionGroup->addAction(action); 1329 1330 action = new QAction(this); 1331 action->setText(i18n("Draw")); 1332 action->setIcon(QIcon::fromTheme(QStringLiteral("draw-freehand"))); 1333 action->setCheckable(true); 1334 connect(action, &QAction::triggered, m_editor, [=]() { 1335 m_editor->selectTool(Editor::ToolDraw); 1336 }); 1337 actions->addAction(QStringLiteral("toolDraw"), action); 1338 actionGroup->addAction(action); 1339 1340 action = new QAction(this); 1341 action->setText(i18n("Erase")); 1342 action->setIcon(QIcon::fromTheme(QStringLiteral("draw-eraser"))); 1343 action->setCheckable(true); 1344 connect(action, &QAction::triggered, m_editor, [=]() { 1345 m_editor->selectTool(Editor::ToolErase); 1346 }); 1347 actions->addAction(QStringLiteral("toolErase"), action); 1348 actionGroup->addAction(action); 1349 1350 action = new QAction(this); 1351 action->setText(i18n("Draw Rectangle")); 1352 action->setIcon(QIcon::fromTheme(QStringLiteral("draw-rectangle"))); 1353 action->setCheckable(true); 1354 connect(action, &QAction::triggered, m_editor, [=]() { 1355 m_editor->selectTool(Editor::ToolRectangle); 1356 }); 1357 actions->addAction(QStringLiteral("toolRectangle"), action); 1358 actionGroup->addAction(action); 1359 1360 action = new QAction(this); 1361 action->setText(i18n("Fill Rectangle")); 1362 action->setIcon(QIcon::fromTheme(QStringLiteral("kxs-draw-rectangle-filled"))); 1363 action->setCheckable(true); 1364 connect(action, &QAction::triggered, m_editor, [=]() { 1365 m_editor->selectTool(Editor::ToolFillRectangle); 1366 }); 1367 actions->addAction(QStringLiteral("toolFillRectangle"), action); 1368 actionGroup->addAction(action); 1369 1370 action = new QAction(this); 1371 action->setText(i18n("Draw Ellipse")); 1372 action->setIcon(QIcon::fromTheme(QStringLiteral("draw-ellipse"))); 1373 action->setCheckable(true); 1374 connect(action, &QAction::triggered, m_editor, [=]() { 1375 m_editor->selectTool(Editor::ToolEllipse); 1376 }); 1377 actions->addAction(QStringLiteral("toolEllipse"), action); 1378 actionGroup->addAction(action); 1379 1380 action = new QAction(this); 1381 action->setText(i18n("Fill Ellipse")); 1382 action->setIcon(QIcon::fromTheme(QStringLiteral("kxs-draw-ellipse-filled"))); 1383 action->setCheckable(true); 1384 connect(action, &QAction::triggered, m_editor, [=]() { 1385 m_editor->selectTool(Editor::ToolFillEllipse); 1386 }); 1387 actions->addAction(QStringLiteral("toolFillEllipse"), action); 1388 actionGroup->addAction(action); 1389 1390 action = new QAction(this); 1391 action->setText(i18n("Fill Polygon")); 1392 action->setIcon(QIcon::fromTheme(QStringLiteral("tool_polygon"))); 1393 action->setCheckable(true); 1394 connect(action, &QAction::triggered, m_editor, [=]() { 1395 m_editor->selectTool(Editor::ToolFillPolygon); 1396 }); 1397 actions->addAction(QStringLiteral("toolFillPolygon"), action); 1398 actionGroup->addAction(action); 1399 1400 action = new QAction(this); 1401 action->setText(i18n("Text")); 1402 action->setIcon(QIcon::fromTheme(QStringLiteral("draw-text"))); 1403 action->setCheckable(true); 1404 connect(action, &QAction::triggered, m_editor, [=]() { 1405 m_editor->selectTool(Editor::ToolText); 1406 }); 1407 actions->addAction(QStringLiteral("toolText"), action); 1408 actionGroup->addAction(action); 1409 1410 action = new QAction(this); 1411 action->setText(i18n("Alphabet")); 1412 action->setIcon(QIcon::fromTheme(QStringLiteral("text-field"))); 1413 action->setCheckable(true); 1414 connect(action, &QAction::triggered, m_editor, [=]() { 1415 m_editor->selectTool(Editor::ToolAlphabet); 1416 }); 1417 actions->addAction(QStringLiteral("toolAlphabet"), action); 1418 actionGroup->addAction(action); 1419 1420 action = new QAction(this); 1421 action->setText(i18nc("Select an area of the pattern", "Select")); 1422 action->setIcon(QIcon::fromTheme(QStringLiteral("select-rectangular"))); 1423 action->setCheckable(true); 1424 connect(action, &QAction::triggered, m_editor, [=]() { 1425 m_editor->selectTool(Editor::ToolSelect); 1426 }); 1427 actions->addAction(QStringLiteral("toolSelectRectangle"), action); 1428 actionGroup->addAction(action); 1429 1430 action = new QAction(this); 1431 action->setText(i18n("Backstitch")); 1432 action->setIcon(QIcon::fromTheme(QStringLiteral("kxs-backstitch"))); 1433 action->setCheckable(true); 1434 connect(action, &QAction::triggered, m_editor, [=]() { 1435 m_editor->selectTool(Editor::ToolBackstitch); 1436 }); 1437 actions->addAction(QStringLiteral("toolBackstitch"), action); 1438 actionGroup->addAction(action); 1439 1440 action = new QAction(this); 1441 action->setText(i18n("Color Picker")); 1442 action->setIcon(QIcon::fromTheme(QStringLiteral("color-picker"))); 1443 action->setCheckable(true); 1444 connect(action, &QAction::triggered, m_editor, [=]() { 1445 m_editor->selectTool(Editor::ToolColorPicker); 1446 }); 1447 actions->addAction(QStringLiteral("toolColorPicker"), action); 1448 actionGroup->addAction(action); 1449 1450 // Palette Menu 1451 action = new QAction(this); 1452 action->setText(i18n("Palette Manager...")); 1453 action->setIcon(QIcon::fromTheme(QStringLiteral("kxs-color-add"))); 1454 connect(action, &QAction::triggered, this, &MainWindow::paletteManager); 1455 actions->addAction(QStringLiteral("paletteManager"), action); 1456 1457 action = new QAction(this); 1458 action->setText(i18n("Show Symbols")); 1459 action->setCheckable(true); 1460 connect(action, &QAction::toggled, this, &MainWindow::paletteShowSymbols); 1461 actions->addAction(QStringLiteral("paletteShowSymbols"), action); 1462 1463 action = new QAction(this); 1464 action->setText(i18n("Clear Unused")); 1465 connect(action, &QAction::triggered, this, &MainWindow::paletteClearUnused); 1466 actions->addAction(QStringLiteral("paletteClearUnused"), action); 1467 1468 action = new QAction(this); 1469 action->setText(i18n("Calibrate Scheme...")); 1470 connect(action, &QAction::triggered, this, &MainWindow::paletteCalibrateScheme); 1471 actions->addAction(QStringLiteral("paletteCalibrateScheme"), action); 1472 1473 action = new QAction(this); 1474 action->setText(i18n("Swap Colors")); 1475 connect(action, &QAction::triggered, m_palette, static_cast<void (Palette::*)()>(&Palette::swapColors)); 1476 actions->addAction(QStringLiteral("paletteSwapColors"), action); 1477 1478 action = new QAction(this); 1479 action->setText(i18n("Replace Colors")); 1480 connect(action, &QAction::triggered, m_palette, static_cast<void (Palette::*)()>(&Palette::replaceColor)); 1481 actions->addAction(QStringLiteral("paletteReplaceColor"), action); 1482 1483 // Pattern Menu 1484 action = new QAction(this); 1485 action->setText(i18n("Extend Pattern...")); 1486 action->setIcon(QIcon::fromTheme(QStringLiteral("kxs-extend-pattern"))); 1487 connect(action, &QAction::triggered, this, &MainWindow::patternExtend); 1488 actions->addAction(QStringLiteral("patternExtend"), action); 1489 1490 action = new QAction(this); 1491 action->setText(i18n("Center Pattern")); 1492 action->setIcon(QIcon::fromTheme(QStringLiteral("kxs-center-pattern"))); 1493 connect(action, &QAction::triggered, this, &MainWindow::patternCentre); 1494 actions->addAction(QStringLiteral("patternCentre"), action); 1495 1496 action = new QAction(this); 1497 action->setText(i18n("Crop Canvas to Pattern")); 1498 connect(action, &QAction::triggered, this, &MainWindow::patternCrop); 1499 actions->addAction(QStringLiteral("patternCrop"), action); 1500 1501 action = new QAction(this); 1502 action->setText(i18n("Crop Canvas to Selection")); 1503 action->setIcon(QIcon::fromTheme(QStringLiteral("transform-crop"))); 1504 connect(action, &QAction::triggered, this, &MainWindow::patternCropToSelection); 1505 action->setEnabled(false); 1506 actions->addAction(QStringLiteral("patternCropToSelection"), action); 1507 1508 action = new QAction(this); 1509 action->setText(i18n("Insert Rows")); 1510 connect(action, &QAction::triggered, this, &MainWindow::insertRows); 1511 action->setEnabled(false); 1512 actions->addAction(QStringLiteral("insertRows"), action); 1513 1514 action = new QAction(this); 1515 action->setText(i18n("Insert Columns")); 1516 connect(action, &QAction::triggered, this, &MainWindow::insertColumns); 1517 action->setEnabled(false); 1518 actions->addAction(QStringLiteral("insertColumns"), action); 1519 1520 // Library Menu 1521 action = new QAction(this); 1522 action->setText(i18n("Library Manager...")); 1523 connect(action, &QAction::triggered, m_editor, &Editor::libraryManager); 1524 actions->addAction(QStringLiteral("libraryManager"), action); 1525 1526 // Settings Menu 1527 KStandardAction::preferences(this, &MainWindow::preferences, actions); 1528 // formatScalesAs 1529 actionGroup = new QActionGroup(this); 1530 actionGroup->setExclusive(true); 1531 1532 action = new QAction(this); 1533 action->setText(i18n("Stitches")); 1534 action->setCheckable(true); 1535 connect(action, &QAction::triggered, m_editor, &Editor::formatScalesAsStitches); 1536 actions->addAction(QStringLiteral("formatScalesAsStitches"), action); 1537 actionGroup->addAction(action); 1538 1539 action = new QAction(this); 1540 action->setText(i18n("Centimeters")); 1541 action->setCheckable(true); 1542 connect(action, &QAction::triggered, m_editor, &Editor::formatScalesAsCentimeters); 1543 actions->addAction(QStringLiteral("formatScalesAsCentimeters"), action); 1544 actionGroup->addAction(action); 1545 1546 action = new QAction(this); 1547 action->setText(i18n("Inches")); 1548 action->setCheckable(true); 1549 connect(action, &QAction::triggered, m_editor, &Editor::formatScalesAsInches); 1550 actions->addAction(QStringLiteral("formatScalesAsInches"), action); 1551 actionGroup->addAction(action); 1552 1553 // ShowStitchesAs 1554 actionGroup = new QActionGroup(this); 1555 actionGroup->setExclusive(true); 1556 1557 action = new QAction(this); 1558 action->setText(i18n("Regular Stitches")); 1559 action->setCheckable(true); 1560 action->setChecked(true); 1561 connect(action, &QAction::triggered, m_editor, [=]() { 1562 m_editor->renderStitchesAs(Configuration::EnumRenderer_RenderStitchesAs::Stitches); 1563 }); 1564 actions->addAction(QStringLiteral("renderStitchesAsRegularStitches"), action); 1565 actionGroup->addAction(action); 1566 1567 action = new QAction(this); 1568 action->setText(i18n("Black & White Symbols")); 1569 action->setCheckable(true); 1570 connect(action, &QAction::triggered, m_editor, [=]() { 1571 m_editor->renderStitchesAs(Configuration::EnumRenderer_RenderStitchesAs::BlackWhiteSymbols); 1572 }); 1573 actions->addAction(QStringLiteral("renderStitchesAsBlackWhiteSymbols"), action); 1574 actionGroup->addAction(action); 1575 1576 action = new QAction(this); 1577 action->setText(i18n("Color Symbols")); 1578 action->setCheckable(true); 1579 connect(action, &QAction::triggered, m_editor, [=]() { 1580 m_editor->renderStitchesAs(Configuration::EnumRenderer_RenderStitchesAs::ColorSymbols); 1581 }); 1582 actions->addAction(QStringLiteral("renderStitchesAsColorSymbols"), action); 1583 actionGroup->addAction(action); 1584 1585 action = new QAction(this); 1586 action->setText(i18n("Color Blocks")); 1587 action->setCheckable(true); 1588 connect(action, &QAction::triggered, m_editor, [=]() { 1589 m_editor->renderStitchesAs(Configuration::EnumRenderer_RenderStitchesAs::ColorBlocks); 1590 }); 1591 actions->addAction(QStringLiteral("renderStitchesAsColorBlocks"), action); 1592 actionGroup->addAction(action); 1593 1594 action = new QAction(this); 1595 action->setText(i18n("Color Blocks & Symbols")); 1596 action->setCheckable(true); 1597 connect(action, &QAction::triggered, m_editor, [=]() { 1598 m_editor->renderStitchesAs(Configuration::EnumRenderer_RenderStitchesAs::ColorBlocksSymbols); 1599 }); 1600 actions->addAction(QStringLiteral("renderStitchesAsColorBlocksSymbols"), action); 1601 actionGroup->addAction(action); 1602 1603 // ShowBackstitchesAs 1604 actionGroup = new QActionGroup(this); 1605 actionGroup->setExclusive(true); 1606 1607 action = new QAction(this); 1608 action->setText(i18n("Color Lines")); 1609 action->setCheckable(true); 1610 action->setChecked(true); 1611 connect(action, &QAction::triggered, m_editor, [=]() { 1612 m_editor->renderBackstitchesAs(Configuration::EnumRenderer_RenderBackstitchesAs::ColorLines); 1613 }); 1614 actions->addAction(QStringLiteral("renderBackstitchesAsColorLines"), action); 1615 actionGroup->addAction(action); 1616 1617 action = new QAction(this); 1618 action->setText(i18n("Black & White Symbols")); 1619 action->setCheckable(true); 1620 connect(action, &QAction::triggered, m_editor, [=]() { 1621 m_editor->renderBackstitchesAs(Configuration::EnumRenderer_RenderBackstitchesAs::BlackWhiteSymbols); 1622 }); 1623 actions->addAction(QStringLiteral("renderBackstitchesAsBlackWhiteSymbols"), action); 1624 actionGroup->addAction(action); 1625 1626 // ShowKnotsAs 1627 actionGroup = new QActionGroup(this); 1628 actionGroup->setExclusive(true); 1629 1630 action = new QAction(this); 1631 action->setText(i18n("Color Blocks")); 1632 action->setCheckable(true); 1633 action->setChecked(true); 1634 connect(action, &QAction::triggered, m_editor, [=]() { 1635 m_editor->renderKnotsAs(Configuration::EnumRenderer_RenderKnotsAs::ColorBlocks); 1636 }); 1637 actions->addAction(QStringLiteral("renderKnotsAsColorBlocks"), action); 1638 actionGroup->addAction(action); 1639 1640 action = new QAction(this); 1641 action->setText(i18n("Color Blocks & Symbols")); 1642 action->setCheckable(true); 1643 connect(action, &QAction::triggered, m_editor, [=]() { 1644 m_editor->renderKnotsAs(Configuration::EnumRenderer_RenderKnotsAs::ColorBlocksSymbols); 1645 }); 1646 actions->addAction(QStringLiteral("renderKnotsAsColorBlocksSymbols"), action); 1647 actionGroup->addAction(action); 1648 1649 action = new QAction(this); 1650 action->setText(i18n("Color Symbols")); 1651 action->setCheckable(true); 1652 connect(action, &QAction::triggered, m_editor, [=]() { 1653 m_editor->renderKnotsAs(Configuration::EnumRenderer_RenderKnotsAs::ColorSymbols); 1654 }); 1655 actions->addAction(QStringLiteral("renderKnotsAsColorSymbols"), action); 1656 actionGroup->addAction(action); 1657 1658 action = new QAction(this); 1659 action->setText(i18n("Black & White Symbols")); 1660 action->setCheckable(true); 1661 connect(action, &QAction::triggered, m_editor, [=]() { 1662 m_editor->renderKnotsAs(Configuration::EnumRenderer_RenderKnotsAs::BlackWhiteSymbols); 1663 }); 1664 actions->addAction(QStringLiteral("renderKnotsAsBlackWhiteSymbols"), action); 1665 actionGroup->addAction(action); 1666 1667 action = new QAction(this); 1668 action->setText(i18n("Color Highlight")); 1669 action->setCheckable(true); 1670 connect(action, &QAction::toggled, m_editor, &Editor::colorHighlight); 1671 actions->addAction(QStringLiteral("colorHighlight"), action); 1672 1673 action = new QAction(this); 1674 action->setText(i18n("Show Stitches")); 1675 action->setCheckable(true); 1676 connect(action, &QAction::toggled, m_editor, static_cast<void (Editor::*)(bool)>(&Editor::renderStitches)); 1677 actions->addAction(QStringLiteral("renderStitches"), action); 1678 1679 action = new QAction(this); 1680 action->setText(i18n("Show Backstitches")); 1681 action->setCheckable(true); 1682 connect(action, &QAction::toggled, m_editor, static_cast<void (Editor::*)(bool)>(&Editor::renderBackstitches)); 1683 actions->addAction(QStringLiteral("renderBackstitches"), action); 1684 1685 action = new QAction(this); 1686 action->setText(i18n("Show French Knots")); 1687 action->setCheckable(true); 1688 connect(action, &QAction::toggled, m_editor, static_cast<void (Editor::*)(bool)>(&Editor::renderFrenchKnots)); 1689 actions->addAction(QStringLiteral("renderFrenchKnots"), action); 1690 1691 action = new QAction(this); 1692 action->setText(i18n("Show Grid")); 1693 action->setCheckable(true); 1694 connect(action, &QAction::toggled, m_editor, static_cast<void (Editor::*)(bool)>(&Editor::renderGrid)); 1695 actions->addAction(QStringLiteral("renderGrid"), action); 1696 1697 action = new QAction(this); 1698 action->setText(i18n("Show Background Images")); 1699 action->setCheckable(true); 1700 connect(action, &QAction::toggled, m_editor, static_cast<void (Editor::*)(bool)>(&Editor::renderBackgroundImages)); 1701 actions->addAction(QStringLiteral("renderBackgroundImages"), action); 1702 1703 m_horizontalScale->addAction(actions->action(QStringLiteral("formatScalesAsStitches"))); 1704 m_horizontalScale->addAction(actions->action(QStringLiteral("formatScalesAsCentimeters"))); 1705 m_horizontalScale->addAction(actions->action(QStringLiteral("formatScalesAsInches"))); 1706 1707 m_verticalScale->addAction(actions->action(QStringLiteral("formatScalesAsStitches"))); 1708 m_verticalScale->addAction(actions->action(QStringLiteral("formatScalesAsCentimeters"))); 1709 m_verticalScale->addAction(actions->action(QStringLiteral("formatScalesAsInches"))); 1710 1711 setupGUI(KXmlGuiWindow::Default, QStringLiteral("kxstitchui.rc")); 1712 } 1713 1714 void MainWindow::updateBackgroundImageActionLists() 1715 { 1716 auto backgroundImages = m_document->backgroundImages().backgroundImages(); 1717 1718 unplugActionList(QStringLiteral("removeBackgroundImageActions")); 1719 unplugActionList(QStringLiteral("fitBackgroundImageActions")); 1720 unplugActionList(QStringLiteral("showBackgroundImageActions")); 1721 1722 QList<QAction *> removeBackgroundImageActions; 1723 QList<QAction *> fitBackgroundImageActions; 1724 QList<QAction *> showBackgroundImageActions; 1725 1726 while (backgroundImages.hasNext()) { 1727 QSharedPointer<BackgroundImage> backgroundImage = backgroundImages.next(); 1728 1729 QAction *action = new QAction(backgroundImage->url().fileName(), this); 1730 action->setData(QVariant::fromValue(backgroundImage)); 1731 action->setIcon(backgroundImage->icon()); 1732 connect(action, &QAction::triggered, this, &MainWindow::fileRemoveBackgroundImage); 1733 removeBackgroundImageActions.append(action); 1734 1735 action = new QAction(backgroundImage->url().fileName(), this); 1736 action->setData(QVariant::fromValue(backgroundImage)); 1737 action->setIcon(backgroundImage->icon()); 1738 connect(action, &QAction::triggered, this, &MainWindow::viewFitBackgroundImage); 1739 fitBackgroundImageActions.append(action); 1740 1741 action = new QAction(backgroundImage->url().fileName(), this); 1742 action->setData(QVariant::fromValue(backgroundImage)); 1743 action->setIcon(backgroundImage->icon()); 1744 action->setCheckable(true); 1745 action->setChecked(backgroundImage->isVisible()); 1746 connect(action, &QAction::triggered, this, &MainWindow::viewShowBackgroundImage); 1747 showBackgroundImageActions.append(action); 1748 } 1749 1750 plugActionList(QStringLiteral("removeBackgroundImageActions"), removeBackgroundImageActions); 1751 plugActionList(QStringLiteral("fitBackgroundImageActions"), fitBackgroundImageActions); 1752 plugActionList(QStringLiteral("showBackgroundImageActions"), showBackgroundImageActions); 1753 } 1754 1755 void MainWindow::setupDockWindows() 1756 { 1757 QDockWidget *dock = new QDockWidget(i18n("Preview"), this); 1758 dock->setObjectName(QStringLiteral("PreviewDock#")); 1759 dock->setAllowedAreas(Qt::AllDockWidgetAreas); 1760 QScrollArea *scrollArea = new QScrollArea(); 1761 m_preview = new Preview(scrollArea); 1762 scrollArea->setWidget(m_preview); 1763 scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); 1764 scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); 1765 scrollArea->setMinimumSize(std::min(300, m_preview->width()), std::min(400, m_preview->height())); 1766 dock->setWidget(scrollArea); 1767 addDockWidget(Qt::LeftDockWidgetArea, dock); 1768 actionCollection()->addAction(QStringLiteral("showPreviewDockWidget"), dock->toggleViewAction()); 1769 1770 dock = new QDockWidget(i18n("Palette"), this); 1771 dock->setObjectName(QStringLiteral("PaletteDock#")); 1772 dock->setAllowedAreas(Qt::AllDockWidgetAreas); 1773 m_palette = new Palette(this); 1774 m_palette->setContextMenuPolicy(Qt::CustomContextMenu); 1775 dock->setWidget(m_palette); 1776 addDockWidget(Qt::LeftDockWidgetArea, dock); 1777 actionCollection()->addAction(QStringLiteral("showPaletteDockWidget"), dock->toggleViewAction()); 1778 1779 dock = new QDockWidget(i18n("History"), this); 1780 dock->setObjectName(QStringLiteral("HistoryDock#")); 1781 dock->setAllowedAreas(Qt::AllDockWidgetAreas); 1782 m_history = new QUndoView(this); 1783 dock->setWidget(m_history); 1784 addDockWidget(Qt::LeftDockWidgetArea, dock); 1785 actionCollection()->addAction(QStringLiteral("showHistoryDockWidget"), dock->toggleViewAction()); 1786 1787 dock = new QDockWidget(i18n("Imported Image"), this); 1788 dock->setObjectName(QStringLiteral("ImportedImage#")); 1789 dock->setAllowedAreas(Qt::AllDockWidgetAreas); 1790 m_imageLabel = new ScaledPixmapLabel(this); 1791 m_imageLabel->setScaledContents(false); 1792 dock->setWidget(m_imageLabel); 1793 addDockWidget(Qt::LeftDockWidgetArea, dock); 1794 actionCollection()->addAction(QStringLiteral("showImportedDockWidget"), dock->toggleViewAction()); 1795 } 1796 1797 #include "moc_MainWindow.cpp"