Warning, file /sdk/ktechlab/src/ktechlab.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) 2003-2005 by David Saxton * 0003 * david@bluehaze.org * 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 <KXMLGUIClient> 0012 0013 #include "circuitdocument.h" 0014 #include "componentmodellibrary.h" 0015 #include "config.h" 0016 #include "contexthelp.h" 0017 #include "docmanager.h" 0018 #include "filemetainfo.h" 0019 #include "flowcodedocument.h" 0020 #include "itemeditor.h" 0021 #include "itemgroup.h" 0022 #include "iteminterface.h" 0023 #include "itemlibrary.h" 0024 #include "ktechlab.h" 0025 #include "languagemanager.h" 0026 #include "mechanicsdocument.h" 0027 #include "microlibrary.h" 0028 #include "newfiledlg.h" 0029 #include "oscilloscope.h" 0030 #include "projectmanager.h" 0031 #include "scopescreen.h" 0032 #include "settingsdlg.h" 0033 #include "subcircuits.h" 0034 #include "symbolviewer.h" 0035 #include "textdocument.h" 0036 #include "textview.h" 0037 #include "viewcontainer.h" 0038 0039 // #include <q3dockarea.h> 0040 #include <QTimer> 0041 #include <QToolButton> 0042 // #include <q3ptrlist.h> 0043 #include <QDesktopWidget> 0044 #include <QFileDialog> 0045 #include <QIcon> 0046 #include <QMenu> 0047 #include <QMimeData> 0048 #include <QStandardPaths> 0049 #include <QTabWidget> 0050 0051 #include <KActionCollection> 0052 #include <KEditToolBar> 0053 #include <KSharedConfig> 0054 #include <KToolBar> 0055 0056 //#include <kkeydialog.h> 0057 #include <KLocalizedString> 0058 #include <KMessageBox> 0059 //#include <kpopupmenu.h> 0060 //#include <kwin.h> 0061 #include <KRecentFilesAction> 0062 #include <KShortcutsDialog> 0063 #include <KStandardAction> 0064 #include <KToolBarPopupAction> 0065 #include <KWindowSystem> 0066 #include <KXMLGUIFactory> 0067 0068 #include <ktlconfig.h> 0069 #include <ktechlab_debug.h> 0070 0071 KTechlab *KTechlab::m_pSelf = nullptr; 0072 0073 KTechlab::KTechlab() 0074 : KateMDI::MainWindow(nullptr) 0075 { 0076 setObjectName("KTechlab"); 0077 m_pSelf = this; 0078 0079 QTime ct; 0080 ct.start(); 0081 0082 m_bIsShown = false; 0083 m_pContainerDropSource = nullptr; 0084 m_pContainerDropReceived = nullptr; 0085 m_pContextMenuContainer = nullptr; 0086 m_pFocusedContainer = nullptr; 0087 m_pToolBarOverlayLabel = nullptr; 0088 0089 if (QFontInfo(m_itemFont).pixelSize() > 11) { 0090 // It has to be > 11, not > 12, as (I think) pixelSize() rounds off the actual size 0091 m_itemFont.setPixelSize(12); 0092 } 0093 0094 m_pUpdateCaptionsTimer = new QTimer(this); 0095 connect(m_pUpdateCaptionsTimer, &QTimer::timeout, this, &KTechlab::slotUpdateCaptions); 0096 0097 setMinimumSize(400, 400); 0098 0099 setupTabWidget(); 0100 setupToolDocks(); 0101 setupActions(); 0102 setupView(); 0103 // readProperties( KGlobal::config() ); 0104 KSharedConfigPtr cfg = KSharedConfig::openConfig(); 0105 readPropertiesInConfig(cfg.data()); 0106 0107 // qCDebug(KTL_LOG) << "Constructor time: " << ct.elapsed(); 0108 } 0109 0110 KTechlab::~KTechlab() 0111 { 0112 fileMetaInfo()->saveAllMetaInfo(); 0113 0114 for (ViewContainerList::Iterator itVc = m_viewContainerList.begin(); itVc != m_viewContainerList.end(); ++itVc) { 0115 ViewContainer *vc = itVc->data(); 0116 disconnect(vc, &ViewContainer::destroyed, this, &KTechlab::slotViewContainerDestroyed); 0117 } 0118 0119 delete fileMetaInfo(); 0120 delete itemLibrary(); // This better be the last time the item library is used! 0121 delete subcircuits(); 0122 } 0123 0124 void KTechlab::show() 0125 { 0126 KateMDI::MainWindow::show(); 0127 m_bIsShown = true; 0128 } 0129 0130 void KTechlab::openFile(ViewArea *viewArea) 0131 { 0132 const QList<QUrl> files = getFileURLs(false); 0133 if (files.isEmpty()) 0134 return; 0135 0136 load(files.first(), viewArea); 0137 } 0138 0139 void KTechlab::load(const QUrl &url, ViewArea *viewArea) 0140 { 0141 if (!url.isValid()) 0142 return; 0143 0144 loadInternal(url, false, viewArea); 0145 } 0146 0147 void KTechlab::slotLoadRecent(const QUrl &url) 0148 { 0149 loadInternal(url, true); 0150 } 0151 0152 void KTechlab::loadInternal(const QUrl &url, bool isRecent, ViewArea *viewArea) 0153 { 0154 if (url.fileName().endsWith(".ktechlab", Qt::CaseInsensitive)) { 0155 // This is a ktechlab project; it has to be handled separetly from a 0156 // normal file. 0157 0158 ProjectManager::self()->slotOpenProject(url); 0159 return; 0160 } 0161 0162 if (!isRecent) 0163 addRecentFile(url); 0164 0165 // set our caption 0166 setCaption(url.toDisplayString(QUrl::PreferLocalFile)); 0167 0168 // load in the file (target is always local) 0169 DocManager::self()->openURL(url, viewArea); 0170 } 0171 0172 QList<QUrl> KTechlab::recentFiles() 0173 { 0174 return m_recentFiles->urls(); 0175 } 0176 0177 void KTechlab::setupToolDocks() 0178 { 0179 setToolViewStyle(KMultiTabBar::KDEV3ICON); 0180 0181 KateMDI::ToolView *tv = nullptr; 0182 0183 tv = createToolView(ProjectManager::toolViewIdentifier(), KMultiTabBar::Left, QIcon::fromTheme("attach"), i18n("Project")); 0184 tv->setObjectName("ProjectManager-ToolView"); 0185 ProjectManager::self(tv); 0186 0187 tv = createToolView(ComponentSelector::toolViewIdentifier(), KMultiTabBar::Left, QIcon::fromTheme("circuit"), i18n("Components")); 0188 tv->setObjectName("ComponentSelector-ToolView"); 0189 ComponentSelector::self(tv); 0190 0191 // Create an instance of the subcircuits interface, now that we have created the component selector 0192 subcircuits(); 0193 Subcircuits::loadSubcircuits(); 0194 0195 tv = createToolView(FlowPartSelector::toolViewIdentifier(), KMultiTabBar::Left, QIcon::fromTheme("flowcode"), i18n("Flow Parts")); 0196 tv->setObjectName("FlowPartSelector-ToolView"); 0197 FlowPartSelector::self(tv); 0198 0199 #ifdef MECHANICS 0200 tv = createToolView(MechanicsSelector::toolViewIdentifier(), KMultiTabBar::Left, QIcon::fromTheme("mechanics"), i18n("Mechanics")); 0201 tv->setObjectName("MechanicsSelector-ToolView"); 0202 MechanicsSelector::self(tv); 0203 #endif 0204 0205 tv = createToolView(ItemEditor::toolViewIdentifier(), KMultiTabBar::Right, QIcon::fromTheme("item"), i18n("Item Editor")); 0206 tv->setObjectName("ItemEditor-ToolView"); 0207 ItemEditor::self(tv); 0208 0209 tv = createToolView(ContextHelp::toolViewIdentifier(), KMultiTabBar::Right, QIcon::fromTheme("help-contents"), i18n("Context Help")); 0210 tv->setObjectName("ContextHelp-ToolView"); 0211 ContextHelp::self(tv); 0212 0213 tv = createToolView(LanguageManager::toolViewIdentifier(), KMultiTabBar::Bottom, QIcon::fromTheme("utilities-log-viewer"), i18n("Messages")); 0214 tv->setObjectName("LanguageManager-ToolView"); 0215 LanguageManager::self(tv); 0216 0217 #ifndef NO_GPSIM 0218 tv = createToolView(SymbolViewer::toolViewIdentifier(), KMultiTabBar::Right, QIcon::fromTheme("blockdevice"), i18n("Symbol Viewer")); 0219 tv->setObjectName("SymbolViewer-ToolView"); 0220 SymbolViewer::self(tv); 0221 #endif 0222 0223 addOscilloscopeAsToolView(this); 0224 #if 1 0225 tv = createToolView(ScopeScreen::toolViewIdentifier(), KMultiTabBar::Bottom, QIcon::fromTheme("oscilloscope"), i18n("Scope Screen (Very Rough)")); 0226 tv->setObjectName("ScopeScreen-ToolView"); 0227 ScopeScreen::self(tv); 0228 #endif 0229 0230 updateSidebarMinimumSizes(); 0231 } 0232 0233 void KTechlab::addWindow(ViewContainer *vc) 0234 { 0235 if (vc && !m_viewContainerList.contains(vc)) { 0236 m_viewContainerList << vc; 0237 connect(vc, &ViewContainer::destroyed, this, &KTechlab::slotViewContainerDestroyed); 0238 } 0239 0240 m_viewContainerList.removeAll((ViewContainer *)nullptr); 0241 slotUpdateTabWidget(); 0242 slotDocModifiedChanged(); 0243 } 0244 0245 void KTechlab::setupView() 0246 { 0247 setAcceptDrops(true); 0248 setStandardToolBarMenuEnabled(true); 0249 setXMLFile("ktechlabui.rc"); 0250 createShellGUI(true); 0251 // 2017.09.04 - no need to explicitly add the new file selector to toolbar 0252 ////action("newfile_popup")->plug( toolBar("mainToolBar"), 0 ); 0253 // actionByName("file_new")->addTo( toolBar("mainToolBar") ); 0254 ////action("file_new")->unplug( toolBar("mainToolBar") ); 0255 // actionByName("file_new")->removeFrom( toolBar("mainToolBar") ); 0256 setupExampleActions(); 0257 statusBar()->show(); 0258 } 0259 0260 void KTechlab::overlayToolBarScreenshot() 0261 { 0262 return; 0263 0264 if (!m_pToolBarOverlayLabel) { 0265 m_pToolBarOverlayLabel = new QLabel(nullptr, 0266 Qt::WindowStaysOnTopHint /* | Qt::WStyle_Customize */ | 0267 Qt::FramelessWindowHint 0268 /*| Qt::WNoAutoErase */ 0269 | Qt::Popup); 0270 m_pToolBarOverlayLabel->hide(); 0271 // m_pToolBarOverlayLabel->setBackgroundMode( Qt::NoBackground ); // 2018.12.02 0272 QPalette p; 0273 p.setColor(m_pToolBarOverlayLabel->backgroundRole(), Qt::transparent); 0274 m_pToolBarOverlayLabel->setPalette(p); 0275 } 0276 0277 if (!m_bIsShown) { 0278 // The window isn't visible yet, so there's nothing to overlay (and if we tried, 0279 // it would appear as a strange floating toolbar). 0280 return; 0281 } 0282 0283 if (m_pToolBarOverlayLabel->isVisible()) { 0284 // This is to avoid successive calls to removeGUIClient when we have 0285 // already popped it up for the first call, and don't want to take 0286 // another screenshot (as that would be without the toolbar). 0287 return; 0288 } 0289 0290 // QPtrListIterator<KToolBar> toolBarIterator(); // unused? 0291 0292 // QWidget * toolsWidget = toolBar( "toolsToolBar" ); 0293 // QWidget * debugWidget = toolBar( "debugTB" ); 0294 0295 // KToolBar * toolsWidget = static_cast<KToolBar*>(child( "toolsToolBar", "KToolBar" )); // 2018.08.18 - see below 0296 // KToolBar * debugWidget = static_cast<KToolBar*>(child( "debugTB", "KToolBar" )); 0297 KToolBar *toolsWidget = findChild<KToolBar *>("toolsToolBar"); 0298 KToolBar *debugWidget = findChild<KToolBar *>("debugTB"); 0299 0300 if (!toolsWidget && !debugWidget) 0301 return; 0302 0303 QWidget *parent = static_cast<QWidget *>(toolsWidget ? toolsWidget->parent() : debugWidget->parent()); 0304 0305 QRect grabRect; 0306 0307 // 128 is a sanity check (widget can do strange things when being destroyed) 0308 0309 if (toolsWidget && toolsWidget->height() <= 128) 0310 grabRect |= toolsWidget->geometry(); 0311 if (debugWidget && debugWidget->height() <= 128) 0312 grabRect |= debugWidget->geometry(); 0313 0314 if (!grabRect.isValid()) 0315 return; 0316 0317 QPixmap shot = parent->grab(grabRect); 0318 0319 m_pToolBarOverlayLabel->move(parent->mapToGlobal(grabRect.topLeft())); 0320 m_pToolBarOverlayLabel->setFixedSize(grabRect.size()); 0321 m_pToolBarOverlayLabel->setPixmap(shot); 0322 m_pToolBarOverlayLabel->show(); 0323 0324 QTimer::singleShot(100, this, SLOT(hideToolBarOverlay())); 0325 } 0326 0327 void KTechlab::hideToolBarOverlay() 0328 { 0329 if (!m_pToolBarOverlayLabel) 0330 return; 0331 0332 // QWidget * hiddenWidget = toolBar( "toolsToolBar" ); 0333 // if ( !hiddenWidget ) 0334 // return; 0335 0336 // hiddenWidget->setBackgroundMode( NoBackground ); 0337 // hiddenWidget->setWFlags( WNoAutoErase ); 0338 // hiddenWidget->setUpdatesEnabled( false ); 0339 0340 m_pToolBarOverlayLabel->hide(); 0341 } 0342 0343 void KTechlab::addNoRemoveGUIClient(KXMLGUIClient *client) 0344 { 0345 if (client && !m_noRemoveGUIClients.contains(client)) 0346 m_noRemoveGUIClients << client; 0347 } 0348 0349 void KTechlab::removeGUIClients() 0350 { 0351 QList<KXMLGUIClient *> clientsToRemove; 0352 0353 QList<KXMLGUIClient *> clients = factory()->clients(); 0354 // for ( KXMLGUIClient * client = clients.first(); client; client = clients.next() ) 0355 for (QList<KXMLGUIClient *>::iterator itClient = clients.begin(); itClient != clients.end(); ++itClient) { 0356 // if ( client && client != this && !m_noRemoveGUIClients.contains( client ) ) 0357 if ((*itClient != this) && (!m_noRemoveGUIClients.contains(*itClient))) 0358 clientsToRemove << *itClient; 0359 } 0360 0361 if (clients.isEmpty()) 0362 return; 0363 0364 overlayToolBarScreenshot(); 0365 0366 QList<KXMLGUIClient *>::iterator end = clientsToRemove.end(); 0367 for (QList<KXMLGUIClient *>::iterator it = clientsToRemove.begin(); it != end; ++it) 0368 factory()->removeClient(*it); 0369 } 0370 0371 void KTechlab::setupTabWidget() 0372 { 0373 m_pViewContainerTabWidget = new QTabWidget(centralWidget()); 0374 if (centralWidget()->layout()) { 0375 centralWidget()->layout()->addWidget(m_pViewContainerTabWidget); 0376 } else { 0377 qCWarning(KTL_LOG) << " unexpected null layout for " << centralWidget(); 0378 } 0379 connect(tabWidget(), &QTabWidget::currentChanged, this, &KTechlab::slotViewContainerActivated); 0380 0381 // KConfig *config = kapp->config(); 0382 // config->setGroup("UI"); 0383 KSharedConfigPtr cfg = KSharedConfig::openConfig(); 0384 KConfigGroup grUi = cfg->group("UI"); 0385 0386 bool CloseOnHover = grUi.readEntry("CloseOnHover", false); 0387 // tabWidget()->setHoverCloseButton( CloseOnHover ); // 2018.08.18 - see below 0388 tabWidget()->setTabsClosable(CloseOnHover); 0389 0390 bool CloseOnHoverDelay = grUi.readEntry("CloseOnHoverDelay", false); 0391 // tabWidget()->setHoverCloseButtonDelayed( CloseOnHoverDelay ); // 2018.08.18 - see below 0392 tabWidget()->setTabsClosable(CloseOnHoverDelay); 0393 0394 if (grUi.readEntry("ShowCloseTabsButton", true)) { 0395 QToolButton *but = new QToolButton(tabWidget()); 0396 but->setIcon(QIcon::fromTheme("tab-close")); 0397 but->adjustSize(); 0398 but->hide(); 0399 connect(but, &QToolButton::clicked, this, &KTechlab::slotViewContainerClose); 0400 tabWidget()->setCornerWidget(but, Qt::TopRightCorner); 0401 } 0402 0403 QTabBar *tabBar = tabWidget()->tabBar(); 0404 tabBar->setContextMenuPolicy(Qt::CustomContextMenu); 0405 connect(tabBar, &QTabBar::customContextMenuRequested, this, &KTechlab::slotTabContext); 0406 } 0407 0408 void KTechlab::slotUpdateTabWidget() 0409 { 0410 m_viewContainerList.removeAll((ViewContainer *)nullptr); 0411 0412 bool noWindows = m_viewContainerList.isEmpty(); 0413 0414 if (QWidget *button = tabWidget()->cornerWidget(Qt::TopRightCorner)) 0415 button->setHidden(noWindows); 0416 0417 if (noWindows) 0418 setCaption(nullptr); 0419 } 0420 0421 void KTechlab::setupActions() 0422 { 0423 KActionCollection *ac = actionCollection(); 0424 // TODO move the actions from KTechLab object level to document view level for 0425 // all types of documents; see actions marked with (1)! and TextView constructor 0426 0427 // 2017.08.06 - using custom new action 0428 // KStandardAction::openNew( this, SLOT(slotFileNew()), ac ); 0429 { 0430 QAction *openAction = KStandardAction::open(this, SLOT(slotFileOpen()), ac); 0431 openAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); 0432 } 0433 KStandardAction::save(this, SLOT(slotFileSave()), ac); // (1)! 0434 KStandardAction::saveAs(this, SLOT(slotFileSaveAs()), ac); 0435 KStandardAction::close(this, SLOT(slotViewClose()), ac); 0436 KStandardAction::print(this, SLOT(slotFilePrint()), ac); // (1)! 0437 KStandardAction::quit(this, SLOT(slotFileQuit()), ac); 0438 KStandardAction::undo(this, SLOT(slotEditUndo()), ac); // (1)! 0439 KStandardAction::redo(this, SLOT(slotEditRedo()), ac); // (1)! 0440 KStandardAction::cut(this, SLOT(slotEditCut()), ac); // (1)! 0441 KStandardAction::copy(this, SLOT(slotEditCopy()), ac); // (1)! 0442 KStandardAction::paste(this, SLOT(slotEditPaste()), ac); // (1)! 0443 KStandardAction::keyBindings(this, SLOT(slotOptionsConfigureKeys()), ac); 0444 KStandardAction::configureToolbars(this, SLOT(slotOptionsConfigureToolbars()), ac); 0445 KStandardAction::preferences(this, SLOT(slotOptionsPreferences()), ac); 0446 0447 // BEGIN New file popup 0448 // KToolBarPopupAction *p = new KToolBarPopupAction( i18n("&New"), "document-new", 0449 // KStandardShortcut::shortcut(KStandardShortcut::New), this, SLOT(slotFileNew()), ac, "newfile_popup" ); 0450 KToolBarPopupAction *p = new KToolBarPopupAction(QIcon::fromTheme("document-new"), i18n("&New"), ac); 0451 p->setObjectName("file_new"); 0452 p->setShortcuts(KStandardShortcut::shortcut(KStandardShortcut::New)); 0453 connect(p, &KToolBarPopupAction::triggered, this, &KTechlab::slotFileNew); 0454 ac->addAction(p->objectName(), p); 0455 p->menu()->setTitle(i18n("New File")); 0456 { 0457 //(new QAction( i18n("Assembly"), "source", 0, this, SLOT(slotFileNewAssembly()), ac, "newfile_asm" ))->plug( p->menu() ); 0458 QAction *a = new QAction(QIcon::fromTheme("source"), i18n("Assembly"), ac); 0459 a->setObjectName("newfile_asm"); 0460 connect(a, &QAction::triggered, this, &KTechlab::slotFileNewAssembly); 0461 p->menu()->addAction(a); 0462 ac->addAction(a->objectName(), a); 0463 } 0464 { 0465 //(new QAction( i18n("C source"), "text-x-csrc", 0, this, SLOT(slotFileNewC()), ac, "newfile_c" ))->plug( p->menu() ); 0466 QAction *a = new QAction(QIcon::fromTheme("text-x-csrc"), i18n("C source"), ac); 0467 a->setObjectName("newfile_c"); 0468 connect(a, &QAction::triggered, this, &KTechlab::slotFileNewC); 0469 p->menu()->addAction(a); 0470 ac->addAction(a->objectName(), a); 0471 } 0472 { 0473 //(new QAction( i18n("Circuit"), "application-x-circuit", 0, this, SLOT(slotFileNewCircuit()), ac, "newfile_circuit" ))->plug( p->menu() ); 0474 QAction *a = new QAction(QIcon::fromTheme("application-x-circuit"), i18n("Circuit"), ac); 0475 a->setObjectName("newfile_circuit"); 0476 connect(a, &QAction::triggered, this, &KTechlab::slotFileNewCircuit); 0477 p->menu()->addAction(a); 0478 ac->addAction(a->objectName(), a); 0479 } 0480 { 0481 //(new QAction( i18n("FlowCode"), "application-x-flowcode", 0, this, SLOT(slotFileNewFlowCode()), ac, "newfile_flowcode" ))->plug( p->menu() ); 0482 QAction *a = new QAction(QIcon::fromTheme("application-x-flowcode"), i18n("FlowCode"), ac); 0483 a->setObjectName("newfile_flowcode"); 0484 connect(a, &QAction::triggered, this, &KTechlab::slotFileNewFlowCode); 0485 p->menu()->addAction(a); 0486 ac->addAction(a->objectName(), a); 0487 } 0488 #ifdef MECHANICS 0489 { 0490 //(new QAction( i18n("Mechanics"), "ktechlab_mechanics", 0, this, SLOT(slotFileNewMechanics()), ac, "newfile_mechanics" ))->plug( p->menu() ); 0491 QAction *a = new QAction(QIcon::fromTheme("" /* "ktechlab_mechanics" -- for the future */), i18n("Mechanics"), ac); 0492 a->setObjectName("newfile_mechanics"); 0493 connect(a, &QAction::triggered, this, &KTechlab::slotFileNewMechanics); 0494 p->menu()->addAction(a); 0495 ac->addAction(a->objectName(), a); 0496 } 0497 #endif 0498 { 0499 //(new QAction( "Microbe", "application-x-microbe", 0, this, SLOT(slotFileNewMicrobe()), ac, "newfile_microbe" ))->plug( p->menu() ); 0500 QAction *a = new QAction(QIcon::fromTheme("application-x-microbe"), i18n("Microbe"), ac); 0501 a->setObjectName("newfile_microbe"); 0502 connect(a, &QAction::triggered, this, &KTechlab::slotFileNewMicrobe); 0503 p->menu()->addAction(a); 0504 ac->addAction(a->objectName(), a); 0505 } 0506 // END New File popup 0507 0508 m_recentFiles = KStandardAction::openRecent(this, SLOT(slotLoadRecent(QUrl)), ac); 0509 0510 m_statusbarAction = KStandardAction::showStatusbar(this, SLOT(slotOptionsShowStatusbar()), ac); 0511 ac->addAction(m_statusbarAction->objectName(), m_statusbarAction); 0512 0513 // BEGIN Project Actions 0514 ProjectManager *pm = ProjectManager::self(); 0515 { 0516 // new QAction( i18n("New Project..."), "window-new", 0, pm, SLOT(slotNewProject()), ac, "project_new" ); 0517 QAction *a = new QAction(QIcon::fromTheme("window-new"), i18n("New Project..."), ac); 0518 a->setObjectName("project_new"); 0519 connect(a, &QAction::triggered, pm, &ProjectManager::slotNewProject); 0520 ac->addAction(a->objectName(), a); 0521 } 0522 { 0523 // new QAction( i18n("Open Project..."), "project-open", 0, pm, SLOT(slotOpenProject()), ac, "project_open" ); 0524 QAction *a = new QAction(QIcon::fromTheme("project-open"), i18n("Open Project..."), ac); 0525 a->setObjectName("project_open"); 0526 connect(a, &QAction::triggered, pm, qOverload<>(&ProjectManager::slotOpenProject)); 0527 ac->addAction(a->objectName(), a); 0528 } 0529 { 0530 m_recentProjects = new KRecentFilesAction(i18n("Open &Recent Project..."), ac); 0531 m_recentProjects->setObjectName("project_open_recent"); 0532 connect(m_recentProjects, SIGNAL(urlSelected(QUrl)), ProjectManager::self(), SLOT(slotOpenProject(QUrl))); 0533 ac->addAction(m_recentProjects->objectName(), m_recentProjects); 0534 } 0535 { 0536 // new QAction( i18n("Export to Makefile..."), "document-export", 0, pm, SLOT(slotExportToMakefile()), ac, "project_export_makefile" ); 0537 QAction *a = new QAction(QIcon::fromTheme("document-export"), i18n("Export to Makefile..."), ac); 0538 a->setObjectName("project_export_makefile"); 0539 connect(a, &QAction::triggered, pm, &ProjectManager::slotExportToMakefile); 0540 ac->addAction(a->objectName(), a); 0541 } 0542 { 0543 // new QAction( i18n("Create Subproject..."), 0, 0, pm, SLOT(slotCreateSubproject()), ac, "project_create_subproject" ); 0544 QAction *a = new QAction(i18n("Create Subproject..."), ac); 0545 a->setObjectName("project_create_subproject"); 0546 connect(a, &QAction::triggered, pm, &ProjectManager::slotCreateSubproject); 0547 ac->addAction(a->objectName(), a); 0548 } 0549 { 0550 // new QAction( i18n("Add Existing File..."), "document-open", 0, pm, SLOT(slotAddFile()), ac, "project_add_existing_file" ); 0551 QAction *a = new QAction(QIcon::fromTheme("document-open"), i18n("Add Existing File..."), ac); 0552 a->setObjectName("project_add_existing_file"); 0553 connect(a, &QAction::triggered, pm, &ProjectManager::slotAddFile); 0554 ac->addAction(a->objectName(), a); 0555 } 0556 { 0557 // new QAction( i18n("Add Current File..."), "document-import", 0, pm, SLOT(slotAddCurrentFile()), ac, "project_add_current_file" ); 0558 QAction *a = new QAction(QIcon::fromTheme("document-import"), i18n("Add Current File..."), ac); 0559 a->setObjectName("project_add_current_file"); 0560 connect(a, &QAction::triggered, pm, &ProjectManager::slotAddCurrentFile); 0561 ac->addAction(a->objectName(), a); 0562 } 0563 // new QAction( i18n("Project Options"), "configure", 0, pm, SLOT(slotProjectOptions()), ac, "project_options" ); 0564 // ^ TODO why commented? 0565 { 0566 // new QAction( i18n("Close Project"), "window-close", 0, pm, SLOT(slotCloseProject()), ac, "project_close" ); 0567 QAction *a = new QAction(QIcon::fromTheme("window-close"), i18n("Close Project"), ac); 0568 a->setObjectName("project_close"); 0569 connect(a, &QAction::triggered, pm, &ProjectManager::slotCloseProject); 0570 ac->addAction(a->objectName(), a); 0571 } 0572 { 0573 // new QAction( i18n("Remove from Project"), "edit-delete", 0, pm, SLOT(slotRemoveSelected()), ac, "project_remove_selected" ); 0574 QAction *a = new QAction(QIcon::fromTheme("edit-delete"), i18n("Remove from Project"), ac); 0575 a->setObjectName("project_remove_selected"); 0576 connect(a, &QAction::triggered, pm, &ProjectManager::slotRemoveSelected); 0577 ac->addAction(a->objectName(), a); 0578 } 0579 { 0580 // new QAction( i18n("Insert Existing File..."), "document-open", 0, pm, SLOT(slotSubprojectAddExistingFile()), ac, "subproject_add_existing_file" ); 0581 QAction *a = new QAction(QIcon::fromTheme("document-open"), i18n("Insert Existing File..."), ac); 0582 a->setObjectName("subproject_add_existing_file"); 0583 connect(a, &QAction::triggered, pm, &ProjectManager::slotSubprojectAddExistingFile); 0584 ac->addAction(a->objectName(), a); 0585 } 0586 { 0587 // new QAction( i18n("Insert Current File..."), "document-import", 0, pm, SLOT(slotSubprojectAddCurrentFile()),ac, "subproject_add_current_file" ); 0588 QAction *a = new QAction(QIcon::fromTheme("document-import"), i18n("Insert Current File..."), ac); 0589 a->setObjectName("subproject_add_current_file"); 0590 connect(a, &QAction::triggered, pm, &ProjectManager::slotSubprojectAddCurrentFile); 0591 ac->addAction(a->objectName(), a); 0592 } 0593 { 0594 // new QAction( i18n("Linker Options..."), "configure", 0, pm, SLOT(slotSubprojectLinkerOptions()), ac, "project_item_linker_options" ); 0595 QAction *a = new QAction(QIcon::fromTheme("configure"), i18n("Linker Options..."), ac); 0596 a->setObjectName("project_item_linker_options"); 0597 connect(a, &QAction::triggered, pm, &ProjectManager::slotSubprojectLinkerOptions); 0598 ac->addAction(a->objectName(), a); 0599 } 0600 { 0601 // new QAction( i18n("Build..."), "launch", 0, pm, SLOT(slotItemBuild()), ac, "project_item_build" ); 0602 QAction *a = new QAction(QIcon::fromTheme("run-build"), i18n("Build..."), ac); 0603 a->setObjectName("project_item_build"); 0604 connect(a, &QAction::triggered, pm, &ProjectManager::slotItemBuild); 0605 ac->addAction(a->objectName(), a); 0606 } 0607 { 0608 // new QAction( i18n("Upload..."), "convert_to_pic", 0, pm, SLOT(slotItemUpload()), ac, "project_item_upload" ); 0609 QAction *a = new QAction(QIcon::fromTheme("convert_to_pic"), i18n("Upload..."), ac); 0610 a->setObjectName("project_item_upload"); 0611 connect(a, &QAction::triggered, pm, &ProjectManager::slotItemUpload); 0612 ac->addAction(a->objectName(), a); 0613 } 0614 { 0615 // new QAction( i18n("Processing Options..."), "configure", 0, pm, SLOT(slotItemProcessingOptions()), ac, "project_item_processing_options" ); 0616 QAction *a = new QAction(QIcon::fromTheme("configure"), i18n("Processing Options..."), ac); 0617 a->setObjectName("project_item_processing_options"); 0618 connect(a, &QAction::triggered, pm, &ProjectManager::slotItemProcessingOptions); 0619 ac->addAction(a->objectName(), a); 0620 } 0621 // END Project Actions 0622 0623 { 0624 // new QAction( i18n("Split View Left/Right"), "view-split-left-right", Qt::CTRL|Qt::SHIFT|Qt::Key_L, this, SLOT(slotViewSplitLeftRight()), ac, "view_split_leftright" ); 0625 QAction *a = new QAction(QIcon::fromTheme("view-split-left-right"), i18n("Split View Left/Right"), ac); 0626 a->setObjectName("view_split_leftright"); 0627 connect(a, &QAction::triggered, this, &KTechlab::slotViewSplitLeftRight); 0628 ac->addAction(a->objectName(), a); 0629 } 0630 { 0631 // new QAction( i18n("Split View Top/Bottom"), "view-split-top-bottom", Qt::CTRL|Qt::SHIFT|Qt::Key_T, this, SLOT(slotViewSplitTopBottom()), ac, "view_split_topbottom" ); 0632 QAction *a = new QAction(QIcon::fromTheme("view-split-top-bottom"), i18n("Split View Top/Bottom"), ac); 0633 a->setObjectName("view_split_topbottom"); 0634 connect(a, &QAction::triggered, this, &KTechlab::slotViewSplitTopBottom); 0635 ac->addAction(a->objectName(), a); 0636 } 0637 { 0638 // KToggleAction * ta = new KToggleAction( i18n("Run Simulation"), "media-playback-start", Qt::Key_F10, 0, 0, ac, "simulation_run" ); 0639 KToggleAction *ta = new KToggleAction(QIcon::fromTheme("media-playback-start"), i18n("Run Simulation"), ac); 0640 ac->setDefaultShortcut(ta, Qt::Key_F10); 0641 ta->setObjectName("simulation_run"); 0642 ta->setChecked(true); 0643 connect(ta, &KToggleAction::toggled, Simulator::self(), &Simulator::slotSetSimulating); 0644 ta->setCheckedState(KGuiItem(i18n("Pause Simulation"), "media-playback-pause", nullptr)); 0645 ac->addAction(ta->objectName(), ta); 0646 } 0647 0648 // We can call slotCloseProject now that the actions have been created 0649 ProjectManager::self()->updateActions(); 0650 DocManager::self()->disableContextActions(); 0651 } 0652 0653 void KTechlab::setupExampleActions() 0654 { 0655 QStringList categories; 0656 categories << "555" 0657 << "basic" 0658 << "diodes" 0659 << "jfets" 0660 << "opamps" 0661 << "matrix_disp_driver" 0662 << "mosfets" 0663 << "transistors"; 0664 0665 // A name for the example circuit can be generated from the filename (and 0666 // will be done so if the filename is not in this list). But the name 0667 // generation is not that intelligent (e.g. and.circuit should be called 0668 // "AND", not "And" - poor capitalization. And it also allows translation of 0669 // names. 0670 QStringMap filesToNames; 0671 filesToNames["internals.circuit"] = i18n("Internals"); 0672 filesToNames["square-wave.circuit"] = i18n("Square Wave"); 0673 filesToNames["2-way-switch.circuit"] = i18n("2-Way Switch"); 0674 filesToNames["3-way-switch.circuit"] = i18n("3-Way Switch"); 0675 filesToNames["capacitor.circuit"] = i18n("Capacitor"); 0676 filesToNames["lrc.circuit"] = i18n("LRC"); 0677 filesToNames["resistors-parallel.circuit"] = i18n("Resistors in Parallel"); 0678 filesToNames["resistors-series.circuit"] = i18n("Resistors in Series"); 0679 filesToNames["voltage-divider.circuit"] = i18n("Voltage Divider"); 0680 filesToNames["full-wave-rectifier.circuit"] = i18n("Full Wave Rectifier"); 0681 filesToNames["half-wave-rectifier.circuit"] = i18n("Half Wave Rectifier"); 0682 filesToNames["inverter.circuit"] = i18n("Inverter"); 0683 filesToNames["and.circuit"] = i18n("AND"); 0684 filesToNames["nand.circuit"] = i18n("NAND"); 0685 filesToNames["nor.circuit"] = i18n("NOR"); 0686 filesToNames["or.circuit"] = i18n("OR"); 0687 filesToNames["decoupler.circuit"] = i18n("Decoupler"); 0688 filesToNames["inverting-amplifier.circuit"] = i18n("Inverting Amplifier"); 0689 filesToNames["noninverting-amplifier.circuit"] = i18n("Noninverting Amplifier"); 0690 filesToNames["instrumentation-amplifier.circuit"] = i18n("Instrumentation Amplifier"); 0691 filesToNames["astable-multivibrator.circuit"] = i18n("Astable Multivibrator"); 0692 filesToNames["inverter.circuit"] = i18n("Inverter"); 0693 filesToNames["scmitt-trigger.circuit"] = i18n("Schmitt Trigger"); 0694 filesToNames["switch.circuit"] = i18n("Switch"); 0695 filesToNames["matrix_display.circuit"] = i18n("Matrix Display Driver"); 0696 0697 int at = 0; 0698 0699 for (QString category : categories) { 0700 QDir dir(QStandardPaths::locate(QStandardPaths::AppDataLocation, "examples/" + category + "/", QStandardPaths::LocateDirectory)); 0701 0702 // K3PopupMenu * m = static_cast<K3PopupMenu*>(factory()->container( "examples_" + category, this )); 0703 QMenu *m = static_cast<QMenu *>(factory()->container("examples_" + category, this)); 0704 if (!m) { 0705 qCWarning(KTL_LOG) << "failed to cast to popup menu: " 0706 << "examples_" + category; 0707 continue; 0708 } 0709 connect(m, &QMenu::triggered, this, &KTechlab::openExample); 0710 0711 QStringList files = dir.entryList(); 0712 files.removeAll("."); 0713 files.removeAll(".."); 0714 0715 for (QString fileName : files) { 0716 QString name = filesToNames[fileName]; 0717 if (name.isEmpty()) { 0718 name = fileName; 0719 name.remove(".circuit"); 0720 name.replace("-", " "); 0721 name.replace("_", " "); 0722 0723 // Capitalize the start of each word 0724 bool prevWasSpace = true; 0725 for (int i = 0; i < name.length(); ++i) { 0726 if (prevWasSpace) 0727 name[i] = name[i].toUpper(); 0728 prevWasSpace = name[i].isSpace(); 0729 } 0730 } 0731 0732 // m->insertItem( name, at, at ); // 2018.12.02 0733 m->addAction(name)->setData(at); 0734 m_exampleFiles[at] = dir.path() + "/" + fileName; 0735 at++; 0736 } 0737 } 0738 } 0739 0740 void KTechlab::openExample(QAction *action) 0741 { 0742 int id = action->data().toInt(); 0743 DocManager::self()->openURL(QUrl::fromLocalFile(m_exampleFiles[id])); 0744 } 0745 0746 void KTechlab::slotViewContainerActivated(int /*index*/) 0747 { 0748 QWidget *viewContainer = m_pViewContainerTabWidget->currentWidget(); 0749 if (!viewContainer) { 0750 return; // null viewContainer could be selected, when all documents are closed 0751 } 0752 m_pFocusedContainer = dynamic_cast<ViewContainer *>(viewContainer); 0753 m_pFocusedContainer->setFocus(); 0754 } 0755 0756 void KTechlab::slotViewContainerDestroyed(QObject *object) 0757 { 0758 m_viewContainerList.removeAll(static_cast<ViewContainer *>(object)); 0759 m_viewContainerList.removeAll((ViewContainer *)nullptr); 0760 slotUpdateTabWidget(); 0761 } 0762 0763 QAction *KTechlab::actionByName(const QString &name) const 0764 { 0765 QAction *action = actionCollection()->action(name); 0766 if (!action) 0767 qCCritical(KTL_LOG) << "No such action: " << name; 0768 return action; 0769 } 0770 0771 void KTechlab::savePropertiesInConfig(KConfig *conf) 0772 { 0773 // Dumbass KMainWindow - can't handle my width/height correctly. Whoever thought of the "+1" hack anyway?! 0774 // conf->setGroup("UI"); 0775 KConfigGroup grUi = conf->group("UI"); 0776 grUi.writeEntry("Width", width()); 0777 grUi.writeEntry("Height", height()); 0778 // grUi.writeEntry( "WinState", KWin::windowInfo( winId(), NET::WMState ).state() ); 0779 grUi.writeEntry("WinState", (qulonglong)KWindowInfo(winId(), NET::WMState).state()); 0780 0781 #ifndef NO_GPSIM 0782 SymbolViewer::self()->saveProperties(conf); 0783 #endif 0784 0785 if (ProjectManager::self()->currentProject()) { 0786 // conf->setGroup("Project"); 0787 KConfigGroup grProject = conf->group("Project"); 0788 grProject.writePathEntry("Open", ProjectManager::self()->currentProject()->url().toDisplayString(QUrl::PreferLocalFile)); 0789 } else { 0790 conf->deleteGroup("Project"); 0791 } 0792 0793 // BEGIN Open Views State 0794 // Remvoe old entries describing the save state - we don't want a horrible mish-mash of saved states 0795 const QStringList groupList = conf->groupList(); 0796 const QStringList::const_iterator groupListEnd = groupList.end(); 0797 for (QStringList::const_iterator it = groupList.begin(); it != groupListEnd; ++it) { 0798 if ((*it).startsWith("ViewContainer")) 0799 conf->deleteGroup(*it); 0800 } 0801 0802 uint viewContainerId = 1; 0803 const ViewContainerList::iterator vcEnd = m_viewContainerList.end(); 0804 for (ViewContainerList::iterator it = m_viewContainerList.begin(); it != vcEnd; ++it) { 0805 if (!(*it) || !(*it)->canSaveUsefulStateInfo()) 0806 continue; 0807 0808 // To make sure the ViewContainers are restored in the right order, we must create them in alphabetical order, 0809 // as KConfig stores them as such... 0810 const QString id = QString::number(viewContainerId++).rightJustified(4, '0'); 0811 0812 // conf->setGroup( "ViewContainer " + id ); 0813 KConfigGroup grViewCont = conf->group("ViewContainer " + id); 0814 //(*it)->saveState(conf); 0815 (*it)->saveState(&grViewCont); 0816 } 0817 // END Open Views State 0818 0819 KConfigGroup grKateMdi = conf->group("KateMDI"); 0820 saveSession(&grKateMdi); 0821 // Piss off KMainWindow 0822 // conf->setGroup("KateMDI"); 0823 int scnum = QApplication::desktop()->screenNumber(parentWidget()); 0824 QRect desk = QApplication::desktop()->screenGeometry(scnum); 0825 grKateMdi.deleteEntry(QString::fromLatin1("Width %1").arg(desk.width())); 0826 grKateMdi.deleteEntry(QString::fromLatin1("Height %1").arg(desk.height())); 0827 0828 conf->sync(); 0829 } 0830 0831 void KTechlab::readPropertiesInConfig(KConfig *conf) 0832 { 0833 startRestore(conf, "KateMDI"); 0834 0835 m_recentFiles->loadEntries(conf->group("Recent Files")); 0836 m_recentProjects->loadEntries(conf->group("Recent Projects")); 0837 0838 // BEGIN Restore Open Views 0839 if (KTLConfig::restoreDocumentsOnStartup()) { 0840 // If we have a lot of views open from last time, then opening them will take a long time. 0841 // So we want to enter the qt event loop to finish drawing the window et al before adding the views. 0842 qApp->processEvents(); 0843 0844 const QStringList groupList = conf->groupList(); 0845 const QStringList::const_iterator groupListEnd = groupList.end(); 0846 for (QStringList::const_iterator it = groupList.begin(); it != groupListEnd; ++it) { 0847 if ((*it).startsWith("ViewContainer")) { 0848 ViewContainer *viewContainer = new ViewContainer(*it); 0849 0850 // conf->setGroup(*it); 0851 KConfigGroup grIt = conf->group(*it); 0852 viewContainer->restoreState(&grIt, *it); 0853 0854 addWindow(viewContainer); 0855 } 0856 } 0857 } 0858 // END Restore Open Views 0859 0860 // conf->setGroup("Project"); 0861 KConfigGroup grProject = conf->group("Project"); 0862 const QString openValue = grProject.readPathEntry("Open", QString()); 0863 if (!openValue.isEmpty()) { 0864 ProjectManager::self()->slotOpenProject(QUrl::fromUserInput(openValue)); 0865 } 0866 0867 #ifndef NO_GPSIM 0868 SymbolViewer::self()->readProperties(conf); 0869 #endif 0870 0871 finishRestore(); 0872 0873 // Dumbass KMainWindow - can't handle my width/height correctly. Whoever thought of the "+1" hack anyway?! 0874 // conf->setGroup("UI"); 0875 KConfigGroup grUi = conf->group("UI"); 0876 resize(grUi.readEntry("Width", 800), grUi.readEntry("Height", 500)); 0877 const quint32 winStateDef = quint32(NET::Max); 0878 const quint32 winState = grUi.readEntry("WinState", winStateDef /* NET::Max */); 0879 KWindowSystem::setState(winId(), NET::States(winState)); 0880 // grUi.readEntry( "WinState", (quint32) NET::Max ) ); 0881 } 0882 0883 void KTechlab::dragEnterEvent(QDragEnterEvent *event) 0884 { 0885 // accept uri drops only 0886 event->setAccepted(event->mimeData()->hasUrls()); 0887 } 0888 0889 void KTechlab::dropEvent(QDropEvent *event) 0890 { 0891 // this is a very simplistic implementation of a drop event. we 0892 // will only accept a dropped URL. the Qt dnd code can do *much* 0893 // much more, so please read the docs there 0894 const QList<QUrl> urls = event->mimeData()->urls(); 0895 0896 // see if we can decode a URI.. if not, just ignore it 0897 if (!urls.isEmpty()) { 0898 // okay, we have a URI.. process it 0899 const QUrl &url = urls.first(); 0900 0901 // load in the file 0902 load(url); 0903 } 0904 } 0905 0906 void KTechlab::slotOptionsShowStatusbar() 0907 { 0908 // this is all very cut and paste code for showing/hiding the 0909 // statusbar 0910 if (m_statusbarAction->isChecked()) 0911 statusBar()->show(); 0912 else 0913 statusBar()->hide(); 0914 } 0915 0916 void KTechlab::slotOptionsConfigureKeys() 0917 { 0918 // KKeyDialog::configureKeys(actionCollection(), "ktechlabui.rc"); 0919 KShortcutsDialog::configure(actionCollection(), KShortcutsEditor::LetterShortcutsAllowed, this, true); 0920 } 0921 0922 void KTechlab::slotOptionsConfigureToolbars() 0923 { 0924 KEditToolBar *dlg = new KEditToolBar(guiFactory()); 0925 0926 if (dlg->exec()) { 0927 createShellGUI(false); 0928 createShellGUI(true); 0929 } 0930 0931 delete dlg; 0932 } 0933 0934 void KTechlab::slotOptionsPreferences() 0935 { 0936 // An instance of your dialog could be already created and could be cached, 0937 // in which case you want to display the cached dialog instead of creating 0938 // another one 0939 if (KConfigDialog::showDialog("settings")) 0940 return; 0941 0942 // KConfigDialog didn't find an instance of this dialog, so lets create it: 0943 SettingsDlg *dialog = new SettingsDlg(this, "settings", KTLConfig::self()); 0944 0945 // User edited the configuration - update your local copies of the 0946 // configuration data 0947 connect(dialog, &SettingsDlg::settingsChanged, this, &KTechlab::slotUpdateConfiguration); 0948 dialog->show(); 0949 } 0950 0951 void KTechlab::slotUpdateConfiguration() 0952 { 0953 emit configurationChanged(); 0954 } 0955 0956 void KTechlab::slotChangeStatusbar(const QString &text) 0957 { 0958 // Avoid flicker by repeatedly displaying the same message, as QStatusBar does not check for this 0959 if (m_lastStatusBarMessage == text) 0960 return; 0961 0962 statusBar()->showMessage(text); 0963 m_lastStatusBarMessage = text; 0964 } 0965 0966 void KTechlab::slotTabContext(const QPoint &pos) 0967 { 0968 QTabBar *tabBar = tabWidget()->tabBar(); 0969 QWidget *widget = tabWidget()->widget(tabBar->tabAt(pos)); 0970 if (!widget) { 0971 return; 0972 } 0973 const QPoint globalPos = tabBar->mapToGlobal(pos); 0974 0975 // Shamelessly stolen from KDevelop... 0976 0977 QMenu *tabMenu = new QMenu; 0978 tabMenu->addSection((dynamic_cast<ViewContainer *>(widget))->windowTitle()); 0979 0980 // Find the document on whose tab the user clicked 0981 m_pContextMenuContainer = nullptr; 0982 0983 m_viewContainerList.removeAll((ViewContainer *)nullptr); 0984 0985 const ViewContainerList::iterator vcEnd = m_viewContainerList.end(); 0986 for (ViewContainerList::iterator it = m_viewContainerList.begin(); it != vcEnd; ++it) { 0987 ViewContainer *viewContainer = *it; 0988 if (viewContainer == widget) { 0989 m_pContextMenuContainer = viewContainer; 0990 0991 tabMenu->addAction(QIcon::fromTheme("tab-close"), i18n("Close"))->setData(0); 0992 0993 View *view = (viewContainer->viewCount() == 1) ? viewContainer->activeView() : nullptr; 0994 0995 if (view && view->document()->isModified()) 0996 tabMenu->addAction(QIcon::fromTheme("document-save"), i18n("Save"))->setData(1); 0997 0998 if (view && !view->document()->url().isEmpty()) 0999 tabMenu->addAction(QIcon::fromTheme("view-refresh"), i18n("Reload"))->setData(2); 1000 1001 if (m_viewContainerList.count() > 1) 1002 tabMenu->addAction(QIcon::fromTheme("tab-close-other"), i18n("Close All Others"))->setData(4); 1003 } 1004 } 1005 1006 connect(tabMenu, &QMenu::triggered, this, &KTechlab::slotTabContextActivated); 1007 1008 tabMenu->exec(globalPos); 1009 delete tabMenu; 1010 } 1011 1012 void KTechlab::slotTabContextActivated(QAction *action) 1013 { 1014 // Shamelessly stolen from KDevelop... 1015 1016 if (!m_pContextMenuContainer || !action || action->data().isNull()) 1017 return; 1018 1019 View *view = m_pContextMenuContainer->activeView(); 1020 if (!view) 1021 return; 1022 QPointer<Document> document = view->document(); 1023 1024 switch (action->data().toInt()) { 1025 case 0: { 1026 m_pContextMenuContainer->closeViewContainer(); 1027 break; 1028 } 1029 case 1: 1030 document->fileSave(); 1031 break; 1032 case 2: { 1033 QUrl url = document->url(); 1034 if (document->fileClose()) { 1035 delete document; 1036 DocManager::self()->openURL(url); 1037 } 1038 break; 1039 } 1040 case 4: { 1041 const ViewContainerList::iterator vcEnd = m_viewContainerList.end(); 1042 for (ViewContainerList::iterator it = m_viewContainerList.begin(); it != vcEnd; ++it) { 1043 ViewContainer *viewContainer = *it; 1044 if (viewContainer && viewContainer != m_pContextMenuContainer) { 1045 if (!viewContainer->closeViewContainer()) 1046 return; 1047 } 1048 } 1049 break; 1050 } 1051 default: 1052 break; 1053 } 1054 } 1055 1056 void KTechlab::slotFileNewAssembly() 1057 { 1058 TextDocument *document = DocManager::self()->createTextDocument(); 1059 if (document) 1060 document->slotInitLanguage(TextDocument::ct_asm); 1061 } 1062 void KTechlab::slotFileNewMicrobe() 1063 { 1064 TextDocument *document = DocManager::self()->createTextDocument(); 1065 if (document) 1066 document->slotInitLanguage(TextDocument::ct_microbe); 1067 } 1068 void KTechlab::slotFileNewC() 1069 { 1070 TextDocument *document = DocManager::self()->createTextDocument(); 1071 if (document) 1072 document->slotInitLanguage(TextDocument::ct_c); 1073 } 1074 void KTechlab::slotFileNewCircuit() 1075 { 1076 DocManager::self()->createCircuitDocument(); 1077 } 1078 void KTechlab::slotFileNewFlowCode() 1079 { 1080 slotFileNew(); 1081 } 1082 void KTechlab::slotFileNewMechanics() 1083 { 1084 DocManager::self()->createMechanicsDocument(); 1085 } 1086 1087 void KTechlab::slotFileNew() 1088 { 1089 NewFileDlg *newFileDlg = new NewFileDlg(this); 1090 1091 const int accepted = newFileDlg->exec(); 1092 1093 bool addToProject = newFileDlg->addToProject(); 1094 int finalType = newFileDlg->fileType(); 1095 QString microID = newFileDlg->microID(); 1096 int codeType = newFileDlg->codeType(); 1097 1098 delete newFileDlg; 1099 if (accepted != QDialog::Accepted) 1100 return; 1101 1102 Document *created = nullptr; 1103 1104 if (finalType == Document::dt_circuit) 1105 created = DocManager::self()->createCircuitDocument(); 1106 1107 else if (finalType == Document::dt_flowcode) { 1108 FlowCodeDocument *fcd = DocManager::self()->createFlowCodeDocument(); 1109 fcd->setPicType(microID); 1110 created = fcd; 1111 } 1112 1113 else if (finalType == Document::dt_mechanics) 1114 created = DocManager::self()->createMechanicsDocument(); 1115 1116 else { 1117 // Presumably a text document 1118 TextDocument *textDocument = DocManager::self()->createTextDocument(); 1119 1120 if (textDocument) 1121 textDocument->slotInitLanguage((TextDocument::CodeType)codeType); 1122 1123 created = textDocument; 1124 } 1125 1126 if (created && addToProject) 1127 created->setAddToProjectOnSave(true); 1128 } 1129 1130 void KTechlab::slotFileOpen() 1131 { 1132 // this slot is called whenever the File->Open menu is selected, 1133 // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar 1134 // button is clicked 1135 1136 // standard filedialog 1137 const QList<QUrl> urls = getFileURLs(); 1138 for (const QUrl &url : urls) 1139 load(url); 1140 } 1141 1142 void KTechlab::addRecentFile(const QUrl &url) 1143 { 1144 KSharedConfigPtr config = KSharedConfig::openConfig(); 1145 m_recentFiles->addUrl(url); 1146 m_recentFiles->saveEntries(config->group("Recent Files")); 1147 config->sync(); 1148 emit recentFileAdded(url); 1149 } 1150 1151 QList<QUrl> KTechlab::getFileURLs(bool allowMultiple) 1152 { 1153 QString filter; 1154 filter = QString( 1155 "*|%1 (*)\n" 1156 ";;*.asm *.src *.inc|%2 (*.asm, *.src, *.inc)\n" 1157 ";;*.hex|%3 (*.hex)\n" 1158 ";;*.circuit|%4 (*.circuit)\n" 1159 ";;*.flowcode|FlowCode (*.flowcode)\n" 1160 ";;*.basic *.microbe|Microbe (*.microbe, *.basic)" 1161 /*"*.mechanics|Mechanics (*.mechanics)\n"*/) 1162 .arg(i18n("All Files")) 1163 .arg(i18n("Assembly Code")) 1164 .arg(i18n("Intel Hex")) 1165 .arg(i18n("Circuit")); 1166 1167 if (allowMultiple) 1168 return QFileDialog::getOpenFileUrls(nullptr, i18n("Open Location"), QUrl(), filter); 1169 1170 else { 1171 QUrl ret = QFileDialog::getOpenFileUrl(nullptr, i18n("Open Location"), QUrl(), filter); 1172 return {ret}; 1173 } 1174 } 1175 1176 void KTechlab::slotDocModifiedChanged() 1177 { 1178 // BEGIN Set tab icons 1179 const ViewContainerList::iterator vcEnd = m_viewContainerList.end(); 1180 for (ViewContainerList::iterator it = m_viewContainerList.begin(); it != vcEnd; ++it) { 1181 ViewContainer *vc = *it; 1182 if (!vc || !vc->activeView() || !vc->activeView()->document()) 1183 continue; 1184 1185 QIcon icon; 1186 1187 if (vc->activeView()->document()->isModified()) { 1188 icon = QIcon::fromTheme("document-save"); 1189 } else { 1190 switch (vc->activeView()->document()->type()) { 1191 case Document::dt_circuit: 1192 icon = QIcon::fromTheme("application-x-circuit"); 1193 break; 1194 1195 case Document::dt_flowcode: 1196 icon = QIcon::fromTheme("application-x-flowcode"); 1197 break; 1198 1199 case Document::dt_mechanics: 1200 icon = QIcon::fromTheme("ktechlab_mechanics"); 1201 break; 1202 1203 case Document::dt_text: 1204 icon = QIcon::fromTheme("text-x-generic"); 1205 break; 1206 1207 case Document::dt_pinMapEditor: 1208 break; 1209 1210 case Document::dt_none: 1211 icon = QIcon::fromTheme("application-x-zerosize"); 1212 break; 1213 } 1214 } 1215 1216 tabWidget()->setTabIcon(tabWidget()->indexOf(vc), icon); 1217 } 1218 // END Set tab icons 1219 } 1220 1221 void KTechlab::requestUpdateCaptions() 1222 { 1223 m_pUpdateCaptionsTimer->setSingleShot(true); 1224 m_pUpdateCaptionsTimer->start(0 /*, true */); 1225 } 1226 1227 void KTechlab::slotUpdateCaptions() 1228 { 1229 // BEGIN Set KTechlab caption 1230 Document *document = DocManager::self()->getFocusedDocument(); 1231 QString newCaption; 1232 if (document) { 1233 QUrl url = document->url(); 1234 if (url.isEmpty()) 1235 newCaption = document->caption(); 1236 else { 1237 if (url.isLocalFile() && !url.hasFragment() && !url.hasQuery()) 1238 newCaption = url.toLocalFile(); 1239 else 1240 newCaption = url.toDisplayString(QUrl::PreferLocalFile); 1241 } 1242 } else 1243 newCaption = ""; 1244 1245 if (newCaption != windowTitle().remove(" - KTechlab")) { 1246 setWindowTitle(newCaption); 1247 } 1248 // END Set KTechlab caption 1249 1250 // BEGIN Set tab captions 1251 emit needUpdateCaptions(); 1252 1253 if (document && document->activeView() && document->activeView()->viewContainer()) { 1254 document->activeView()->viewContainer()->updateCaption(); 1255 } 1256 // END Set tab captions 1257 } 1258 1259 void KTechlab::slotDocUndoRedoChanged() 1260 { 1261 Document *document = DocManager::self()->getFocusedDocument(); 1262 if (!document) 1263 return; 1264 1265 action("edit_undo")->setEnabled(document->isUndoAvailable()); 1266 action("edit_redo")->setEnabled(document->isRedoAvailable()); 1267 } 1268 1269 void KTechlab::slotFileSave() 1270 { 1271 Document *document = DocManager::self()->getFocusedDocument(); 1272 if (document) 1273 document->fileSave(); 1274 } 1275 1276 void KTechlab::slotFileSaveAs() 1277 { 1278 Document *document = DocManager::self()->getFocusedDocument(); 1279 if (document) 1280 document->fileSaveAs(); 1281 } 1282 1283 void KTechlab::slotFilePrint() 1284 { 1285 Document *document = DocManager::self()->getFocusedDocument(); 1286 if (document) 1287 document->print(); 1288 } 1289 1290 bool KTechlab::queryClose() 1291 { 1292 KSharedConfigPtr cfgPtr = KSharedConfig::openConfig(); 1293 // saveProperties( KGlobal::config() ); 1294 savePropertiesInConfig(cfgPtr.data()); 1295 1296 if (DocManager::self()->closeAll() && ProjectManager::self()->slotCloseProject()) { 1297 // Make ourself "deleted" 1298 m_pSelf = nullptr; 1299 return true; 1300 } 1301 1302 return false; 1303 } 1304 1305 void KTechlab::slotFileQuit() 1306 { 1307 // close the first window, the list makes the next one the first again. 1308 // This ensures that queryClose() is called on each window to ask for closing 1309 // KMainWindow* w; 1310 if (!memberList().isEmpty()) { 1311 QList<KMainWindow *> mainWindowList = memberList(); 1312 // for( w=memberList->first(); w!=0; w=memberList->next() ) 1313 for (QList<KMainWindow *>::iterator itWnd = mainWindowList.begin(); itWnd != mainWindowList.end(); ++itWnd) { 1314 // only close the window if the closeEvent is accepted. If the user presses Cancel on the saveModified() dialog, 1315 // the window and the application stay open. 1316 // if( !w->close() ) break; 1317 if (!(*itWnd)->close()) 1318 break; 1319 } 1320 } 1321 1322 slotChangeStatusbar(i18n("Exiting...")); 1323 } 1324 1325 void KTechlab::slotEditUndo() 1326 { 1327 Document *document = DocManager::self()->getFocusedDocument(); 1328 if (document) 1329 document->undo(); 1330 } 1331 1332 void KTechlab::slotEditRedo() 1333 { 1334 Document *document = DocManager::self()->getFocusedDocument(); 1335 if (document) 1336 document->redo(); 1337 } 1338 1339 void KTechlab::slotEditCut() 1340 { 1341 Document *document = DocManager::self()->getFocusedDocument(); 1342 if (document) 1343 document->cut(); 1344 } 1345 1346 void KTechlab::slotEditCopy() 1347 { 1348 Document *document = DocManager::self()->getFocusedDocument(); 1349 if (document) 1350 document->copy(); 1351 } 1352 1353 void KTechlab::slotEditPaste() 1354 { 1355 Document *document = DocManager::self()->getFocusedDocument(); 1356 if (document) 1357 document->paste(); 1358 } 1359 1360 void KTechlab::slotViewContainerClose() 1361 { 1362 if (m_pFocusedContainer) 1363 m_pFocusedContainer->closeViewContainer(); 1364 } 1365 void KTechlab::slotViewClose() 1366 { 1367 View *view = DocManager::self()->getFocusedView(); 1368 if (view) 1369 view->closeView(); 1370 } 1371 void KTechlab::slotViewSplitLeftRight() 1372 { 1373 View *view = DocManager::self()->getFocusedView(); 1374 if (!view) 1375 return; 1376 ViewContainer *vc = view->viewContainer(); 1377 uint vaId = vc->createViewArea(view->viewAreaId(), ViewArea::Right, true); 1378 // view->document()->createView( vc, vaId ); 1379 (void)vaId; 1380 } 1381 void KTechlab::slotViewSplitTopBottom() 1382 { 1383 View *view = DocManager::self()->getFocusedView(); 1384 if (!view) 1385 return; 1386 ViewContainer *vc = view->viewContainer(); 1387 uint vaId = vc->createViewArea(view->viewAreaId(), ViewArea::Bottom, true); 1388 // view->document()->createView( vc, vaId ); 1389 (void)vaId; 1390 }