File indexing completed on 2024-04-28 04:37:32
0001 /* 0002 SPDX-FileCopyrightText: 2006-2007 Alexander Dymo <adymo@kdevelop.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "mainwindow.h" 0008 #include "mainwindow_p.h" 0009 0010 #include <QApplication> 0011 #include <QDesktopWidget> 0012 #include <QMenuBar> 0013 #include <QStatusBar> 0014 #include <QScreen> 0015 0016 #include <KConfigGroup> 0017 #include <KLocalizedString> 0018 #include <KSharedConfig> 0019 #include <KToolBar> 0020 0021 #include "area.h" 0022 #include "view.h" 0023 #include "controller.h" 0024 #include "container.h" 0025 #include "idealbuttonbarwidget.h" 0026 #include "idealcontroller.h" 0027 #include "holdupdates.h" 0028 #include <debug.h> 0029 0030 namespace Sublime { 0031 0032 MainWindow::MainWindow(Controller *controller, Qt::WindowFlags flags) 0033 : KParts::MainWindow(nullptr, flags) 0034 , d_ptr(new MainWindowPrivate(this, controller)) 0035 { 0036 connect(this, &MainWindow::destroyed, controller, QOverload<>::of(&Controller::areaReleased)); 0037 0038 loadGeometry(KSharedConfig::openConfig()->group("Main Window")); 0039 0040 // don't allow AllowTabbedDocks - that doesn't make sense for "ideal" UI 0041 setDockOptions(QMainWindow::AnimatedDocks); 0042 } 0043 0044 bool MainWindow::containsView(View* view) const 0045 { 0046 const auto areas = this->areas(); 0047 0048 return std::any_of(areas.begin(), areas.end(), [view](Area* area) { 0049 return area->views().contains(view); 0050 }); 0051 } 0052 0053 QList< Area* > MainWindow::areas() const 0054 { 0055 QList< Area* > areas = controller()->areas(const_cast<MainWindow*>(this)); 0056 if(areas.isEmpty()) 0057 areas = controller()->defaultAreas(); 0058 0059 return areas; 0060 } 0061 0062 MainWindow::~MainWindow() 0063 { 0064 qCDebug(SUBLIME) << "destroying mainwindow"; 0065 } 0066 0067 void MainWindow::reconstructViews(const QList<View*>& topViews) 0068 { 0069 Q_D(MainWindow); 0070 0071 d->reconstructViews(topViews); 0072 } 0073 0074 QList<View*> MainWindow::topViews() const 0075 { 0076 Q_D(const MainWindow); 0077 0078 QList<View*> topViews; 0079 const auto views = d->area->views(); 0080 for (View* view : views) { 0081 if(view->hasWidget()) 0082 { 0083 QWidget* widget = view->widget(); 0084 if(widget->parent() && widget->parent()->parent()) 0085 { 0086 auto* container = qobject_cast<Container*>(widget->parent()->parent()); 0087 if(container->currentWidget() == widget) 0088 topViews << view; 0089 } 0090 } 0091 } 0092 return topViews; 0093 } 0094 0095 QSet<Container*> MainWindow::containers() const 0096 { 0097 Q_D(const MainWindow); 0098 0099 return QSet<Container*>(d->viewContainers.cbegin(), d->viewContainers.cend()); 0100 } 0101 0102 void MainWindow::setArea(Area *area) 0103 { 0104 Q_D(MainWindow); 0105 0106 if (d->area) 0107 disconnect(d->area, nullptr, d, nullptr); 0108 0109 bool differentArea = (area != d->area); 0110 /* All views will be removed from dock area now. However, this does 0111 not mean those are removed from area, so prevent slotDockShown 0112 from recording those views as no longer shown in the area. */ 0113 d->ignoreDockShown = true; 0114 0115 if (d->autoAreaSettingsSave && differentArea) 0116 saveSettings(); 0117 0118 HoldUpdates hu(this); 0119 if (d->area) 0120 clearArea(); 0121 d->area = area; 0122 d->reconstruct(); 0123 0124 if(d->area->activeView()) 0125 activateView(d->area->activeView()); 0126 else 0127 d->activateFirstVisibleView(); 0128 0129 initializeStatusBar(); 0130 emit areaChanged(area); 0131 d->ignoreDockShown = false; 0132 0133 hu.stop(); 0134 0135 loadSettings(); 0136 connect(area, &Area::viewAdded, d, &MainWindowPrivate::viewAdded); 0137 connect(area, &Area::viewRemoved, d, &MainWindowPrivate::viewRemovedInternal); 0138 connect(area, &Area::requestToolViewRaise, d, &MainWindowPrivate::raiseToolView); 0139 connect(area, &Area::aboutToRemoveView, d, &MainWindowPrivate::aboutToRemoveView); 0140 connect(area, &Area::toolViewAdded, d, &MainWindowPrivate::toolViewAdded); 0141 connect(area, &Area::aboutToRemoveToolView, d, &MainWindowPrivate::aboutToRemoveToolView); 0142 connect(area, &Area::toolViewMoved, d, &MainWindowPrivate::toolViewMoved); 0143 } 0144 0145 void MainWindow::initializeStatusBar() 0146 { 0147 //nothing here, reimplement in the subclasses if you want to have status bar 0148 //inside the bottom tool view buttons row 0149 } 0150 0151 void MainWindow::clearArea() 0152 { 0153 Q_D(MainWindow); 0154 0155 emit areaCleared(d->area); 0156 d->clearArea(); 0157 } 0158 0159 QList<View*> MainWindow::toolDocks() const 0160 { 0161 Q_D(const MainWindow); 0162 0163 return d->docks; 0164 } 0165 0166 Area *Sublime::MainWindow::area() const 0167 { 0168 Q_D(const MainWindow); 0169 0170 return d->area; 0171 } 0172 0173 Controller *MainWindow::controller() const 0174 { 0175 Q_D(const MainWindow); 0176 0177 return d->controller; 0178 } 0179 0180 View *MainWindow::activeView() const 0181 { 0182 Q_D(const MainWindow); 0183 0184 return d->activeView; 0185 } 0186 0187 View *MainWindow::activeToolView() const 0188 { 0189 Q_D(const MainWindow); 0190 0191 return d->activeToolView; 0192 } 0193 0194 void MainWindow::activateView(Sublime::View* view, bool focus) 0195 { 0196 Q_D(MainWindow); 0197 0198 const auto containerIt = d->viewContainers.constFind(view); 0199 if (containerIt == d->viewContainers.constEnd()) 0200 return; 0201 0202 if (d->activeView == view) 0203 { 0204 if (focus && view && !view->widget()->hasFocus()) 0205 view->widget()->setFocus(); 0206 return; 0207 } 0208 0209 (*containerIt)->setCurrentWidget(view->widget()); 0210 0211 setActiveView(view, focus); 0212 d->area->setActiveView(view); 0213 } 0214 0215 void MainWindow::setActiveView(View *view, bool focus) 0216 { 0217 Q_D(MainWindow); 0218 0219 View* oldActiveView = d->activeView; 0220 0221 d->activeView = view; 0222 0223 if (focus && view && !view->widget()->hasFocus()) 0224 view->widget()->setFocus(); 0225 0226 if(d->activeView != oldActiveView) 0227 emit activeViewChanged(view); 0228 } 0229 0230 void Sublime::MainWindow::setActiveToolView(View *view) 0231 { 0232 Q_D(MainWindow); 0233 0234 d->activeToolView = view; 0235 emit activeToolViewChanged(view); 0236 } 0237 0238 void MainWindow::saveSettings() 0239 { 0240 Q_D(MainWindow); 0241 0242 d->disableConcentrationMode(); 0243 QString group = QStringLiteral("MainWindow"); 0244 if (area()) 0245 group += QLatin1Char('_') + area()->objectName(); 0246 KConfigGroup cg = KSharedConfig::openConfig()->group(group); 0247 // This will try to save also the window size and the enabled state of the statusbar. 0248 // But it's OK, since we won't use this information when loading. 0249 saveMainWindowSettings(cg); 0250 0251 //debugToolBar visibility is stored separately to allow a area dependent default value 0252 const auto toolBars = this->toolBars(); 0253 for (KToolBar* toolbar : toolBars) { 0254 if (toolbar->objectName() == QLatin1String("debugToolBar")) { 0255 cg.writeEntry("debugToolBarVisibility", toolbar->isVisibleTo(this)); 0256 } 0257 } 0258 0259 d->idealController->leftBarWidget->saveOrderSettings(cg); 0260 d->idealController->bottomBarWidget->saveOrderSettings(cg); 0261 d->idealController->rightBarWidget->saveOrderSettings(cg); 0262 0263 cg.sync(); 0264 } 0265 0266 void MainWindow::loadSettings() 0267 { 0268 Q_D(MainWindow); 0269 0270 HoldUpdates hu(this); 0271 0272 qCDebug(SUBLIME) << "loading settings for " << (area() ? area()->objectName() : QString()); 0273 QString group = QStringLiteral("MainWindow"); 0274 if (area()) 0275 group += QLatin1Char('_') + area()->objectName(); 0276 KConfigGroup cg = KSharedConfig::openConfig()->group(group); 0277 0278 // What follows is copy-paste from applyMainWindowSettings. Unfortunately, 0279 // we don't really want that one to try restoring window size, and we also 0280 // cannot stop it from doing that in any clean way. 0281 // We also do not want that one do it for the enabled state of the statusbar: 0282 // KMainWindow scans the widget tree for a QStatusBar-inheriting instance and 0283 // set enabled state by the config value stored by the key "StatusBar", 0284 // while the QStatusBar subclass used in sublime should always be enabled. 0285 auto* mb = findChild<QMenuBar *>(); 0286 if (mb) { 0287 QString entry = cg.readEntry ("MenuBar", "Enabled"); 0288 if ( entry == QLatin1String("Disabled") ) 0289 mb->hide(); 0290 else 0291 mb->show(); 0292 } 0293 0294 if ( !autoSaveSettings() || cg.name() == autoSaveGroup() ) { 0295 QString entry = cg.readEntry ("ToolBarsMovable", "Enabled"); 0296 if ( entry == QLatin1String("Disabled") ) 0297 KToolBar::setToolBarsLocked(true); 0298 else 0299 KToolBar::setToolBarsLocked(false); 0300 } 0301 0302 // Utilise the QMainWindow::restoreState() functionality 0303 // Note that we're fixing KMainWindow bug here -- the original 0304 // code has this fragment above restoring toolbar properties. 0305 // As result, each save/restore would move the toolbar a bit to 0306 // the left. 0307 if (cg.hasKey("State")) { 0308 QByteArray state; 0309 state = cg.readEntry("State", state); 0310 state = QByteArray::fromBase64(state); 0311 // One day will need to load the version number, but for now, assume 0 0312 restoreState(state); 0313 } else { 0314 // If there's no state we use a default size of 870x650 0315 // Resize only when showing "code" area. If we do that for other areas, 0316 // then we'll hit bug https://bugs.kde.org/show_bug.cgi?id=207990 0317 // TODO: adymo: this is more like a hack, we need a proper first-start initialization 0318 if (area() && area()->objectName() == QLatin1String("code")) 0319 resize(870,650); 0320 } 0321 0322 int n = 1; // Toolbar counter. toolbars are counted from 1, 0323 const auto toolBars = this->toolBars(); 0324 for (KToolBar* toolbar : toolBars) { 0325 QString group(QStringLiteral("Toolbar")); 0326 // Give a number to the toolbar, but prefer a name if there is one, 0327 // because there's no real guarantee on the ordering of toolbars 0328 group += (toolbar->objectName().isEmpty() ? QString::number(n) : QLatin1Char(' ')+toolbar->objectName()); 0329 0330 KConfigGroup toolbarGroup(&cg, group); 0331 toolbar->applySettings(toolbarGroup); 0332 0333 if (toolbar->objectName() == QLatin1String("debugToolBar")) { 0334 //debugToolBar visibility is stored separately to allow a area dependent default value 0335 bool visibility = cg.readEntry("debugToolBarVisibility", area()->objectName() == QLatin1String("debug")); 0336 toolbar->setVisible(visibility); 0337 } 0338 n++; 0339 } 0340 0341 const bool tabBarHidden = !Container::configTabBarVisible(); 0342 const bool closeButtonsOnTabs = Container::configCloseButtonsOnTabs(); 0343 for (Container *container : qAsConst(d->viewContainers)) { 0344 container->setTabBarHidden(tabBarHidden); 0345 container->setCloseButtonsOnTabs(closeButtonsOnTabs); 0346 } 0347 0348 hu.stop(); 0349 0350 d->idealController->leftBarWidget->loadOrderSettings(cg); 0351 d->idealController->bottomBarWidget->loadOrderSettings(cg); 0352 d->idealController->rightBarWidget->loadOrderSettings(cg); 0353 0354 emit settingsLoaded(); 0355 0356 d->disableConcentrationMode(); 0357 } 0358 0359 bool MainWindow::queryClose() 0360 { 0361 // saveSettings(); 0362 KConfigGroup config(KSharedConfig::openConfig(), "Main Window"); 0363 saveGeometry(config); 0364 config.sync(); 0365 0366 return KParts::MainWindow::queryClose(); 0367 } 0368 0369 void MainWindow::postMessage(Message* message) 0370 { 0371 Q_D(MainWindow); 0372 0373 d->postMessage(message); 0374 } 0375 0376 QString MainWindow::screenKey() const 0377 { 0378 const int scnum = QApplication::desktop()->screenNumber(parentWidget()); 0379 QList<QScreen *> screens = QApplication::screens(); 0380 QRect desk = screens[scnum]->geometry(); 0381 0382 // if the desktop is virtual then use virtual screen size 0383 if (QGuiApplication::primaryScreen()->virtualSiblings().size() > 1) 0384 desk = QGuiApplication::primaryScreen()->virtualGeometry(); 0385 0386 return QStringLiteral("Desktop %1 %2") 0387 .arg(desk.width()).arg(desk.height()); 0388 } 0389 0390 void MainWindow::saveGeometry(KConfigGroup &config) const 0391 { 0392 config.writeEntry(screenKey(), geometry()); 0393 0394 } 0395 void MainWindow::loadGeometry(const KConfigGroup &config) 0396 { 0397 // The below code, essentially, is copy-paste from 0398 // KMainWindow::restoreWindowSize. Right now, that code is buggy, 0399 // as per http://permalink.gmane.org/gmane.comp.kde.devel.core/52423 0400 // so we implement a less theoretically correct, but working, version 0401 // below 0402 QRect g = config.readEntry(screenKey(), QRect()); 0403 if (!g.isEmpty()) 0404 setGeometry(g); 0405 } 0406 0407 void MainWindow::enableAreaSettingsSave() 0408 { 0409 Q_D(MainWindow); 0410 0411 d->autoAreaSettingsSave = true; 0412 } 0413 0414 QWidget *MainWindow::statusBarLocation() const 0415 { 0416 Q_D(const MainWindow); 0417 0418 return d->idealController->statusBarLocation(); 0419 } 0420 0421 ViewBarContainer *MainWindow::viewBarContainer() const 0422 { 0423 Q_D(const MainWindow); 0424 0425 return d->viewBarContainer; 0426 } 0427 0428 void MainWindow::setTabBarLeftCornerWidget(QWidget* widget) 0429 { 0430 Q_D(MainWindow); 0431 0432 d->setTabBarLeftCornerWidget(widget); 0433 } 0434 0435 void MainWindow::tabDoubleClicked(View* view) 0436 { 0437 Q_UNUSED(view); 0438 0439 Q_D(MainWindow); 0440 0441 d->toggleDocksShown(); 0442 } 0443 0444 void MainWindow::tabContextMenuRequested(View* , QMenu* ) 0445 { 0446 // do nothing 0447 } 0448 0449 void MainWindow::tabToolTipRequested(View*, Container*, int) 0450 { 0451 // do nothing 0452 } 0453 0454 void MainWindow::newTabRequested() 0455 { 0456 } 0457 0458 void MainWindow::dockBarContextMenuRequested(Qt::DockWidgetArea , const QPoint& ) 0459 { 0460 // do nothing 0461 } 0462 0463 View* MainWindow::viewForPosition(const QPoint& globalPos) const 0464 { 0465 Q_D(const MainWindow); 0466 0467 for (Container* container : qAsConst(d->viewContainers)) { 0468 QRect globalGeom = QRect(container->mapToGlobal(QPoint(0,0)), container->mapToGlobal(QPoint(container->width(), container->height()))); 0469 if(globalGeom.contains(globalPos)) 0470 { 0471 return d->widgetToView[container->currentWidget()]; 0472 } 0473 } 0474 0475 return nullptr; 0476 } 0477 0478 void MainWindow::setBackgroundCentralWidget(QWidget* w) 0479 { 0480 Q_D(MainWindow); 0481 0482 d->setBackgroundCentralWidget(w); 0483 } 0484 0485 } 0486 0487 #include "moc_mainwindow.cpp"