Warning, file /graphics/symboleditor/src/MainWindow.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /******************************************************************************** 0002 * Copyright (C) 2011-2015 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 0012 /** 0013 * @file 0014 * Implement the MainWindow class. This supplies the main user interface which comprises of a tabbed widget 0015 * containing a symbol editor and a library of symbols loaded from a symbol file. A standard menu bar, tool 0016 * bar and status bar are provided to access the various functions and provide any suitable feedback or status 0017 * messages. 0018 */ 0019 0020 0021 /** 0022 * @page main_window Main Window 0023 * The symbol editor main window comprises a tabbed widget containing the symbol editor and a list of the 0024 * current symbols in the loaded file. A standard menu bar, tool bar and status bar are provided to access 0025 * the various tools and functions and provide any necessary status messages or user feedback. 0026 * 0027 * @image html ui-main-editor.png "The user interface showing the editor tab" 0028 * 0029 * @section file_menu File Menu 0030 * 0031 * @subsection file_new New 0032 * Start a new symbol definition. The editor is cleared ready to define the new symbol. If there is an existing 0033 * symbol being edited that has not been saved, the user is prompted to save it or allow it to be overwritten. 0034 * Alternatively the user can cancel the creation of the new symbol leaving the current one intact. 0035 * 0036 * @subsection file_open Open 0037 * Open an existing symbol library. The current symbol and symbol library are cleared and the user is prompted to 0038 * select a file to be opened. If the current symbol of symbol file have not been saved the user is asked to 0039 * save them or allow them to be overwritten. Alternatively the user can cancel opening a file leaving the current 0040 * ones intact. 0041 * 0042 * @subsection file_open_recent Open Recent 0043 * Previously opened files are added to the recent files menu and can be opened by selecting the file specified. 0044 * The same rules relating to Open and the current symbol and library apply here. 0045 * 0046 * @subsection file_save Save 0047 * Save the current library to a file. If this is a new library the user will be prompted to enter a file name. 0048 * 0049 * @subsection file_save_as Save As 0050 * Save the current library using a different name. The user will be prompted to enter a file name. 0051 * 0052 * @subsection file_save_symbol Save Symbol 0053 * Save the current symbol being edited to the current library. This does not save the symbol library to disk, this 0054 * is done by the Save command. 0055 * 0056 * @subsection file_save_symbol_as_new Save Symbol as New 0057 * Save the symbol as if it was a new one. This would apply if the symbol was one from the library being edited. The 0058 * editor maintains a link between it and the library and would normally update it when saved. This will reset the 0059 * index and add the symbol to the library as a new one. The symbol being edited is now detached from the library 0060 * and subsequent saves will continue to add new symbols to the library. This can be used to create new symbols based 0061 * on an existing library symbol. 0062 * 0063 * @subsection file_import_library Import Library 0064 * Import an existing symbol library and append the symbols in it to the current library. 0065 * 0066 * @subsection file_close Close 0067 * Close the current library. The editor and the library are cleared leaving an empty library ready for new symbols 0068 * to be added. If the current symbol and library need to be saved the user is prompted to do so. 0069 * 0070 * @subsection file_quit Quit 0071 * Quit the application. If the current symbol and library need to be saved the user is prompted to do so. 0072 * 0073 * @section edit_menu Edit Menu 0074 * 0075 * @subsection edit_undo Undo 0076 * Actions that modify the symbol currently being edited or the current symbol library can be undone reverting to 0077 * the previous state. The editor and the library have independent undo stacks and changes to one do not affect the 0078 * other. The undo command affects the currently selected tab. The undo command in the menu shows a description of 0079 * the action that will be undone. For the undo command on the toolbar, the tooltip will show the desciption. 0080 * 0081 * @subsection edit_redo Redo 0082 * Actions that are undone can be redone. As with undo, the editor and the symbol library are independent of each 0083 * other and the redo command affects the currently selected tab. The redo command in the menu and the toolbar tooltip 0084 * shows a description of the action that will be redone. 0085 * 0086 * @subsection file_edit_toolbar File and Edit Toolbar 0087 * The file and edit menu toolbar allow quick access to these common functions. 0088 * @image html ui-main-toolbar.png 0089 * - @ref file_new 0090 * - @ref file_open 0091 * - @ref file_save 0092 * - @ref edit_undo 0093 * - @ref edit_redo 0094 * - @ref file_save_symbol 0095 * 0096 * @section rendering_menu Rendering Menu 0097 * The defined path can be rendered with various settings. Filled or unfilled, for which the fill method can be defined. 0098 * The path end cap can be defined as flat, square and round. The line join type can be defined as bevel, miter and round. 0099 * The line width can be increased or decreased. 0100 * 0101 * For full details of the rendering options, see the @ref path_rendering. 0102 * 0103 * @subsection rendering_toolbar Rendering Toolbar 0104 * The rendering toolbar allows quick access to these common functions. 0105 * @image html ui-rendering-toolbar.png 0106 * - @ref fill_mode 0107 * - @ref fill_rule 0108 * - @ref line_cap 0109 * - @ref line_join 0110 * - @ref line_width 0111 * 0112 * @section tools_menu Tools Menu 0113 * A number of tools are available to aid the design of the symbols. The symbols are composed of a series of sub paths 0114 * and each sub path is composed of a move to the start position (this defaults to 0,0 for new symbols) followed by 0115 * lines and curves. The curves are cubic splines having a start, an end and two control points defining the curve. 0116 * There are convenience tools to create rectangles and ellipses, but these will be broken down into lines and curves. 0117 * 0118 * All points created for the elements are moveable by dragging them to their new position. All points can be snapped 0119 * to the grid intersections if the snap option is turned on, otherwise they can be positioned anywhere. 0120 * 0121 * The symbol can be rotated clockwise and counter clockwise and also flipped vertically and horizontally. This allows 0122 * multiple symbols to be easily created based on the same design. Remember to use the save symbol as new option for this. 0123 * 0124 * For full details of the tools see the @ref editor_tools. 0125 * 0126 * @subsection tools_toolbar Tools Toolbar 0127 * The tools toolbar allows quick access to these common functions. 0128 * @image html ui-tools-toolbar.png 0129 * - @ref move_to 0130 * - @ref line_to 0131 * - @ref cubic_to 0132 * - @ref rectangle 0133 * - @ref ellipse 0134 * - @ref character 0135 * - @ref rotate_left 0136 * - @ref rotate_right 0137 * - @ref flip_horizontal 0138 * - @ref flip_vertical 0139 * - @ref scale_preferred 0140 * - @ref snap_grid 0141 * - @ref guide_lines 0142 */ 0143 0144 0145 #include "MainWindow.h" 0146 0147 #include <QAction> 0148 #include <QFileDialog> 0149 #include <QIcon> 0150 #include <QVBoxLayout> 0151 #include <QListWidgetItem> 0152 #include <QMenu> 0153 #include <QStatusBar> 0154 #include <QTabWidget> 0155 #include <QTemporaryFile> 0156 0157 #include <kwidgetsaddons_version.h> 0158 #include <KActionCollection> 0159 #include <KConfigDialog> 0160 #include <KConfigGroup> 0161 #include <KIO/FileCopyJob> 0162 #include <KLocalizedString> 0163 #include <KMessageBox> 0164 #include <KRecentFilesAction> 0165 0166 #include "ConfigurationDialogs.h" 0167 #include "Editor.h" 0168 #include "Exceptions.h" 0169 #include "SymbolListWidget.h" 0170 #include "SymbolLibrary.h" 0171 0172 #include "ui_EditorConfigPage.h" 0173 0174 #include "SymbolEditor.h" 0175 0176 0177 /** 0178 * Construct the MainWindow. 0179 * Create an instance of a symbol file. 0180 * Create the tab widget, editor, list widget and the symbol file. The tab widget is then set as 0181 * the central widget and will contain the editor and list widgets. The Editor is added to a 0182 * layout to allow it to be centralized in the main window. 0183 * Set up the actions, add the two undo stacks to the undo group and connect any signal slots required. 0184 * Set up the GUI from the applications rc file. 0185 * The editor page is selected in the tab widget which should also initialise the undo redo buttons. 0186 * The moveTo tool action is triggered to enable the moveTo tool as the initial one. 0187 * Other actions are initialised from the current Editor symbol. 0188 */ 0189 MainWindow::MainWindow() 0190 : m_tabWidget(new QTabWidget(this)), 0191 m_editor(new Editor), 0192 m_listWidget(new SymbolListWidget(m_tabWidget)), 0193 m_symbolLibrary(new SymbolLibrary(m_listWidget)), 0194 m_item(nullptr), 0195 m_menu(nullptr) 0196 { 0197 m_listWidget->loadFromLibrary(m_symbolLibrary); 0198 m_url = QUrl(i18n("Untitled")); 0199 0200 setObjectName(QStringLiteral("MainWindow#")); 0201 0202 KActionCollection *actions = actionCollection(); 0203 0204 m_listWidget->setIconSize(48); 0205 m_listWidget->setContextMenuPolicy(Qt::CustomContextMenu); 0206 0207 m_tabWidget->addTab(m_editor, i18nc("The editor tab title", "Editor")); 0208 m_tabWidget->addTab(m_listWidget, i18nc("The library tab title", "Library")); 0209 0210 setCentralWidget(m_tabWidget); 0211 0212 setupActions(); 0213 0214 m_undoGroup.addStack(m_editor->undoStack()); 0215 m_undoGroup.addStack(m_symbolLibrary->undoStack()); 0216 connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(currentChanged(int))); 0217 connect(m_editor, SIGNAL(message(QString)), statusBar(), SLOT(showMessage(QString))); 0218 connect(m_editor, SIGNAL(minLineWidth(bool)), actions->action(QStringLiteral("decreaseLineWidth")), SLOT(setDisabled(bool))); 0219 connect(m_editor, SIGNAL(maxLineWidth(bool)), actions->action(QStringLiteral("increaseLineWidth")), SLOT(setDisabled(bool))); 0220 connect(&m_undoGroup, SIGNAL(canUndoChanged(bool)), actions->action(QStringLiteral("edit_undo")), SLOT(setEnabled(bool))); 0221 connect(&m_undoGroup, SIGNAL(canRedoChanged(bool)), actions->action(QStringLiteral("edit_redo")), SLOT(setEnabled(bool))); 0222 connect(&m_undoGroup, SIGNAL(undoTextChanged(QString)), this, SLOT(undoTextChanged(QString))); 0223 connect(&m_undoGroup, SIGNAL(redoTextChanged(QString)), this, SLOT(redoTextChanged(QString))); 0224 connect(&m_undoGroup, SIGNAL(cleanChanged(bool)), this, SLOT(cleanChanged(bool))); 0225 connect(m_editor->undoStack(), SIGNAL(cleanChanged(bool)), actions->action(QStringLiteral("saveSymbol")), SLOT(setDisabled(bool))); 0226 connect(m_editor->undoStack(), SIGNAL(cleanChanged(bool)), actions->action(QStringLiteral("saveSymbolAsNew")), SLOT(setDisabled(bool))); 0227 connect(m_symbolLibrary->undoStack(), SIGNAL(cleanChanged(bool)), actions->action(QStringLiteral("file_save")), SLOT(setDisabled(bool))); 0228 connect(m_listWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(itemSelected(QListWidgetItem*))); 0229 connect(m_listWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(listWidgetContextMenuRequested(QPoint))); 0230 0231 setupGUI(KXmlGuiWindow::Default, QStringLiteral("SymbolEditorui.rc")); 0232 0233 actions->action(QStringLiteral("moveTo"))->trigger(); // select draw tool 0234 actions->action(QStringLiteral("enableSnap"))->setChecked(true); // enable snap 0235 actions->action(QStringLiteral("enableGuides"))->setChecked(true); // enable creation of guides 0236 actions->action(QStringLiteral("file_save"))->setEnabled(false); // nothing to save yet 0237 actions->action(QStringLiteral("saveSymbol"))->setEnabled(false); // nothing to save yet 0238 actions->action(QStringLiteral("saveSymbolAsNew"))->setEnabled(false); // nothing to save yet 0239 setActionsFromSymbol(m_editor->symbol().second); // set the actions that depend on the current empty symbol, i.e. the defaults 0240 0241 currentChanged(m_tabWidget->currentIndex()); // this should be the editor 0242 } 0243 0244 0245 /** 0246 * Descructor for the MainWindow 0247 * Delete the SymbolLibrary object. The other widgets that are created in the constructor are children of the 0248 * MainWindow and will be destroyed when this is. 0249 */ 0250 MainWindow::~MainWindow() 0251 { 0252 delete m_symbolLibrary; 0253 } 0254 0255 0256 /** 0257 * Test if it is ok to close this window. 0258 * Check if the current symbol being edited has been changed and if the library has been changed. 0259 * 0260 * @return true if it is ok to close, false otherwise 0261 */ 0262 bool MainWindow::queryClose() 0263 { 0264 return (editorClean() && libraryClean()); 0265 } 0266 0267 0268 /** 0269 * Check if it ok to close the currently edited symbol. 0270 * 0271 * @return true if is ok to close the symbol, false otherwise 0272 */ 0273 bool MainWindow::editorClean() 0274 { 0275 bool clean = m_editor->undoStack()->isClean(); 0276 0277 if (!clean) { 0278 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0279 int messageBoxResult = KMessageBox::warningTwoActionsCancel(this, 0280 #else 0281 int messageBoxResult = KMessageBox::warningYesNoCancel(this, 0282 #endif 0283 i18n("Save changes to the symbol?"), QString(), 0284 KStandardGuiItem::save(), 0285 KStandardGuiItem::discard(), 0286 KStandardGuiItem::cancel()); 0287 0288 switch (messageBoxResult) { 0289 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0290 case KMessageBox::PrimaryAction: 0291 #else 0292 case KMessageBox::Yes: 0293 #endif 0294 saveSymbol(); 0295 save(); 0296 clean = true; 0297 break; 0298 0299 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0300 case KMessageBox::SecondaryAction: 0301 #else 0302 case KMessageBox::No: 0303 #endif 0304 clean = true; 0305 break; 0306 0307 case KMessageBox::Cancel: 0308 clean = false; 0309 break; 0310 } 0311 } 0312 0313 return clean; 0314 } 0315 0316 0317 /** 0318 * Check if it is ok to close the library. 0319 * 0320 * @return true if it is ok to close the library, false otherwise 0321 */ 0322 bool MainWindow::libraryClean() 0323 { 0324 bool clean = m_symbolLibrary->undoStack()->isClean(); 0325 0326 if (!clean) { 0327 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0328 int messageBoxResult = KMessageBox::warningTwoActionsCancel(this, 0329 #else 0330 int messageBoxResult = KMessageBox::warningYesNoCancel(this, 0331 #endif 0332 i18n("Save changes to the library?"), QString(), 0333 KStandardGuiItem::save(), 0334 KStandardGuiItem::discard(), 0335 KStandardGuiItem::cancel()); 0336 0337 switch (messageBoxResult) { 0338 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0339 case KMessageBox::PrimaryAction: 0340 #else 0341 case KMessageBox::Yes: 0342 #endif 0343 save(); 0344 clean = true; 0345 break; 0346 0347 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0348 case KMessageBox::SecondaryAction: 0349 #else 0350 case KMessageBox::No: 0351 #endif 0352 clean = true; 0353 break; 0354 0355 case KMessageBox::Cancel: 0356 clean = false; 0357 break; 0358 } 0359 } 0360 0361 return clean; 0362 } 0363 0364 0365 /** 0366 * Open a file. 0367 * Use the QFileDialog::getOpenFileUrl to get a QUrl to open which is then passed to filOpen(const QUrl &). 0368 */ 0369 void MainWindow::fileOpen() 0370 { 0371 QUrl url = QFileDialog::getOpenFileUrl(this, i18n("Open file"), QUrl::fromLocalFile(QDir::homePath()), i18n("Cross Stitch Symbols (*.sym)")); 0372 0373 if (!url.isEmpty()) { 0374 fileOpen(url); 0375 } 0376 } 0377 0378 0379 /** 0380 * If a valid url is supplied, try and download the file (in case it comes from a remote source) and 0381 * then try and open it read only. Once opened create a QDataStream and try and read the contents. 0382 * This is protected in a try-catch block to intercept any exceptions that may be thrown by the loading 0383 * routines. If there were any errors, the symbol library will be cleared and a suitable error message 0384 * will be displayed. 0385 * The url of the file is set in the symbol file object only if there were no errors. This will avoid 0386 * writing to a corrupt file or to a file that isn't a symbol file. The url is added to the recent file 0387 * list. 0388 */ 0389 void MainWindow::fileOpen(const QUrl &url) 0390 { 0391 if (!editorClean() || !libraryClean()) { 0392 return; 0393 } 0394 0395 m_symbolLibrary->clear(); 0396 m_editor->clear(); 0397 0398 if (url.isValid()) { 0399 QTemporaryFile tmpFile; 0400 0401 if (tmpFile.open()) { 0402 tmpFile.close(); 0403 0404 KIO::FileCopyJob *job = KIO::file_copy(url, QUrl::fromLocalFile(tmpFile.fileName()), -1, KIO::Overwrite); 0405 0406 if (job->exec()) { 0407 QFile reader(tmpFile.fileName()); 0408 0409 if (reader.open(QIODevice::ReadOnly)) { 0410 QDataStream stream(&reader); 0411 0412 try { 0413 stream >> *m_symbolLibrary; 0414 m_url = url; 0415 KRecentFilesAction *action = static_cast<KRecentFilesAction *>(actionCollection()->action(QStringLiteral("file_open_recent"))); 0416 action->addUrl(url); 0417 action->saveEntries(KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("RecentFiles"))); 0418 m_tabWidget->setCurrentIndex(1); 0419 } catch (const InvalidFile &e) { 0420 KMessageBox::error(nullptr, i18n("This doesn't appear to be a valid symbol file")); 0421 } catch (const InvalidFileVersion &e) { 0422 KMessageBox::error(nullptr, i18n("Version %1 of the library file is not supported in this version of SymbolEditor", e.version)); 0423 } catch (const InvalidSymbolVersion &e) { 0424 KMessageBox::error(nullptr, i18n("Version %1 of the symbol is not supported in this version of SymbolEditor", e.version)); 0425 } catch (const FailedReadLibrary &e) { 0426 KMessageBox::error(nullptr, i18n("Failed to read the library\n%1", e.statusMessage())); 0427 m_symbolLibrary->clear(); 0428 } 0429 } else { 0430 KMessageBox::error(nullptr, reader.errorString()); 0431 } 0432 } else { 0433 KMessageBox::error(nullptr, job->errorString()); 0434 } 0435 } else { 0436 KMessageBox::error(nullptr, tmpFile.errorString()); 0437 } 0438 } else { 0439 KMessageBox::error(nullptr, i18n("The url %1 is invalid", url.fileName())); 0440 } 0441 } 0442 0443 0444 /** 0445 * Save the library using its url, if this is Untitled than call saveAs to get a valid url. 0446 * Open the file and write to the stream. This is protected in a try-catch block to intercept 0447 * any exceptions thrown by the writing routines. If there were any exceptions thrown or the 0448 * file could not be opened a suitable error message is shown. 0449 */ 0450 void MainWindow::save() 0451 { 0452 if (m_url == QUrl(i18n("Untitled"))) { 0453 saveAs(); 0454 } else { 0455 QFile file(m_url.path()); 0456 0457 if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { 0458 QDataStream stream(&file); 0459 stream.setVersion(QDataStream::Qt_4_0); 0460 0461 try { 0462 stream << *m_symbolLibrary; 0463 } catch (const FailedWriteLibrary &e) { 0464 KMessageBox::error(nullptr, i18n("Failed to write the library\n%1", e.statusMessage())); 0465 } 0466 0467 file.close(); 0468 m_symbolLibrary->undoStack()->setClean(); 0469 } else { 0470 KMessageBox::error(nullptr, i18n("Failed to open the file %1\n%2", m_url.fileName(), file.errorString())); 0471 } 0472 } 0473 } 0474 0475 0476 /** 0477 * Save the library using a different url. 0478 * This is also called from save when the assigned url is Untitled. 0479 * The new url is added to the recent files list. 0480 */ 0481 void MainWindow::saveAs() 0482 { 0483 QUrl url = QFileDialog::getSaveFileUrl(this, i18n("Save As..."), QUrl::fromLocalFile(QDir::homePath()), i18n("Cross Stitch Symbols (*.sym)")); 0484 0485 if (url.isValid()) { 0486 m_url = url; 0487 save(); 0488 KRecentFilesAction *action = static_cast<KRecentFilesAction *>(actionCollection()->action(QStringLiteral("file_open_recent"))); 0489 action->addUrl(url); 0490 action->saveEntries(KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("RecentFiles"))); 0491 } 0492 } 0493 0494 0495 /** 0496 * Initialise a new symbol. 0497 * Check if the current symbol has been saved or can be overwritten and then call clear 0498 * on the editor which initializes the editor with an empty symbol. 0499 * The actions are reset to those relevant to the new empty symbol. 0500 * The moveTo action is triggered as this is the most likely to be used next. 0501 */ 0502 void MainWindow::newSymbol() 0503 { 0504 if (editorClean()) { 0505 m_editor->clear(); 0506 setActionsFromSymbol(m_editor->symbol().second); 0507 actionCollection()->action(QStringLiteral("moveTo"))->trigger(); // Select move tool 0508 } 0509 } 0510 0511 0512 /** 0513 * Save the current symbol. 0514 * Store the symbol currently in the editor into the symbol library object. If it is a 0515 * new symbol the index will be 0, a new index will then be created. Otherwise the index 0516 * will be the one from the library and storing it will overwrite the existing symbol. 0517 */ 0518 void MainWindow::saveSymbol() 0519 { 0520 QPair<qint16, Symbol> pair = m_editor->symbol(); 0521 m_symbolLibrary->undoStack()->push(new UpdateSymbolCommand(m_symbolLibrary, pair.first, pair.second)); 0522 m_editor->undoStack()->setClean(); 0523 } 0524 0525 0526 /** 0527 * Save the current symbol using a new index. 0528 * Store the symbol currently in the editor into the symbol library object. Ignore the 0529 * editors index, resetting it to 0 and a new index will then be created. 0530 * Reassign this symbol back to the editor with a 0 index effectively creating a new symbol in 0531 * the editor. 0532 */ 0533 void MainWindow::saveSymbolAsNew() 0534 { 0535 QPair<qint16, Symbol> pair = m_editor->symbol(); 0536 pair.first = 0; 0537 m_symbolLibrary->undoStack()->push(new UpdateSymbolCommand(m_symbolLibrary, pair.first, pair.second)); 0538 m_editor->setSymbol(pair); 0539 } 0540 0541 0542 /** 0543 * Import a library of symbols into the current library. 0544 * Get a url for the library file and try and download it in case it comes from a remote source. 0545 * Open the file and read the contents into a new SymbolLibrary object. The read is protected by 0546 * a try-catch block to intercept any exceptions thrown by the read routines. If there were no 0547 * errors an ImportLibraryCommand is created and pushed onto the symbol library undo stack. 0548 * This will copy all the symbols from the imported library into the current library. 0549 * Any errors will display a suitable error message. 0550 */ 0551 void MainWindow::importLibrary() 0552 { 0553 QUrl url = QFileDialog::getOpenFileUrl(this, i18n("Import library"), QUrl::fromLocalFile(QDir::homePath()), i18n("Cross Stitch Symbols (*.sym)")); 0554 0555 if (url.isEmpty()) { 0556 return; 0557 } 0558 0559 if (url.isValid()) { 0560 QTemporaryFile tmpFile; 0561 0562 if (tmpFile.open()) { 0563 KIO::FileCopyJob *job = KIO::file_copy(url, QUrl::fromLocalFile(tmpFile.fileName()), -1, KIO::Overwrite); 0564 0565 if (job->exec()) { 0566 SymbolLibrary *lib = new SymbolLibrary; 0567 QDataStream stream(&tmpFile); 0568 0569 try { 0570 stream >> *lib; 0571 m_symbolLibrary->undoStack()->push(new ImportLibraryCommand(m_symbolLibrary, lib)); 0572 } catch (const InvalidFile &e) { 0573 KMessageBox::error(nullptr, i18n("This doesn't appear to be a valid symbol file")); 0574 } catch (const InvalidFileVersion &e) { 0575 KMessageBox::error(nullptr, i18n("Version %1 of the library file is not supported in this version of SymbolEditor", e.version)); 0576 } 0577 } else { 0578 KMessageBox::error(nullptr, job->errorString()); 0579 } 0580 } else { 0581 KMessageBox::error(nullptr, tmpFile.errorString()); 0582 } 0583 } else { 0584 KMessageBox::error(nullptr, i18n("The url %1 is invalid", url.fileName())); 0585 } 0586 } 0587 0588 0589 /** 0590 * Close the current library. 0591 * Check if the current symbol and the symbol library need to be saved and then clear 0592 * the library and the editor. 0593 */ 0594 void MainWindow::close() 0595 { 0596 if (editorClean() && libraryClean()) { 0597 m_editor->clear(); 0598 m_symbolLibrary->clear(); 0599 m_url = QUrl(i18n("Untitled")); 0600 } 0601 } 0602 0603 0604 /** 0605 * Quit the application. 0606 * Closes this MainWindow. 0607 */ 0608 void MainWindow::quit() 0609 { 0610 KXmlGuiWindow::close(); 0611 } 0612 0613 0614 /** 0615 * Undo the last operation. 0616 * Several undo stacks will be available. One for the library object and one for the editor. 0617 * Changing the tab will update the actions depending on the contents of the relevant undo stack. 0618 */ 0619 void MainWindow::undo() 0620 { 0621 m_undoGroup.undo(); 0622 } 0623 0624 0625 /** 0626 * Redo the last operation undone. 0627 * Several undo stacks will be available. One for the library object and one for the editor. 0628 * Changing the tab will update the actions depending on the contents of the relevant undo stack. 0629 */ 0630 void MainWindow::redo() 0631 { 0632 m_undoGroup.redo(); 0633 } 0634 0635 0636 /** 0637 * Update the undo action text to reflect the last operation available to undo. 0638 * Several undo stacks will be available. One for the library object and one for the editor. 0639 * Changing the tab will update the actions depending on the contents of the relevant undo stack. 0640 * 0641 * @param text the text string to describe the operation 0642 */ 0643 void MainWindow::undoTextChanged(const QString &text) 0644 { 0645 actionCollection()->action(QStringLiteral("edit_undo"))->setText(QString(i18n("Undo %1", text))); 0646 } 0647 0648 0649 /** 0650 * Update the redo action text to reflect the last operation available to redo. 0651 * Several undo stacks will be available. One for the library object and one for the editor. 0652 * Changing the tab will update the actions depending on the contents of the relevant undo stack. 0653 * 0654 * @param text the text string to describe the operation 0655 */ 0656 void MainWindow::redoTextChanged(const QString &text) 0657 { 0658 actionCollection()->action(QStringLiteral("edit_redo"))->setText(QString(i18n("Redo %1", text))); 0659 } 0660 0661 0662 /** 0663 * Update the caption based on the state of the undo stack. 0664 * 0665 * @param clean true if the symbol has not been changed, false otherwise 0666 */ 0667 void MainWindow::cleanChanged(bool clean) 0668 { 0669 QString tab; 0670 0671 if (m_tabWidget->currentIndex() == 1) { 0672 tab = QString(i18nc("The library tab title %1 is the file name", "%1 Library", m_url.fileName())); 0673 } else { 0674 tab = QString(i18nc("The editor tab title %1 is the file name", "%1 Editor", m_url.fileName())); 0675 } 0676 0677 setCaption(tab, !clean); 0678 } 0679 0680 0681 /** 0682 * Change the tab selected. 0683 * This is connected to the QTabWidget::currentChanged() slot and indicates that the current tab 0684 * has changed. This allows the undo stack connections to be modified. 0685 * 0686 * @param index the index of the page 0687 */ 0688 void MainWindow::currentChanged(int index) 0689 { 0690 if (index == 0) { // Editor 0691 m_undoGroup.setActiveStack(m_editor->undoStack()); 0692 m_editor->updateStatusMessage(); 0693 } else if (index == 1) { // QListWidget 0694 m_undoGroup.setActiveStack(m_symbolLibrary->undoStack()); 0695 statusBar()->clearMessage(); 0696 } 0697 } 0698 0699 0700 /** 0701 * Edit an existing symbol from the symbol library. 0702 * Check if the current symbol being edited has been changed. If yes, ask if it should be 0703 * saved or discarded. 0704 * Clear the contents of the editor and assign a copy of the item symbol to it to edit. 0705 * The actions are updated to reflect the settings of the symbol being edited. 0706 * 0707 * @param item a pointer to a QListWidgetItem that was double clicked. 0708 */ 0709 void MainWindow::itemSelected(QListWidgetItem *item) 0710 { 0711 QPair<qint16, Symbol> pair; 0712 0713 if (editorClean()) { 0714 m_editor->clear(); 0715 pair.first = static_cast<qint16>(item->data(Qt::UserRole).toInt()); 0716 pair.second = m_symbolLibrary->symbol(pair.first); 0717 m_editor->setSymbol(pair); 0718 setActionsFromSymbol(pair.second); 0719 m_tabWidget->setCurrentIndex(0); 0720 } 0721 } 0722 0723 0724 /** 0725 * Display a context menu for the list widget. 0726 * Options: 0727 * Delete Symbol 0728 * 0729 * @param pos a const reference to a QPoint representing the cursor position 0730 */ 0731 void MainWindow::listWidgetContextMenuRequested(const QPoint &pos) 0732 { 0733 if ((m_item = m_listWidget->itemAt(pos))) { 0734 if (!m_menu) { 0735 m_menu = new QMenu; 0736 m_menu->addAction(i18n("Delete Symbol"), this, SLOT(deleteSymbol())); 0737 } 0738 0739 m_menu->popup(QCursor::pos()); 0740 } 0741 } 0742 0743 0744 /** 0745 * Delete the symbol pointed to by m_item. 0746 */ 0747 void MainWindow::deleteSymbol() 0748 { 0749 m_symbolLibrary->undoStack()->push(new DeleteSymbolCommand(m_symbolLibrary, static_cast<qint16>(m_item->data(Qt::UserRole).toInt()))); 0750 } 0751 0752 0753 /** 0754 * Configure the application. 0755 * Display the configuration dialog, creating it if necessary. 0756 */ 0757 void MainWindow::preferences() 0758 { 0759 if (KConfigDialog::showDialog(QStringLiteral("preferences"))) { 0760 return; 0761 } 0762 0763 KConfigDialog *dialog = new KConfigDialog(this, QStringLiteral("preferences"), Configuration::self()); 0764 dialog->setFaceType(KPageDialog::List); 0765 0766 dialog->addPage(new EditorConfigPage(nullptr, QStringLiteral("EditorConfigPage")), i18nc("The Editor configuration page", "Editor"), QStringLiteral("preferences-desktop")); 0767 // dialog->setHelp("ConfigurationDialog"); 0768 0769 connect(dialog, SIGNAL(settingsChanged(QString)), m_editor, SLOT(readSettings())); 0770 0771 dialog->show(); 0772 } 0773 0774 0775 /** 0776 * Set up the applications actions. 0777 * Create standard actions. 0778 * Create other actions, setting the icon and data as required. 0779 * Several actions are added to groups which are set as exclusive. 0780 * All actions are added to the applications QActionCollection. 0781 */ 0782 void MainWindow::setupActions() 0783 { 0784 QAction *action; 0785 QActionGroup *actionGroup; 0786 0787 KActionCollection *actions = actionCollection(); 0788 0789 // File menu 0790 KStandardAction::open(this, SLOT(fileOpen()), actions); 0791 KStandardAction::openNew(this, SLOT(newSymbol()), actions); 0792 KStandardAction::openRecent(this, SLOT(fileOpen(QUrl)), actions)->loadEntries(KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("RecentFiles"))); 0793 KStandardAction::save(this, SLOT(save()), actions); 0794 KStandardAction::saveAs(this, SLOT(saveAs()), actions); 0795 0796 action = new QAction(this); 0797 action->setText(i18n("Import Library")); 0798 action->setWhatsThis(i18n("Imports another library appending the symbols it contains to the current library.")); 0799 connect(action, SIGNAL(triggered()), this, SLOT(importLibrary())); 0800 actions->addAction(QStringLiteral("importLibrary"), action); 0801 0802 action = new QAction(this); 0803 action->setText(i18n("Save Symbol")); 0804 action->setWhatsThis(i18n("Save the symbol to the library. If this is a new symbol, subsequent saves will create additional symbols in the library. If the symbol was selected from the library to edit then saving will update that symbol in the library.")); 0805 action->setIcon(QIcon::fromTheme(QStringLiteral("symboleditor-save-symbol"))); 0806 connect(action, SIGNAL(triggered()), this, SLOT(saveSymbol())); 0807 actions->addAction(QStringLiteral("saveSymbol"), action); 0808 0809 action = new QAction(this); 0810 action->setText(i18n("Save Symbol as New")); 0811 action->setWhatsThis(i18n("Save the current symbol as a new one in the library. Subsequent saves will update the new symbol.")); 0812 connect(action, SIGNAL(triggered()), this, SLOT(saveSymbolAsNew())); 0813 actions->addAction(QStringLiteral("saveSymbolAsNew"), action); 0814 0815 KStandardAction::close(this, SLOT(close()), actions); 0816 KStandardAction::quit(this, SLOT(quit()), actions); 0817 0818 // Edit menu 0819 KStandardAction::undo(this, SLOT(undo()), actions); 0820 KStandardAction::redo(this, SLOT(redo()), actions); 0821 0822 // Rendering menu 0823 action = new QAction(this); 0824 action->setText(i18n("Fill Path")); 0825 action->setWhatsThis(i18n("Enable path filling. The path defines the closed boundary of the shape and the path is filled with the selected fill method.")); 0826 action->setIcon(QIcon::fromTheme(QStringLiteral("format-fill-color"))); 0827 action->setCheckable(true); 0828 connect(action, SIGNAL(triggered(bool)), m_editor, SLOT(selectFilled(bool))); 0829 actions->addAction(QStringLiteral("fillPath"), action); 0830 0831 actionGroup = new QActionGroup(this); 0832 actionGroup->setExclusive(true); 0833 0834 action = new QAction(this); 0835 action->setText(i18n("Odd Even Fill")); 0836 action->setWhatsThis(i18n("The Odd Even fill method will fill alternate areas of the symbol.")); 0837 action->setData(Qt::OddEvenFill); 0838 action->setIcon(QIcon::fromTheme(QStringLiteral("symboleditor-odd-even-fill"))); 0839 action->setCheckable(true); 0840 actions->addAction(QStringLiteral("oddEvenFill"), action); 0841 actionGroup->addAction(action); 0842 0843 action = new QAction(this); 0844 action->setText(i18n("Winding Fill")); 0845 action->setWhatsThis(i18n("The Winding fill method will fill the complete interior of the path.")); 0846 action->setData(Qt::WindingFill); 0847 action->setIcon(QIcon::fromTheme(QStringLiteral("symboleditor-winding-fill"))); 0848 action->setCheckable(true); 0849 actions->addAction(QStringLiteral("windingFill"), action); 0850 actionGroup->addAction(action); 0851 0852 connect(actionGroup, SIGNAL(triggered(QAction*)), m_editor, SLOT(selectFillRule(QAction*))); 0853 0854 actionGroup = new QActionGroup(this); 0855 actionGroup->setExclusive(true); 0856 0857 action = new QAction(this); 0858 action->setText(i18n("Flat Cap")); 0859 action->setWhatsThis(i18n("The Flat Cap end type provides a square end that stops at the end point of the line.\n\nThis is only applicable to non-filled paths.")); 0860 action->setData(Qt::FlatCap); 0861 action->setIcon(QIcon::fromTheme(QStringLiteral("stroke-cap-butt"))); 0862 action->setCheckable(true); 0863 actions->addAction(QStringLiteral("flatCap"), action); 0864 actionGroup->addAction(action); 0865 0866 action = new QAction(this); 0867 action->setText(i18n("Square Cap")); 0868 action->setWhatsThis(i18n("The Square Cap end type provides a square end that projects beyond the end point of the line by half the line width.\n\nThis is only applicable to non-filled paths.")); 0869 action->setData(Qt::SquareCap); 0870 action->setIcon(QIcon::fromTheme(QStringLiteral("stroke-cap-square"))); 0871 action->setCheckable(true); 0872 actions->addAction(QStringLiteral("squareCap"), action); 0873 actionGroup->addAction(action); 0874 0875 action = new QAction(this); 0876 action->setText(i18n("Round Cap")); 0877 action->setWhatsThis(i18n("The Round Cap end type provides a round end that projects beyond the end point of the line with a radius of half the line width.\n\nThis is only applicable to non-filled paths.")); 0878 action->setData(Qt::RoundCap); 0879 action->setIcon(QIcon::fromTheme(QStringLiteral("stroke-cap-round"))); 0880 action->setCheckable(true); 0881 actions->addAction(QStringLiteral("roundCap"), action); 0882 actionGroup->addAction(action); 0883 0884 connect(actionGroup, SIGNAL(triggered(QAction*)), m_editor, SLOT(selectCapStyle(QAction*))); 0885 0886 actionGroup = new QActionGroup(this); 0887 actionGroup->setExclusive(true); 0888 0889 action = new QAction(this); 0890 action->setText(i18n("Bevel Join")); 0891 action->setWhatsThis(i18n("The Bevel Join provides a beveled corner between two lines.\n\nThis is only applicable to non-filled paths.")); 0892 action->setData(Qt::BevelJoin); 0893 action->setIcon(QIcon::fromTheme(QStringLiteral("stroke-join-bevel"))); 0894 action->setCheckable(true); 0895 actions->addAction(QStringLiteral("bevelJoin"), action); 0896 actionGroup->addAction(action); 0897 0898 action = new QAction(this); 0899 action->setText(i18n("Miter Join")); 0900 action->setWhatsThis(i18n("The Miter Join provides a mitered corner between two lines.\n\nThis is only applicable to non-filled paths.")); 0901 action->setData(Qt::MiterJoin); 0902 action->setIcon(QIcon::fromTheme(QStringLiteral("stroke-join-miter"))); 0903 action->setCheckable(true); 0904 actions->addAction(QStringLiteral("miterJoin"), action); 0905 actionGroup->addAction(action); 0906 0907 action = new QAction(this); 0908 action->setText(i18n("Round Join")); 0909 action->setWhatsThis(i18n("The Round Join provides a rounded corner between two lines using a radius of half the line width.\n\nThis is only applicable to non-filled paths.")); 0910 action->setData(Qt::RoundJoin); 0911 action->setIcon(QIcon::fromTheme(QStringLiteral("stroke-join-round"))); 0912 action->setCheckable(true); 0913 actions->addAction(QStringLiteral("roundJoin"), action); 0914 actionGroup->addAction(action); 0915 0916 connect(actionGroup, SIGNAL(triggered(QAction*)), m_editor, SLOT(selectJoinStyle(QAction*))); 0917 0918 action = new QAction(this); 0919 action->setText(i18n("Increase Line Width")); 0920 action->setWhatsThis(i18n("Increases the line width.\n\nThis is only applicable to non-filled paths.")); 0921 action->setIcon(QIcon::fromTheme(QStringLiteral("symboleditor-increase-line-width"))); 0922 connect(action, SIGNAL(triggered()), m_editor, SLOT(increaseLineWidth())); 0923 actions->addAction(QStringLiteral("increaseLineWidth"), action); 0924 0925 action = new QAction(this); 0926 action->setText(i18n("Decrease Line Width")); 0927 action->setWhatsThis(i18n("Decreases the line width.\n\nThis is only applicable to non-filled paths.")); 0928 action->setIcon(QIcon::fromTheme(QStringLiteral("symboleditor-decrease-line-width"))); 0929 connect(action, SIGNAL(triggered()), m_editor, SLOT(decreaseLineWidth())); 0930 actions->addAction(QStringLiteral("decreaseLineWidth"), action); 0931 0932 // Tools Menu 0933 actionGroup = new QActionGroup(this); 0934 actionGroup->setExclusive(true); 0935 0936 action = new QAction(this); 0937 action->setText(i18n("Move To")); 0938 action->setWhatsThis(i18n("Move the current point to a new position. This implicitly closes any existing sub path, starting a new one.")); 0939 action->setData(Editor::MoveTo); 0940 action->setIcon(QIcon::fromTheme(QStringLiteral("go-jump"))); 0941 action->setCheckable(true); 0942 actions->addAction(QStringLiteral("moveTo"), action); 0943 actionGroup->addAction(action); 0944 0945 action = new QAction(this); 0946 action->setText(i18n("Draw To")); 0947 action->setWhatsThis(i18n("Add a straight line from the current position to a defined end point. The end point becomes the new current position.")); 0948 action->setData(Editor::LineTo); 0949 action->setIcon(QIcon::fromTheme(QStringLiteral("draw-line"))); 0950 action->setCheckable(true); 0951 actions->addAction(QStringLiteral("lineTo"), action); 0952 actionGroup->addAction(action); 0953 0954 action = new QAction(this); 0955 action->setText(i18n("Cubic To")); 0956 action->setWhatsThis(i18n("Add a cubic bezier curve from the current position using two control points and an end point. The end point becomes the new current position.")); 0957 action->setData(Editor::CubicTo); 0958 action->setIcon(QIcon::fromTheme(QStringLiteral("draw-bezier-curves"))); 0959 action->setCheckable(true); 0960 actions->addAction(QStringLiteral("cubicTo"), action); 0961 actionGroup->addAction(action); 0962 0963 action = new QAction(this); 0964 action->setText(i18n("Rectangle")); 0965 action->setWhatsThis(i18n("Add a rectangle as a separate sub path defined by two points representing the opposite corners.")); 0966 action->setData(Editor::Rectangle); 0967 action->setIcon(QIcon::fromTheme(QStringLiteral("draw-rectangle"))); 0968 action->setCheckable(true); 0969 actions->addAction(QStringLiteral("rectangle"), action); 0970 actionGroup->addAction(action); 0971 0972 action = new QAction(this); 0973 action->setText(i18n("Ellipse")); 0974 action->setWhatsThis(i18n("Add an ellipse as a separate sub path defined by a bounding rectangle represented by two opposite corners.")); 0975 action->setData(Editor::Ellipse); 0976 action->setIcon(QIcon::fromTheme(QStringLiteral("draw-ellipse"))); 0977 action->setCheckable(true); 0978 actions->addAction(QStringLiteral("ellipse"), action); 0979 actionGroup->addAction(action); 0980 0981 action = new QAction(this); 0982 action->setText(i18n("Insert Character")); 0983 action->setWhatsThis(i18n("Allows selection of a character from any font to be inserted as a closed sub path. The inserted character will overwrite any existing path, but additional sub paths may be added to the character.")); 0984 action->setData(Editor::Character); 0985 action->setIcon(QIcon::fromTheme(QStringLiteral("insert-text"))); 0986 action->setCheckable(true); 0987 actions->addAction(QStringLiteral("character"), action); 0988 actionGroup->addAction(action); 0989 0990 connect(actionGroup, SIGNAL(triggered(QAction*)), m_editor, SLOT(selectTool(QAction*))); 0991 0992 action = new QAction(this); 0993 action->setText(i18n("Rotate Left")); 0994 action->setWhatsThis(i18n("Rotate all the points of a path counter-clockwise 90 degrees around the center of the editor.")); 0995 action->setIcon(QIcon::fromTheme(QStringLiteral("object-rotate-left"))); 0996 connect(action, SIGNAL(triggered()), m_editor, SLOT(rotateLeft())); 0997 actions->addAction(QStringLiteral("rotateLeft"), action); 0998 0999 action = new QAction(this); 1000 action->setText(i18n("Rotate Right")); 1001 action->setWhatsThis(i18n("Rotate all the points of a path clockwise 90 degrees around the center point of the editor.")); 1002 action->setIcon(QIcon::fromTheme(QStringLiteral("object-rotate-right"))); 1003 connect(action, SIGNAL(triggered()), m_editor, SLOT(rotateRight())); 1004 actions->addAction(QStringLiteral("rotateRight"), action); 1005 1006 action = new QAction(this); 1007 action->setText(i18n("Flip Horizontal")); 1008 action->setWhatsThis(i18n("Flip all the points of the path horizontally about the vertical center of the editor.")); 1009 action->setIcon(QIcon::fromTheme(QStringLiteral("object-flip-horizontal"))); 1010 connect(action, SIGNAL(triggered()), m_editor, SLOT(flipHorizontal())); 1011 actions->addAction(QStringLiteral("flipHorizontal"), action); 1012 1013 action = new QAction(this); 1014 action->setText(i18n("Flip Vertical")); 1015 action->setWhatsThis(i18n("Flip all the points of the path vertically about the horizontal center of the editor.")); 1016 action->setIcon(QIcon::fromTheme(QStringLiteral("object-flip-vertical"))); 1017 connect(action, SIGNAL(triggered()), m_editor, SLOT(flipVertical())); 1018 actions->addAction(QStringLiteral("flipVertical"), action); 1019 1020 action = new QAction(this); 1021 action->setText(i18n("Scale to Preferred Size")); 1022 action->setWhatsThis(i18n("Scale the current symbol so that it fits within the preferred size of a symbol.")); 1023 action->setIcon(QIcon::fromTheme(QStringLiteral("symboleditor-scale-preferred"))); 1024 connect(action, SIGNAL(triggered()), m_editor, SLOT(scalePreferred())); 1025 actions->addAction(QStringLiteral("scalePreferred"), action); 1026 1027 action = new QAction(this); 1028 action->setText(i18n("Enable Snap")); 1029 action->setWhatsThis(i18n("Enable snapping of points to guide intersections or to the grid.")); 1030 action->setIcon(QIcon::fromTheme(QStringLiteral("snap-orthogonal"))); 1031 action->setCheckable(true); 1032 connect(action, SIGNAL(toggled(bool)), m_editor, SLOT(enableSnap(bool))); 1033 actions->addAction(QStringLiteral("enableSnap"), action); 1034 1035 action = new QAction(this); 1036 action->setText(i18n("Enable Guides")); 1037 action->setWhatsThis(i18n("Enable the generation of guide intersections.")); 1038 action->setIcon(QIcon::fromTheme(QStringLiteral("snap-intersection"))); 1039 action->setCheckable(true); 1040 connect(action, SIGNAL(toggled(bool)), m_editor, SLOT(enableGuides(bool))); 1041 actions->addAction(QStringLiteral("enableGuides"), action); 1042 1043 // Settings Menu 1044 KStandardAction::preferences(this, SLOT(preferences()), actions); 1045 } 1046 1047 1048 /** 1049 * Set the actions status based on the settings in the specified Symbol. 1050 * 1051 * @param symbol a const reference to a Symbol 1052 */ 1053 void MainWindow::setActionsFromSymbol(const Symbol &symbol) 1054 { 1055 action("fillPath")->setChecked(symbol.filled()); 1056 1057 switch (symbol.path().fillRule()) { 1058 case Qt::WindingFill: 1059 action("windingFill")->setChecked(true); 1060 break; 1061 1062 case Qt::OddEvenFill: 1063 action("oddEvenFill")->setChecked(true); 1064 break; 1065 } 1066 1067 switch (symbol.capStyle()) { 1068 case Qt::FlatCap: 1069 action("flatCap")->setChecked(true); 1070 break; 1071 1072 case Qt::SquareCap: 1073 action("squareCap")->setChecked(true); 1074 break; 1075 1076 case Qt::RoundCap: 1077 action("roundCap")->setChecked(true); 1078 break; 1079 1080 case Qt::MPenCapStyle: // this is a combination of the Qt::FlatCap, Qt::SquareCap and Qt::RoundCap 1081 break; 1082 } 1083 1084 switch (symbol.joinStyle()) { 1085 case Qt::BevelJoin: 1086 action("bevelJoin")->setChecked(true); 1087 break; 1088 1089 case Qt::MiterJoin: 1090 case Qt::SvgMiterJoin: 1091 action("miterJoin")->setChecked(true); 1092 break; 1093 1094 case Qt::RoundJoin: 1095 action("roundJoin")->setChecked(true); 1096 break; 1097 1098 case Qt::MPenJoinStyle: // this is a combination of Qt::BevelJoin, Qt::MiterJoin, Qt::SvgMiterJoin and Qt::RoundJoin 1099 break; 1100 } 1101 1102 action("increaseLineWidth")->setDisabled(symbol.lineWidth() == 1.00); 1103 action("decreaseLineWidth")->setDisabled(symbol.lineWidth() == 0.01); 1104 } 1105 1106 #include "moc_MainWindow.cpp"