File indexing completed on 2024-04-28 05:49:31
0001 /* 0002 SPDX-FileCopyrightText: 2005 Christoph Cullmann <cullmann@kde.org> 0003 SPDX-FileCopyrightText: 2002, 2003 Joseph Wenninger <jowenn@kde.org> 0004 0005 GUIClient partly based on ktoolbarhandler.cpp: SPDX-FileCopyrightText: 2002 Simon Hausmann <hausmann@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "katemdi.h" 0011 #include "kateapp.h" 0012 0013 #include <KAcceleratorManager> 0014 #include <KActionCollection> 0015 #include <KActionMenu> 0016 #include <KConfigGroup> 0017 #include <KLocalizedString> 0018 #include <KMessageBox> 0019 #include <KSharedConfig> 0020 #include <KToolBar> 0021 #include <KWindowConfig> 0022 #include <KXMLGUIFactory> 0023 0024 #include <QApplication> 0025 #include <QContextMenuEvent> 0026 #include <QDomDocument> 0027 #include <QDrag> 0028 #include <QHBoxLayout> 0029 #include <QLabel> 0030 #include <QMenu> 0031 #include <QMimeData> 0032 #include <QRubberBand> 0033 #include <QSizePolicy> 0034 #include <QStackedWidget> 0035 #include <QStyle> 0036 #include <QTimer> 0037 #include <QVBoxLayout> 0038 0039 namespace KateMDI 0040 { 0041 // BEGIN TOGGLETOOLVIEWACTION 0042 // 0043 ToggleToolViewAction::ToggleToolViewAction(const QString &text, ToolView *tv, QObject *parent) 0044 : KToggleAction(text, parent) 0045 , m_tv(tv) 0046 { 0047 connect(this, &ToggleToolViewAction::toggled, this, &ToggleToolViewAction::slotToggled); 0048 connect(m_tv, &ToolView::toolVisibleChanged, this, &ToggleToolViewAction::toolVisibleChanged); 0049 0050 setChecked(m_tv->toolVisible()); 0051 } 0052 0053 void ToggleToolViewAction::toolVisibleChanged(bool v) 0054 { 0055 if (isChecked() != v) { 0056 setChecked(v); 0057 } 0058 } 0059 0060 void ToggleToolViewAction::slotToggled(bool t) 0061 { 0062 if (m_tv->toolVisible() == t) { 0063 return; 0064 } 0065 0066 if (t) { 0067 m_tv->mainWindow()->showToolView(m_tv); 0068 m_tv->setFocus(); 0069 } else { 0070 m_tv->mainWindow()->hideToolView(m_tv); 0071 } 0072 } 0073 0074 // END TOGGLETOOLVIEWACTION 0075 0076 // BEGIN GUICLIENT 0077 0078 static const QString actionListName = QStringLiteral("kate_mdi_view_actions"); 0079 0080 GUIClient::GUIClient(MainWindow *mw) 0081 : QObject(mw) 0082 , KXMLGUIClient(mw) 0083 , m_mw(mw) 0084 { 0085 setComponentName(QStringLiteral("toolviewmanager"), i18n("Toolview Manager")); 0086 connect(m_mw->guiFactory(), &KXMLGUIFactory::clientAdded, this, &GUIClient::clientAdded); 0087 const QString guiDescription = QStringLiteral( 0088 "" 0089 "<!DOCTYPE gui><gui name=\"kate_mdi_view_actions\">" 0090 "<MenuBar>" 0091 " <Menu name=\"view\">" 0092 " <ActionList name=\"%1\" />" 0093 " </Menu>" 0094 "</MenuBar>" 0095 "</gui>"); 0096 0097 if (domDocument().documentElement().isNull()) { 0098 QString completeDescription = guiDescription.arg(actionListName); 0099 0100 setXML(completeDescription, false /*merge*/); 0101 } 0102 0103 m_sidebarButtonsMenu = new KActionMenu(i18n("Sidebar Buttons"), this); 0104 actionCollection()->addAction(QStringLiteral("kate_mdi_show_sidebar_buttons"), m_sidebarButtonsMenu); 0105 0106 m_focusToolviewMenu = new KActionMenu(i18n("Focus Toolview"), this); 0107 actionCollection()->addAction(QStringLiteral("kate_mdi_focus_toolview"), m_focusToolviewMenu); 0108 0109 m_toolMenu = new KActionMenu(i18n("Tool &Views"), this); 0110 actionCollection()->addAction(QStringLiteral("kate_mdi_toolview_menu"), m_toolMenu); 0111 m_showSidebarsAction = new KToggleAction(i18n("Show Side&bars"), this); 0112 actionCollection()->addAction(QStringLiteral("kate_mdi_sidebar_visibility"), m_showSidebarsAction); 0113 actionCollection()->setDefaultShortcut(m_showSidebarsAction, Qt::CTRL | Qt::ALT | Qt::SHIFT | Qt::Key_F); 0114 0115 m_showSidebarsAction->setChecked(m_mw->sidebarsVisible()); 0116 connect(m_showSidebarsAction, &KToggleAction::toggled, m_mw, &MainWindow::setSidebarsVisible); 0117 0118 m_hideToolViews = actionCollection()->addAction(QStringLiteral("kate_mdi_hide_toolviews"), m_mw, &MainWindow::hideToolViews); 0119 m_hideToolViews->setText(i18n("Hide All Tool Views")); 0120 0121 m_toolMenu->addAction(m_showSidebarsAction); 0122 m_toolMenu->addAction(m_hideToolViews); 0123 QAction *sep_act = new QAction(this); 0124 sep_act->setSeparator(true); 0125 m_toolMenu->addAction(sep_act); 0126 0127 // read shortcuts 0128 actionCollection()->setConfigGroup(QStringLiteral("Shortcuts")); 0129 actionCollection()->readSettings(); 0130 0131 actionCollection()->addAssociatedWidget(m_mw); 0132 const auto actions = actionCollection()->actions(); 0133 for (QAction *action : actions) { 0134 action->setShortcutContext(Qt::WidgetWithChildrenShortcut); 0135 } 0136 0137 // hide tool views menu for KWrite mode 0138 if (KateApp::isKWrite()) { 0139 m_sidebarButtonsMenu->setVisible(false); 0140 m_focusToolviewMenu->setVisible(false); 0141 m_toolMenu->setVisible(false); 0142 } 0143 } 0144 0145 void GUIClient::updateSidebarsVisibleAction() 0146 { 0147 m_showSidebarsAction->setChecked(m_mw->sidebarsVisible()); 0148 } 0149 0150 void GUIClient::registerToolView(ToolView *tv) 0151 { 0152 QString aname = QLatin1String("kate_mdi_toolview_") + tv->id; 0153 0154 // try to read the action shortcut 0155 0156 auto shortcutsForActionName = [](const QString &aname) { 0157 QList<QKeySequence> shortcuts; 0158 KSharedConfigPtr cfg = KSharedConfig::openConfig(); 0159 const QString shortcutString = cfg->group(QStringLiteral("Shortcuts")).readEntry(aname, QString()); 0160 const auto shortcutStrings = shortcutString.split(QLatin1Char(';')); 0161 for (const QString &shortcut : shortcutStrings) { 0162 shortcuts << QKeySequence::fromString(shortcut); 0163 } 0164 return shortcuts; 0165 }; 0166 0167 /** Show ToolView Action **/ 0168 KToggleAction *a = new ToggleToolViewAction(i18n("Show %1", tv->text), tv, this); 0169 actionCollection()->setDefaultShortcuts(a, shortcutsForActionName(aname)); 0170 actionCollection()->addAction(aname, a); 0171 0172 m_toolMenu->addAction(a); 0173 0174 auto &actionsForTool = m_toolToActions[tv]; 0175 actionsForTool.push_back(a); 0176 0177 /** Show Tab button in sidebar action **/ 0178 aname = QStringLiteral("kate_mdi_show_toolview_button_") + tv->id; 0179 a = new KToggleAction(i18n("Show %1 Button", tv->text), this); 0180 a->setChecked(true); 0181 actionCollection()->setDefaultShortcuts(a, shortcutsForActionName(aname)); 0182 actionCollection()->addAction(aname, a); 0183 connect(a, &KToggleAction::toggled, this, [toolview = QPointer<ToolView>(tv)](bool checked) { 0184 if (toolview) { 0185 const QSignalBlocker b(toolview); 0186 toolview->sidebar()->showToolviewTab(toolview, checked); 0187 } 0188 }); 0189 connect(tv, &ToolView::tabButtonVisibleChanged, a, &QAction::setChecked); 0190 0191 m_sidebarButtonsMenu->addAction(a); 0192 actionsForTool.push_back(a); 0193 0194 aname = QStringLiteral("kate_mdi_focus_toolview_") + tv->id; 0195 QAction *act = new QAction(i18n("Focus %1", tv->text), this); 0196 actionCollection()->setDefaultShortcuts(act, shortcutsForActionName(aname)); 0197 actionCollection()->addAction(aname, act); 0198 connect(act, &QAction::triggered, tv, [tv = QPointer(tv)] { 0199 if (tv && tv->mainWindow()) { 0200 if (!tv->isVisible()) { 0201 tv->mainWindow()->showToolView(tv); 0202 } 0203 tv->setFocus(); 0204 } 0205 }); 0206 m_focusToolviewMenu->addAction(act); 0207 actionsForTool.push_back(act); 0208 0209 updateActions(); 0210 } 0211 0212 void GUIClient::unregisterToolView(ToolView *tv) 0213 { 0214 auto &actionsForTool = m_toolToActions[tv]; 0215 if (actionsForTool.empty()) 0216 return; 0217 0218 for (auto *a : actionsForTool) { 0219 delete a; 0220 } 0221 m_toolToActions.erase(tv); 0222 0223 updateActions(); 0224 } 0225 0226 void GUIClient::clientAdded(KXMLGUIClient *client) 0227 { 0228 if (client == this) { 0229 updateActions(); 0230 } 0231 } 0232 0233 void GUIClient::updateActions() 0234 { 0235 if (!factory()) { 0236 return; 0237 } 0238 0239 unplugActionList(actionListName); 0240 0241 QList<QAction *> addList; 0242 addList.append(m_toolMenu); 0243 addList.append(m_sidebarButtonsMenu); 0244 addList.append(m_focusToolviewMenu); 0245 0246 plugActionList(actionListName, addList); 0247 } 0248 0249 // END GUICLIENT 0250 0251 // BEGIN TOOLVIEW 0252 0253 ToolView::ToolView(MainWindow *mainwin, Sidebar *sidebar, QWidget *parent, const QString &identifier) 0254 : QFrame(parent) 0255 , m_mainWin(mainwin) 0256 , m_sidebar(sidebar) 0257 , m_toolbar(nullptr) 0258 , id(identifier) 0259 , m_toolVisible(false) 0260 { 0261 // try to fix resize policy 0262 QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Preferred); 0263 policy.setRetainSizeWhenHidden(true); 0264 setSizePolicy(policy); 0265 0266 // per default vbox layout 0267 QVBoxLayout *layout = new QVBoxLayout(this); 0268 layout->setContentsMargins(0, 0, 0, 0); 0269 layout->setSpacing(0); 0270 setLayout(layout); 0271 0272 // toolbar to collect actions 0273 m_toolbar = new KToolBar(this); 0274 m_toolbar->setVisible(false); 0275 m_toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly); 0276 0277 // ensure reasonable icons sizes, like e.g. the quick-open and co. icons 0278 // the normal toolbar sizes are TOO large, e.g. for scaled stuff even more! 0279 const int iconSize = style()->pixelMetric(QStyle::PM_ButtonIconSize, nullptr, this); 0280 m_toolbar->setIconSize(QSize(iconSize, iconSize)); 0281 } 0282 0283 QSize ToolView::sizeHint() const 0284 { 0285 return size(); 0286 } 0287 0288 QSize ToolView::minimumSizeHint() const 0289 { 0290 return QSize(160, 160); 0291 } 0292 0293 bool ToolView::tabButtonVisible() const 0294 { 0295 return isTabButtonVisible; 0296 } 0297 0298 void ToolView::setTabButtonVisible(bool visible) 0299 { 0300 isTabButtonVisible = visible; 0301 } 0302 0303 ToolView::~ToolView() 0304 { 0305 m_mainWin->toolViewDeleted(this); 0306 } 0307 0308 void ToolView::setToolVisible(bool vis) 0309 { 0310 if (m_toolVisible == vis) { 0311 return; 0312 } 0313 0314 m_toolVisible = vis; 0315 Q_EMIT toolVisibleChanged(m_toolVisible); 0316 } 0317 0318 bool ToolView::toolVisible() const 0319 { 0320 return m_toolVisible; 0321 } 0322 0323 void ToolView::childEvent(QChildEvent *ev) 0324 { 0325 // set the widget to be focus proxy if possible 0326 if (ev->type() == QEvent::ChildAdded) { 0327 if (QWidget *widget = qobject_cast<QWidget *>(ev->child())) { 0328 setFocusProxy(widget); 0329 layout()->addWidget(widget); 0330 } 0331 } 0332 0333 QFrame::childEvent(ev); 0334 } 0335 0336 void ToolView::actionEvent(QActionEvent *event) 0337 { 0338 QFrame::actionEvent(event); 0339 if (event->type() == QEvent::ActionAdded) { 0340 m_toolbar->addAction(event->action()); 0341 } else if (event->type() == QEvent::ActionRemoved) { 0342 m_toolbar->removeAction(event->action()); 0343 } 0344 m_toolbar->setVisible(!m_toolbar->actions().isEmpty()); 0345 } 0346 0347 // END TOOLVIEW 0348 0349 // BEGIN SIDEBAR 0350 0351 MultiTabBar::MultiTabBar(KMultiTabBar::KMultiTabBarPosition pos, Sidebar *sb, int idx) 0352 : m_sb(sb) 0353 , m_stack(new QStackedWidget()) 0354 , m_multiTabBar(new KMultiTabBar(pos, this)) 0355 { 0356 setProperty("is-multi-tabbar", true); 0357 QVBoxLayout *layout = new QVBoxLayout(this); 0358 layout->setContentsMargins(0, 0, 0, 0); 0359 layout->setSpacing(0); 0360 layout->addWidget(m_multiTabBar); 0361 0362 m_sb->m_ownSplit->insertWidget(idx, m_stack); 0363 m_stack->hide(); 0364 } 0365 0366 MultiTabBar::~MultiTabBar() 0367 { 0368 // Don't forget to remove our stack from the splitter 0369 m_stack->deleteLater(); 0370 } 0371 0372 KMultiTabBarTab *MultiTabBar::addTab(int id, ToolView *tv) 0373 { 0374 m_stack->addWidget(tv); 0375 KMultiTabBarTab *newTab; 0376 0377 if (std::find(m_tabList.begin(), m_tabList.end(), id) != m_tabList.end()) { 0378 // We are in session restore 0379 newTab = m_multiTabBar->tab(id); 0380 newTab->setIcon(tv->icon); 0381 newTab->setText(tv->text); 0382 } else { 0383 m_tabList.push_back(id); 0384 m_multiTabBar->appendTab(tv->icon, id, tv->text); 0385 newTab = m_multiTabBar->tab(id); 0386 } 0387 0388 connect(newTab, &KMultiTabBarTab::clicked, this, &MultiTabBar::tabClicked); 0389 0390 m_sb->m_widgetToTabBar.emplace(tv, this); 0391 0392 return newTab; 0393 } 0394 0395 int MultiTabBar::addBlankTab() 0396 { 0397 int id = m_sb->nextId(); 0398 m_tabList.push_back(id); 0399 m_multiTabBar->appendTab(QIcon(), id, QStringLiteral("placeholder")); 0400 return id; 0401 } 0402 0403 void MultiTabBar::tabClicked(int id) 0404 { 0405 if (m_multiTabBar->isTabRaised(id) || m_sb->isCollapsed()) { 0406 showToolView(id); 0407 } else { 0408 hideToolView(id); 0409 } 0410 0411 m_sb->updateSidebar(); 0412 } 0413 0414 void MultiTabBar::removeBlankTab(int id) 0415 { 0416 m_tabList.erase(std::remove(m_tabList.begin(), m_tabList.end(), id), m_tabList.end()); 0417 m_multiTabBar->removeTab(id); 0418 if (tabCount() == 0) { 0419 m_activeTab = 0; 0420 Q_EMIT lastTabRemoved(this); 0421 } 0422 } 0423 0424 void MultiTabBar::removeTab(int id) 0425 { 0426 m_tabList.erase(std::remove(m_tabList.begin(), m_tabList.end(), id), m_tabList.end()); 0427 m_multiTabBar->removeTab(id); 0428 ToolView *tv = m_sb->m_idToWidget.at(id); 0429 m_sb->m_widgetToTabBar.erase(tv); 0430 0431 bool hideView = (m_stack->currentWidget() == tv); 0432 m_stack->removeWidget(tv); 0433 0434 if (tabCount() == 0) { 0435 m_activeTab = 0; // Without any tab left, there is no one active 0436 Q_EMIT lastTabRemoved(this); 0437 return; 0438 } 0439 0440 if (!hideView) { 0441 // Some other than the active is removed, no more to do 0442 return; 0443 } 0444 0445 m_activeTab = 0; // Ensure we are up to date, reporting nonsense is dangerous 0446 tv = static_cast<ToolView *>(m_stack->currentWidget()); 0447 if (tv) { 0448 hideToolView(m_sb->m_widgetToId.at(tv)); 0449 } 0450 } 0451 0452 void MultiTabBar::reorderTab(int id, KMultiTabBarTab *before) 0453 { 0454 // can't find source id? 0455 auto it = std::find(m_tabList.begin(), m_tabList.end(), id); 0456 if (it == m_tabList.end()) { 0457 return; 0458 } 0459 int idIdx = std::distance(m_tabList.begin(), it); 0460 it = before ? std::find(m_tabList.begin(), m_tabList.end(), before->id()) : m_tabList.end(); 0461 if (before && it == m_tabList.end()) { 0462 // can't find before id? 0463 return; 0464 } 0465 // before == null, idx will be the last idx 0466 int beforeIdx = it == m_tabList.end() ? m_tabList.size() - 1 : std::distance(m_tabList.begin(), it); 0467 if (idIdx == beforeIdx) { 0468 return; 0469 } 0470 0471 int start = std::min(idIdx, beforeIdx); 0472 0473 // copy because after removeTab `before` will be invalid 0474 const int beforeId = before ? before->id() : -1; 0475 0476 // Remove the actual tabs 0477 for (size_t i = start; i < m_tabList.size(); ++i) { 0478 auto oldTab = m_multiTabBar->tab(m_tabList[i]); 0479 oldTab->removeEventFilter(m_sb); 0480 m_multiTabBar->removeTab(m_tabList[i]); 0481 } 0482 0483 // reorder the tab list 0484 // erase old position 0485 m_tabList.erase(std::remove(m_tabList.begin(), m_tabList.end(), id), m_tabList.end()); 0486 // find new position and insert 0487 it = before ? std::find(m_tabList.begin(), m_tabList.end(), beforeId) : m_tabList.end(); 0488 m_tabList.insert(it, id); 0489 0490 // re-add tabs 0491 for (size_t i = start; i < m_tabList.size(); ++i) { 0492 auto tabId = m_tabList[i]; 0493 ToolView *tv = m_sb->m_idToWidget.at(tabId); 0494 m_multiTabBar->appendTab(tv->icon, tabId, tv->text); 0495 m_sb->appendStyledTab(tabId, this, tv); 0496 } 0497 } 0498 0499 void MultiTabBar::showToolView(int id) 0500 { 0501 setTabActive(id, true); 0502 expandToolView(); 0503 } 0504 0505 void MultiTabBar::hideToolView(int id) 0506 { 0507 setTabActive(id, false); 0508 collapseToolView(); 0509 } 0510 0511 void MultiTabBar::setTabActive(int id, bool state) 0512 { 0513 // Only change m_activeTab when state is true 0514 0515 if (m_activeTab == id) { 0516 // Well, normally should be state always==false, but who knows... 0517 m_multiTabBar->setTab(id, state); 0518 m_sb->m_idToWidget.at(id)->setToolVisible(state); 0519 m_activeTab = state ? id : 0; 0520 return; 0521 } 0522 0523 if (m_activeTab && state) { 0524 // Obviously the active tool is changed, disable the old one 0525 m_multiTabBar->setTab(m_activeTab, false); 0526 m_sb->m_idToWidget.at(m_activeTab)->setToolVisible(false); 0527 } 0528 0529 m_multiTabBar->setTab(id, state); 0530 m_sb->m_idToWidget.at(id)->setToolVisible(state); 0531 m_activeTab = state ? id : m_activeTab; 0532 } 0533 0534 bool MultiTabBar::isToolActive() const 0535 { 0536 return m_activeTab > 0; 0537 } 0538 0539 void MultiTabBar::collapseToolView() const 0540 { 0541 m_stack->hide(); 0542 0543 if (m_stack->count() < 1) { 0544 return; 0545 } 0546 0547 static_cast<ToolView *>(m_stack->currentWidget())->setToolVisible(false); 0548 } 0549 0550 bool MultiTabBar::expandToolView() const 0551 { 0552 if (!m_activeTab) { 0553 return false; 0554 } 0555 0556 if (m_stack->count() < 1) { 0557 return false; 0558 } 0559 0560 ToolView *tv = m_sb->m_idToWidget.at(m_activeTab); 0561 tv->setToolVisible(true); 0562 tv->setFocus(); // This is for some tools nice, for some other not 0563 m_stack->setCurrentWidget(tv); 0564 m_stack->show(); 0565 0566 return true; 0567 } 0568 0569 Sidebar::Sidebar(KMultiTabBar::KMultiTabBarPosition pos, QSplitter *sp, MainWindow *mainwin, QWidget *parent) 0570 : QSplitter(parent) 0571 , m_mainWin(mainwin) 0572 , m_tabBarPosition(pos) 0573 , m_splitter(sp) 0574 , m_ownSplit(new QSplitter(sp)) 0575 , m_ownSplitIndex(sp->indexOf(m_ownSplit)) 0576 , m_lastSize(200) // Default used when no session to restore is around 0577 , m_dropIndicator(new QRubberBand(QRubberBand::Rectangle, mainwin)) 0578 , m_internalDropIndicator(new QRubberBand(QRubberBand::Rectangle, mainwin)) 0579 { 0580 setChildrenCollapsible(false); 0581 setAcceptDrops(true); 0582 connect(this, &Sidebar::destroyed, m_dropIndicator, &QObject::deleteLater); 0583 0584 if (isVertical()) { 0585 m_ownSplit->setOrientation(Qt::Vertical); 0586 setOrientation(Qt::Vertical); 0587 setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); 0588 } else { 0589 m_ownSplit->setOrientation(Qt::Horizontal); 0590 setOrientation(Qt::Horizontal); 0591 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); 0592 } 0593 0594 m_ownSplit->setChildrenCollapsible(false); 0595 0596 // ensure proper sidebar state, see resizing issues in bug 460160 0597 m_ownSplit->hide(); 0598 0599 connect(this, &QSplitter::splitterMoved, this, &Sidebar::barSplitMoved); 0600 connect(m_ownSplit, &QSplitter::splitterMoved, this, &Sidebar::ownSplitMoved); 0601 connect(m_splitter, &QSplitter::splitterMoved, this, &Sidebar::handleCollapse); 0602 0603 insertTabBar(); 0604 0605 // handle config changes & apply initial config 0606 connect(KateApp::self(), &KateApp::configurationChanged, this, &Sidebar::readConfig); 0607 readConfig(); 0608 } 0609 0610 void Sidebar::readConfig() 0611 { 0612 bool needsUpdate = false; 0613 0614 KSharedConfig::Ptr config = KSharedConfig::openConfig(); 0615 KConfigGroup cgGeneral = KConfigGroup(config, QStringLiteral("General")); 0616 const bool syncWithTabs = cgGeneral.readEntry("Sync section size with tab positions", false); 0617 if (syncWithTabs != m_syncWithTabs) { 0618 m_syncWithTabs = syncWithTabs; 0619 needsUpdate = true; 0620 } 0621 // Ignore the option for the bottom bar! Due to it's special design would that never looks good 0622 if (position() == KMultiTabBar::Bottom) { 0623 m_syncWithTabs = false; 0624 needsUpdate = false; 0625 } 0626 if (m_syncWithTabs && needsUpdate) { 0627 // Give the user an immediate feedback that the option has an effect, works not perfect 0628 // when some section is not active, but may better that to do nothing 0629 QList<int> wsizes = m_ownSplit->sizes(); 0630 for (int i = 0; i < wsizes.count(); ++i) { 0631 if (wsizes.at(i) == 0) { 0632 wsizes[i] = tabBar(i)->sectionSize(); 0633 } 0634 } 0635 setSizes(wsizes); 0636 adjustSplitterSections(); 0637 needsUpdate = false; 0638 } 0639 0640 // shall we show text for the left and right bars? 0641 const bool showTextForLeftRight = cgGeneral.readEntry("Show text for left and right sidebar", false); 0642 if (showTextForLeftRight != m_showTextForLeftRight) { 0643 m_showTextForLeftRight = showTextForLeftRight; 0644 needsUpdate = true; 0645 } 0646 0647 int size = cgGeneral.readEntry("Icon size for left and right sidebar buttons", 32); 0648 if (size != m_leftRightSidebarIconSize) { 0649 m_leftRightSidebarIconSize = size; 0650 needsUpdate = true; 0651 } 0652 0653 if (!needsUpdate) { 0654 return; 0655 } 0656 0657 for (const auto &[id, wid] : m_idToWidget) { 0658 updateButtonStyle(kmTabBar(wid)->tab(id)); 0659 } 0660 } 0661 0662 void Sidebar::appendStyledTab(int id, MultiTabBar *bar, ToolView *widget) 0663 { 0664 auto newTab = bar->addTab(id, widget); 0665 0666 Q_ASSERT(newTab); 0667 newTab->installEventFilter(this); 0668 0669 // remember original text, we will need it again if we update the style in updateButtonStyle 0670 newTab->setProperty("kate_original_text", widget->text); 0671 0672 // fixup styling 0673 updateButtonStyle(newTab); 0674 0675 // tell that we have a new tab, useful for e.g. overlays 0676 // do it delayed so that if toolview was constructed before the container widget 0677 // and the container wants to react to this signal, it can do so. Otherwise, this 0678 // will fire before the container has connected to this signal 0679 QMetaObject::invokeMethod( 0680 m_mainWin, 0681 [w = m_mainWin, widget, newTab] { 0682 Q_EMIT w->tabForToolViewAdded(widget, newTab); 0683 }, 0684 Qt::QueuedConnection); 0685 } 0686 0687 void Sidebar::updateButtonStyle(KMultiTabBarTab *button) 0688 { 0689 const auto originalText = button->property("kate_original_text").toString(); 0690 if (!m_showTextForLeftRight && (position() == KMultiTabBar::Left || position() == KMultiTabBar::Right)) { 0691 const int iconSize = m_leftRightSidebarIconSize; 0692 button->setIconSize(QSize(iconSize, iconSize)); 0693 button->setText(QString()); 0694 button->setToolTip(originalText); 0695 } else { 0696 const int iconSize = style()->pixelMetric(QStyle::PM_ButtonIconSize, nullptr, this); 0697 button->setIconSize(QSize(iconSize, iconSize)); 0698 button->setText(originalText); 0699 button->setToolTip(QString()); 0700 } 0701 } 0702 0703 void Sidebar::setStyle(KMultiTabBar::KMultiTabBarStyle style) 0704 { 0705 m_tabBarStyle = style; 0706 0707 for (int i = 0; i < tabBarCount(); ++i) { 0708 tabBar(i)->tabBar()->setStyle(style); 0709 } 0710 } 0711 0712 QSize Sidebar::sizeHint() const 0713 { 0714 return minimumSizeHint(); 0715 } 0716 0717 QSize Sidebar::minimumSizeHint() const 0718 { 0719 return isVisible() ? QSplitter::minimumSizeHint() : QSize{0, 0}; 0720 } 0721 0722 MultiTabBar *Sidebar::insertTabBar(int idx /* = -1*/) 0723 { 0724 auto *newBar = new MultiTabBar(m_tabBarPosition, this, idx); 0725 newBar->installEventFilter(this); 0726 newBar->tabBar()->setStyle(tabStyle()); 0727 // Fetch user set tabBar splitting before the new bar is inserted 0728 auto sections = sizes(); 0729 insertWidget(idx, newBar); 0730 0731 // For a halfway nice new section distribution we need to help the splitter. 0732 // We only support with this math to insert below some section, 0733 // not above like at first place, but that's ok atm 0734 idx = idx < 0 ? sections.count() : idx; 0735 if (idx) { 0736 if (m_syncWithTabs) { 0737 // Share the space where the tab came from with the new bar 0738 sections[idx - 1] = sections.at(idx - 1) / 2; 0739 sections.insert(idx, sections.at(idx - 1)); 0740 setSizes(sections); 0741 } else { 0742 // We try here to keep the user manipulated tabBar splitting, but that works not perfect. 0743 // For proper calculations we need to ask for sizeHint, otherwise would tabs with text crunched, 0744 // but because the to be moved tab is still at the old place, we need to delay that. 0745 QTimer::singleShot(100, this, [this, idx, sections]() { 0746 if (tabBarCount() - 1 < idx) { 0747 // Config mismatch, the add bar was removed in the meanwhile 0748 return; 0749 } 0750 QList<int> sectionsC(sections); // To manipulate, we need a C-opy 0751 if (sectionsC.count() == 1) { 0752 int oldTabSize = isVertical() ? tabBar(idx - 1)->sizeHint().height() : tabBar(idx - 1)->sizeHint().width(); 0753 sectionsC[0] -= oldTabSize; 0754 sectionsC.insert(0, oldTabSize); 0755 } else { 0756 int newTabSize = isVertical() ? tabBar(idx)->sizeHint().height() : tabBar(idx)->sizeHint().width(); 0757 for (int i = 0; i < sections.size(); ++i) { 0758 sectionsC[i] -= newTabSize; 0759 } 0760 sectionsC.insert(idx, newTabSize); 0761 } 0762 setSizes(sectionsC); 0763 }); 0764 } 0765 } 0766 0767 connect(newBar, &MultiTabBar::lastTabRemoved, this, &Sidebar::tabBarIsEmpty); 0768 0769 return newBar; 0770 } 0771 0772 void Sidebar::updateLastSizeOnResize() 0773 { 0774 const int splitHandleIndex = qMin(m_splitter->indexOf(m_ownSplit) + 1, m_splitter->count() - 1); 0775 // this method requires that a splitter handle for resizing the sidebar exists 0776 Q_ASSERT(splitHandleIndex > 0); 0777 m_splitter->handle(splitHandleIndex)->installEventFilter(this); 0778 } 0779 0780 int Sidebar::nextId() 0781 { 0782 static int id = 0; 0783 return ++id; 0784 } 0785 0786 ToolView *Sidebar::addToolView(const QIcon &icon, const QString &text, const QString &identifier, ToolView *widget) 0787 { 0788 if (widget) { 0789 if (widget->sidebar() == this) { 0790 return widget; 0791 } 0792 0793 widget->sidebar()->removeToolView(widget); 0794 0795 } else { 0796 widget = new ToolView(m_mainWin, this, nullptr, identifier); 0797 widget->icon = icon; 0798 widget->text = text; 0799 } 0800 0801 widget->m_sidebar = this; 0802 0803 auto blankTabId = m_tvIdToTabId.find(identifier); 0804 if (blankTabId != m_tvIdToTabId.end()) { 0805 int newId = blankTabId->second; 0806 m_idToWidget.emplace(newId, widget); 0807 m_widgetToId.emplace(widget, newId); 0808 appendStyledTab(newId, tabBar(m_tvIdToTabBar.at(identifier)), widget); 0809 // Indicate the blank tab is re-used 0810 m_tvIdToTabId.erase(identifier); 0811 m_tvIdToTabBar.erase(identifier); 0812 } else { 0813 int newId = nextId(); 0814 m_idToWidget.emplace(newId, widget); 0815 m_widgetToId.emplace(widget, newId); 0816 appendStyledTab(newId, tabBar(0), widget); 0817 } 0818 0819 show(); 0820 0821 return widget; 0822 } 0823 0824 bool Sidebar::removeToolView(ToolView *widget) 0825 { 0826 if (m_widgetToId.find(widget) == m_widgetToId.end()) { 0827 return false; 0828 } 0829 0830 int id = m_widgetToId.at(widget); 0831 0832 auto tbar = m_widgetToTabBar.at(widget); 0833 tbar->removeTab(id); 0834 0835 m_idToWidget.erase(id); 0836 m_widgetToId.erase(widget); 0837 0838 updateSidebar(); 0839 0840 return true; 0841 } 0842 0843 bool Sidebar::showToolView(ToolView *widget) 0844 { 0845 if (m_widgetToId.find(widget) == m_widgetToId.end()) { 0846 return false; 0847 } 0848 0849 tabBar(widget)->showToolView(m_widgetToId.at(widget)); 0850 updateSidebar(); 0851 0852 return true; 0853 } 0854 0855 bool Sidebar::hideToolView(ToolView *widget) 0856 { 0857 if (m_widgetToId.find(widget) == m_widgetToId.end()) { 0858 return false; 0859 } 0860 0861 updateLastSize(); 0862 tabBar(widget)->hideToolView(m_widgetToId.at(widget)); 0863 updateSidebar(); 0864 0865 return true; 0866 } 0867 0868 void Sidebar::showToolviewTab(ToolView *widget, bool show) 0869 { 0870 auto it = m_widgetToId.find(widget); 0871 if (it == m_widgetToId.end()) { 0872 qWarning() << Q_FUNC_INFO << "Unexpected no id for widget " << widget; 0873 return; 0874 } 0875 auto *tab = kmTabBar(widget)->tab(it->second); 0876 if (widget->tabButtonVisible() == show) { 0877 return; 0878 } else { 0879 widget->setTabButtonVisible(show); 0880 tab->setVisible(show); 0881 Q_EMIT widget->tabButtonVisibleChanged(show); 0882 } 0883 } 0884 0885 bool Sidebar::isCollapsed() 0886 { 0887 return m_splitter->sizes().at(m_ownSplitIndex) == 0; 0888 } 0889 0890 void Sidebar::handleCollapse(int pos, int index) 0891 { 0892 Q_UNUSED(pos); 0893 0894 // Verify that we are handling the correct/matching sidebar 0895 // 0 | 1 | 2 <- m_ownSplitIndex (can be 0 or 2) 0896 // 1 2 <- index (of splitters, represented by |) 0897 const bool myInterest = ((m_ownSplitIndex == 0) && (1 == index)) || (m_ownSplitIndex == index); 0898 if (!myInterest) { 0899 return; 0900 } 0901 0902 if (isCollapsed() && !m_isPreviouslyCollapsed) { 0903 if (!m_resizePlaceholder) { 0904 m_resizePlaceholder = new QLabel(); 0905 m_ownSplit->addWidget(m_resizePlaceholder); 0906 m_resizePlaceholder->show(); 0907 m_resizePlaceholder->setMinimumSize(QSize(160, 160)); // Same minimum size set in ToolView::minimumSizeHint 0908 } 0909 collapseSidebar(); 0910 } else if (!isCollapsed() && m_isPreviouslyCollapsed) { 0911 updateSidebar(); 0912 } 0913 } 0914 0915 void Sidebar::ownSplitMoved(int pos, int index) 0916 { 0917 QList<int> wsizes = m_ownSplit->sizes(); 0918 for (int i = 0; i < tabBarCount(); ++i) { 0919 if (tabBar(i)->isToolActive()) { 0920 tabBar(i)->setSectionSize(wsizes.at(i)); 0921 } 0922 } 0923 0924 if (m_syncWithTabs) { 0925 moveSplitter(pos, index); 0926 } 0927 } 0928 0929 void Sidebar::barSplitMoved(int pos, int index) 0930 { 0931 Q_UNUSED(pos); 0932 Q_UNUSED(index); 0933 0934 if (m_syncWithTabs) { 0935 adjustSplitterSections(); 0936 } 0937 } 0938 0939 bool Sidebar::tabBarIsEmpty(MultiTabBar *bar) 0940 { 0941 // Don't remove the last bar! 0942 if (!bar || bar->tabCount() > 0 || tabBarCount() == 1) { 0943 return false; 0944 } 0945 0946 delete bar; 0947 0948 QTimer::singleShot(0, this, [this]() { 0949 // We need to delay the update or m_ownSplit report wrong size count 0950 updateSidebar(); 0951 }); 0952 0953 return true; 0954 } 0955 0956 void Sidebar::collapseSidebar() 0957 { 0958 if (m_isPreviouslyCollapsed) { 0959 return; 0960 } 0961 0962 updateLastSize(); 0963 0964 for (int i = 0; i < tabBarCount(); ++i) { 0965 tabBar(i)->collapseToolView(); 0966 } 0967 0968 m_isPreviouslyCollapsed = true; 0969 0970 if (!m_resizePlaceholder) { 0971 // Hiding m_ownSplit will cause that no resize handle is offered and 0972 // as side effect the sidebar collapse 0973 m_ownSplit->hide(); 0974 } else { 0975 // We need to force collapse the sidebar by set a zero size 0976 QList<int> wsizes = m_splitter->sizes(); 0977 wsizes[m_ownSplitIndex] = 0; 0978 m_splitter->setSizes(wsizes); 0979 } 0980 0981 // Now that tools are hidden, ensure the doc got the focus 0982 m_mainWin->triggerFocusForCentralWidget(); 0983 } 0984 0985 bool Sidebar::adjustSplitterSections() 0986 { 0987 // Here we catch two birds with one stone 0988 // - Report some caller if any tool is in use or not 0989 // - Adjust the m_ownSplit sizes to fit more sensible the active tools 0990 // To do so we run the loop in reverse order for a better result 0991 bool anyVis = false; 0992 QList<int> wsizes = sizes(); 0993 int sizeCollector = 0; 0994 int lastExpandedId = -1; 0995 for (int i = tabBarCount() - 1; i > -1; --i) { 0996 sizeCollector += wsizes.at(i); 0997 if (tabBar(i)->expandToolView()) { 0998 anyVis = true; 0999 wsizes[i] = sizeCollector; 1000 sizeCollector = 0; 1001 lastExpandedId = i; 1002 } else { 1003 wsizes[i] = 0; 1004 } 1005 } 1006 1007 if (!anyVis) { 1008 // No need to go on 1009 return false; 1010 } 1011 1012 if (!m_syncWithTabs) { 1013 return true; 1014 } 1015 1016 if (sizeCollector && lastExpandedId > -1) { 1017 wsizes[lastExpandedId] += sizeCollector; 1018 } 1019 1020 m_ownSplit->setSizes(wsizes); 1021 1022 return true; 1023 } 1024 1025 void Sidebar::updateSidebar() 1026 { 1027 if (!adjustSplitterSections()) { 1028 // Nothing is shown, don't expand to a blank area 1029 collapseSidebar(); 1030 return; 1031 } 1032 1033 if (m_resizePlaceholder) { 1034 delete m_resizePlaceholder; 1035 } 1036 1037 m_isPreviouslyCollapsed = false; 1038 1039 if (isCollapsed()) { 1040 QList<int> wsizes = m_splitter->sizes(); 1041 wsizes[m_ownSplitIndex] = m_lastSize; 1042 m_splitter->setSizes(wsizes); 1043 } 1044 1045 if (!m_syncWithTabs) { 1046 QList<int> wsizes = m_ownSplit->sizes(); 1047 for (int i = 0; i < tabBarCount(); ++i) { 1048 wsizes[i] = tabBar(i)->isToolActive() ? tabBar(i)->sectionSize() : 0; 1049 } 1050 m_ownSplit->setSizes(wsizes); 1051 } 1052 1053 // Ensure we are visible 1054 m_ownSplit->show(); 1055 } 1056 1057 bool Sidebar::eventFilter(QObject *obj, QEvent *ev) 1058 { 1059 if (ev->type() == QEvent::ContextMenu) { 1060 QContextMenuEvent *e = static_cast<QContextMenuEvent *>(ev); 1061 KMultiTabBarTab *bt = qobject_cast<KMultiTabBarTab *>(obj); 1062 if (bt) { 1063 // qCDebug(LOG_KATE) << "Request for popup"; 1064 1065 m_popupButton = bt->id(); 1066 1067 ToolView *w = m_idToWidget[m_popupButton]; 1068 1069 if (w) { 1070 QMenu menu(this); 1071 1072 menu.addSection(w->icon, w->text); 1073 1074 if (!w->plugin.isNull()) { 1075 if (w->plugin.data()->configPages() > 0) { 1076 menu.addAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Configure..."))->setData(ConfigureAction); 1077 } 1078 } 1079 1080 menu.addAction(i18n("Hide Button"))->setData(HideButtonAction); 1081 1082 menu.addSection(QIcon::fromTheme(QStringLiteral("move")), i18n("Move To")); 1083 1084 int tabBarId = indexOf(m_widgetToTabBar.at(w)); 1085 1086 if (tabBar(tabBarId)->tabCount() > 1) { 1087 menu.addAction(QIcon::fromTheme(QStringLiteral("list-add")), i18n("Own Section"))->setData(ToOwnSectAction); 1088 } 1089 1090 if (tabBarCount() > 1) { 1091 if (tabBarId < 1) { 1092 if (isVertical()) { 1093 menu.addAction(QIcon::fromTheme(QStringLiteral("go-down")), i18n("One Down"))->setData(DownRightAction); 1094 } else { 1095 menu.addAction(QIcon::fromTheme(QStringLiteral("go-next")), i18n("One Right"))->setData(DownRightAction); 1096 } 1097 } else { 1098 if (isVertical()) { 1099 menu.addAction(QIcon::fromTheme(QStringLiteral("go-up")), i18n("One Up"))->setData(UpLeftAction); 1100 if (tabBarId < tabBarCount() - 1) { 1101 menu.addAction(QIcon::fromTheme(QStringLiteral("go-down")), i18n("One Down"))->setData(DownRightAction); 1102 } 1103 } else { 1104 menu.addAction(QIcon::fromTheme(QStringLiteral("go-previous")), i18n("One Left"))->setData(UpLeftAction); 1105 if (tabBarId < tabBarCount() - 1) { 1106 menu.addAction(QIcon::fromTheme(QStringLiteral("go-next")), i18n("One Right"))->setData(DownRightAction); 1107 } 1108 } 1109 } 1110 } 1111 1112 if (position() != 0) { 1113 menu.addAction(QIcon::fromTheme(QStringLiteral("go-previous")), i18n("Left Sidebar"))->setData(0); 1114 } 1115 1116 if (position() != 1) { 1117 menu.addAction(QIcon::fromTheme(QStringLiteral("go-next")), i18n("Right Sidebar"))->setData(1); 1118 } 1119 1120 if (position() != 2) { 1121 menu.addAction(QIcon::fromTheme(QStringLiteral("go-up")), i18n("Top Sidebar"))->setData(2); 1122 } 1123 1124 if (position() != 3) { 1125 menu.addAction(QIcon::fromTheme(QStringLiteral("go-down")), i18n("Bottom Sidebar"))->setData(3); 1126 } 1127 1128 connect(&menu, &QMenu::triggered, this, &Sidebar::buttonPopupActivate); 1129 1130 menu.exec(e->globalPos()); 1131 1132 return true; 1133 } 1134 } 1135 } else if (ev->type() == QEvent::MouseButtonRelease) { 1136 // The sidebar's splitter handle handle was released, so we update the sidebar's size. See Sidebar::updateLastSizeOnResize 1137 QMouseEvent *e = static_cast<QMouseEvent *>(ev); 1138 if (e->button() == Qt::LeftButton) { 1139 updateLastSize(); 1140 } 1141 } else if (ev->type() == QEvent::MouseButtonPress) { 1142 QMouseEvent *e = static_cast<QMouseEvent *>(ev); 1143 if (qobject_cast<MultiTabBar *>(obj)) { 1144 // The non-tab area of the sidebar is clicked (well, pressed) => toggle collapse/expand 1145 if (e->button() == Qt::LeftButton) { 1146 if (obj->property("is-multi-tabbar").toBool()) { 1147 if (isCollapsed()) { 1148 updateSidebar(); 1149 } else { 1150 collapseSidebar(); 1151 } 1152 return true; 1153 } 1154 } 1155 } else if (qobject_cast<KMultiTabBarTab *>(obj) && e->button() == Qt::LeftButton) { 1156 dragStartPos = e->pos(); 1157 } 1158 } else if (!dragStartPos.isNull() && ev->type() == QEvent::MouseMove) { 1159 QMouseEvent *e = static_cast<QMouseEvent *>(ev); 1160 auto tab = qobject_cast<KMultiTabBarTab *>(obj); 1161 if (tab && (e->pos() - dragStartPos).manhattanLength() >= QApplication::startDragDistance()) { 1162 // start drag 1163 QPixmap pixmap = tab->grab(); 1164 QDrag *drag = new QDrag(this); 1165 auto md = new QMimeData(); 1166 ToolView *toolView = m_idToWidget[tab->id()]; 1167 Q_ASSERT(toolView); 1168 md->setProperty("toolviewToMove", QVariant::fromValue(toolView)); 1169 drag->setMimeData(md); 1170 drag->setPixmap(pixmap); 1171 drag->setHotSpot(dragStartPos); 1172 dragStartPos = {}; 1173 connect(drag, &QObject::destroyed, this, &Sidebar::dragEnded); 1174 1175 Q_EMIT dragStarted(); 1176 1177 drag->exec(Qt::MoveAction); 1178 return true; 1179 } 1180 } 1181 1182 return QSplitter::eventFilter(obj, ev); 1183 } 1184 1185 void Sidebar::dragEnterEvent(QDragEnterEvent *e) 1186 { 1187 if (e->proposedAction() != Qt::MoveAction) { 1188 return; 1189 } 1190 1191 if (!e->mimeData() || !e->mimeData()->property("toolviewToMove").value<ToolView *>()) { 1192 return; 1193 } 1194 1195 if (e->source() == this) { 1196 if (toolviewCount() == 1) { 1197 // only 1 toolview? Nothing to reorder then 1198 return; 1199 } 1200 m_internalDropIndicator->raise(); 1201 if (m_internalDropIndicator->geometry() != geometry()) { 1202 m_internalDropIndicator->setGeometry(geometry()); 1203 } 1204 1205 if (isVertical()) { 1206 m_internalDropIndicator->setFixedHeight(4); 1207 } else { 1208 m_internalDropIndicator->setFixedWidth(4); 1209 } 1210 1211 auto mimeData = e->mimeData(); 1212 ToolView *toolview = mimeData->property("toolviewToMove").value<ToolView *>(); 1213 QWidget *tab = tabButtonForToolview(toolview); 1214 if (!tab || !toolview) { 1215 return; 1216 } 1217 1218 const QPoint tabPos = tab->pos(); 1219 auto globalPos = mapToGlobal(tabPos); 1220 auto pos = m_mainWin->mapFromGlobal(globalPos); 1221 m_internalDropIndicator->move(pos); 1222 m_internalDropIndicator->show(); 1223 } else { // Show Drop Indicator 1224 m_dropIndicator->raise(); 1225 if (m_dropIndicator->geometry() != geometry()) { 1226 m_dropIndicator->setGeometry(geometry()); 1227 } 1228 auto globalPos = mapToGlobal(pos()); 1229 auto indicatorPos = m_dropIndicator->mapFromGlobal(globalPos); 1230 if (indicatorPos != m_dropIndicator->pos()) { 1231 m_dropIndicator->move(indicatorPos); 1232 } 1233 1234 m_dropIndicator->show(); 1235 } 1236 e->acceptProposedAction(); 1237 } 1238 1239 void Sidebar::dropEvent(QDropEvent *e) 1240 { 1241 auto mimeData = e->mimeData(); 1242 m_dropIndicator->hide(); 1243 m_internalDropIndicator->hide(); 1244 1245 if (!mimeData) { 1246 return; 1247 } 1248 ToolView *toolview = mimeData->property("toolviewToMove").value<ToolView *>(); 1249 if (!toolview) { 1250 return; 1251 } 1252 1253 if (e->source() == this) { 1254 // Re-ordering tabs 1255 auto sourceTab = qobject_cast<KMultiTabBarTab *>(tabButtonForToolview(toolview)); 1256 if (!sourceTab) { 1257 return; 1258 } 1259 // destTab might be null, which means we will just append to the end 1260 auto destTab = qobject_cast<KMultiTabBarTab *>(childAt(e->position().toPoint())); 1261 auto tabbar = m_widgetToTabBar[toolview]; 1262 tabbar->reorderTab(sourceTab->id(), destTab); 1263 } else { 1264 m_mainWin->moveToolView(toolview, position(), /*isDND=*/true); 1265 m_mainWin->showToolView(toolview); 1266 } 1267 1268 e->accept(); 1269 } 1270 1271 void Sidebar::dragMoveEvent(QDragMoveEvent *e) 1272 { 1273 if (e->source() != this || toolviewCount() == 1) { 1274 // We only handle drag move if we are moving on source sidebar 1275 // and if there is only 1 toolview, there is nothing to reorder 1276 return; 1277 } 1278 1279 auto *tab = qobject_cast<KMultiTabBarTab *>(childAt(e->position().toPoint())); 1280 if (tab) { 1281 // moving over a tab? show the indicator at tab start 1282 const QPoint tabPos = tab->pos(); 1283 auto globalPos = mapToGlobal(tabPos); 1284 auto pos = m_mainWin->mapFromGlobal(globalPos); 1285 m_internalDropIndicator->move(pos); 1286 } else { 1287 // Otherwise show at the end of tab list 1288 auto mimeData = e->mimeData(); 1289 ToolView *toolview = mimeData->property("toolviewToMove").value<ToolView *>(); 1290 if (!toolview) { 1291 return; 1292 } 1293 auto tabbar = m_widgetToTabBar[toolview]; 1294 auto lastTabId = tabbar->tabList().back(); 1295 auto tab = tabbar->tabBar()->tab(lastTabId); 1296 1297 QPoint tabPos = tab->pos(); 1298 if (isVertical()) { 1299 tabPos.setY(tabPos.y() + tab->height()); 1300 } else { 1301 tabPos.setX(tabPos.x() + tab->width()); 1302 } 1303 auto globalPos = mapToGlobal(tabPos); 1304 auto pos = m_mainWin->mapFromGlobal(globalPos); 1305 m_internalDropIndicator->move(pos); 1306 } 1307 } 1308 1309 void Sidebar::dragLeaveEvent(QDragLeaveEvent *) 1310 { 1311 m_internalDropIndicator->hide(); 1312 m_dropIndicator->hide(); 1313 } 1314 1315 void Sidebar::setVisible(bool visible) 1316 { 1317 // visible==true means show-request 1318 if (visible && (m_idToWidget.empty() || !m_mainWin->sidebarsVisible())) { 1319 return; 1320 } 1321 1322 QSplitter::setVisible(visible); 1323 } 1324 1325 void Sidebar::buttonPopupActivate(QAction *a) 1326 { 1327 const int id = a->data().toInt(); 1328 ToolView *w = m_idToWidget[m_popupButton]; 1329 1330 if (!w) { 1331 return; 1332 } 1333 1334 // move to other Sidebar ids 1335 if (id < 4) { 1336 // move + show ;) 1337 m_mainWin->moveToolView(w, static_cast<KMultiTabBar::KMultiTabBarPosition>(id)); 1338 m_mainWin->showToolView(w); 1339 } 1340 1341 if (id == ConfigureAction) { 1342 if (!w->plugin.isNull()) { 1343 if (w->plugin.data()->configPages() > 0) { 1344 Q_EMIT sigShowPluginConfigPage(w->plugin.data(), 0); 1345 } 1346 } 1347 } 1348 1349 if (id == HideButtonAction) { 1350 showToolviewTab(w, false); 1351 } 1352 1353 if (id == ToOwnSectAction) { 1354 auto newBar = insertTabBar(indexOf(m_widgetToTabBar.at(w)) + 1); 1355 tabBar(w)->removeTab(m_widgetToId.at(w)); 1356 appendStyledTab(m_widgetToId.at(w), newBar, w); 1357 showToolView(w); 1358 } 1359 if (id == UpLeftAction) { 1360 auto newBar = tabBar(indexOf(tabBar(w)) - 1); 1361 tabBar(w)->removeTab(m_widgetToId.at(w)); 1362 appendStyledTab(m_widgetToId.at(w), newBar, w); 1363 } 1364 if (id == DownRightAction) { 1365 auto newBar = tabBar(indexOf(tabBar(w)) + 1); 1366 tabBar(w)->removeTab(m_widgetToId.at(w)); 1367 appendStyledTab(m_widgetToId.at(w), newBar, w); 1368 } 1369 } 1370 1371 void Sidebar::updateLastSize() 1372 { 1373 if (isCollapsed()) { 1374 // We are too late, don't update to stupid value 1375 return; 1376 } 1377 1378 QList<int> s = m_splitter->sizes(); 1379 1380 // Ensure last size is always sensible 1381 m_lastSize = qMax(s[m_ownSplitIndex], 160); 1382 } 1383 1384 void Sidebar::startRestoreSession(KConfigGroup &config) 1385 { 1386 // ensure we only run once and we don't start a saveSession in addition 1387 if (m_sessionRestoreRunning) { 1388 return; 1389 } 1390 m_sessionRestoreRunning = true; 1391 1392 // Using splitter data avoid to store tabBarCount explicit ;-) 1393 QList<int> s = config.readEntry(QStringLiteral("Kate-MDI-Sidebar-%1-Splitter").arg(position()), QList<int>()); 1394 // Notice the start value of 1, only add extra tab bars 1395 for (int i = 1; i < s.size(); ++i) { 1396 insertTabBar(); 1397 } 1398 // Create for each tool we expect, in the correct order, a tab in advance, a blank one 1399 for (int i = 0; i < s.size(); ++i) { 1400 QStringList tvList = config.readEntry(QStringLiteral("Kate-MDI-Sidebar-%1-Bar-%2-TvList").arg(position()).arg(i), QStringList()); 1401 for (int j = 0; j < tvList.size(); ++j) { 1402 // Don't add in case of a config mismatch blank tabs for some stuff twice 1403 auto search = m_tvIdToTabId.find(tvList.at(j)); 1404 if (search == m_tvIdToTabId.end()) { 1405 int id = tabBar(i)->addBlankTab(); 1406 m_tvIdToTabId.emplace(tvList.at(j), id); 1407 m_tvIdToTabBar.emplace(tvList.at(j), i); 1408 } 1409 } 1410 } 1411 } 1412 1413 void Sidebar::restoreSession(KConfigGroup &config) 1414 { 1415 // Only continue when restore was started properly 1416 if (!m_sessionRestoreRunning) { 1417 return; 1418 } 1419 1420 // show only correct toolviews ;) 1421 for (const auto &[id, tv] : m_idToWidget) { 1422 tabBar(tv)->setTabActive(id, config.readEntry(QStringLiteral("Kate-MDI-ToolView-%1-Visible").arg(tv->id), false)); 1423 showToolviewTab(tv, config.readEntry(QStringLiteral("Kate-MDI-ToolView-%1-Show-Button-In-Sidebar").arg(tv->id), true)); 1424 } 1425 1426 // In case of some config mismatch, we should remove left over blank tabs 1427 for (const auto &[tv, id] : m_tvIdToTabId) { 1428 tabBar(m_tvIdToTabBar.at(tv))->removeBlankTab(id); 1429 } 1430 m_tvIdToTabId.clear(); 1431 m_tvIdToTabBar.clear(); 1432 1433 // In case of some config mismatch, we may have some ugly empty bars 1434 for (int i = 0; i < tabBarCount(); ++i) { 1435 // Don't panic! Function take care not to remove non empty bar 1436 if (tabBarIsEmpty(tabBar(i))) { 1437 // Now that the bar is gone, we need to adjust our index or we would skip some bar 1438 --i; 1439 } 1440 } 1441 1442 QList<int> sectSizes = config.readEntry(QStringLiteral("Kate-MDI-Sidebar-%1-SectSizes").arg(position()), QList<int>()); 1443 for (int i = 0; i < sectSizes.count(); ++i) { 1444 if (tabBarCount() - 1 < i) { 1445 // Config mismatch! 1446 break; 1447 } 1448 tabBar(i)->setSectionSize(sectSizes.at(i)); 1449 } 1450 1451 // Collapse now, and before! we restore m_lastSize, will hide (all) m_stack(s) so that 1452 // expanding will work fine... 1453 collapseSidebar(); 1454 m_lastSize = config.readEntry(QStringLiteral("Kate-MDI-Sidebar-%1-LastSize").arg(position()), 160); 1455 // Since we delay in insertTabBar(..) to adjust the sizes, we need it here too or the now set data will overwritten 1456 auto sz = config.readEntry(QStringLiteral("Kate-MDI-Sidebar-%1-Splitter").arg(position()), QList<int>()); 1457 QTimer::singleShot(100, this, [this, sz]() { 1458 setSizes(sz); 1459 1460 // ensure focus is not stolen 1461 m_mainWin->triggerFocusForCentralWidget(); 1462 }); 1463 // ...now we are ready to get the final splitter sizes by MainWindow::finishRestore 1464 updateSidebar(); 1465 1466 // be done, e.g. saveSession is now allowed again 1467 m_sessionRestoreRunning = false; 1468 } 1469 1470 void Sidebar::saveSession(KConfigGroup &config) 1471 { 1472 // Don't try to save a session while we are still in "session restore mode" BUG:459108 1473 if (m_sessionRestoreRunning) { 1474 return; 1475 } 1476 1477 config.writeEntry(QStringLiteral("Kate-MDI-Sidebar-%1-Splitter").arg(position()), sizes()); 1478 config.writeEntry(QStringLiteral("Kate-MDI-Sidebar-%1-LastSize").arg(position()), m_lastSize); 1479 1480 // store the data about all toolviews in this sidebar ;) 1481 for (const auto &[id, tv] : m_idToWidget) { 1482 config.writeEntry(QStringLiteral("Kate-MDI-ToolView-%1-Position").arg(tv->id), int(tv->sidebar()->position())); 1483 config.writeEntry(QStringLiteral("Kate-MDI-ToolView-%1-Visible").arg(tv->id), tv->toolVisible()); 1484 config.writeEntry(QStringLiteral("Kate-MDI-ToolView-%1-Show-Button-In-Sidebar").arg(tv->id), tv->tabButtonVisible()); 1485 } 1486 1487 QList<int> sectSizes; 1488 for (int i = 0; i < tabBarCount(); ++i) { 1489 sectSizes << tabBar(i)->sectionSize(); 1490 1491 QStringList tvList; 1492 for (int j : tabBar(i)->tabList()) { 1493 tvList << m_idToWidget.at(j)->id; 1494 } 1495 config.writeEntry(QStringLiteral("Kate-MDI-Sidebar-%1-Bar-%2-TvList").arg(position()).arg(i), tvList); 1496 } 1497 1498 config.writeEntry(QStringLiteral("Kate-MDI-Sidebar-%1-SectSizes").arg(position()), sectSizes); 1499 } 1500 1501 // END SIDEBAR 1502 1503 // BEGIN MAIN WINDOW 1504 1505 MainWindow::MainWindow(QWidget *parent) 1506 : KParts::MainWindow(parent, Qt::Window) 1507 , m_guiClient(new GUIClient(this)) 1508 { 1509 // central frame for all stuff 1510 QFrame *hb = new QFrame(this); 1511 setCentralWidget(hb); 1512 1513 // top level vbox for all stuff + bottom bar 1514 QVBoxLayout *toplevelVBox = new QVBoxLayout(hb); 1515 toplevelVBox->setContentsMargins(0, 0, 0, 0); 1516 toplevelVBox->setSpacing(0); 1517 1518 // hbox for all splitters and other side bars 1519 QHBoxLayout *hlayout = new QHBoxLayout; 1520 hlayout->setContentsMargins(0, 0, 0, 0); 1521 hlayout->setSpacing(0); 1522 toplevelVBox->addLayout(hlayout); 1523 1524 m_hSplitter = new QSplitter(Qt::Horizontal, hb); 1525 m_sidebars[KMultiTabBar::Left] = std::make_unique<Sidebar>(KMultiTabBar::Left, m_hSplitter, this, hb); 1526 hlayout->addWidget(m_sidebars[KMultiTabBar::Left].get()); 1527 hlayout->addWidget(m_hSplitter); 1528 1529 QFrame *vb = new QFrame(m_hSplitter); 1530 QVBoxLayout *vlayout = new QVBoxLayout(vb); 1531 vlayout->setContentsMargins(0, 0, 0, 0); 1532 vlayout->setSpacing(0); 1533 1534 m_hSplitter->setCollapsible(m_hSplitter->indexOf(vb), false); 1535 m_hSplitter->setStretchFactor(m_hSplitter->indexOf(vb), 1); 1536 1537 m_vSplitter = new QSplitter(Qt::Vertical, vb); 1538 m_sidebars[KMultiTabBar::Top] = std::make_unique<Sidebar>(KMultiTabBar::Top, m_vSplitter, this, vb); 1539 vlayout->addWidget(m_sidebars[KMultiTabBar::Top].get()); 1540 vlayout->addWidget(m_vSplitter); 1541 1542 m_centralWidget = new QWidget(m_vSplitter); 1543 m_centralWidget->setLayout(new QVBoxLayout); 1544 m_centralWidget->layout()->setSpacing(0); 1545 m_centralWidget->layout()->setContentsMargins(0, 0, 0, 0); 1546 1547 m_vSplitter->setCollapsible(m_vSplitter->indexOf(m_centralWidget), false); 1548 m_vSplitter->setStretchFactor(m_vSplitter->indexOf(m_centralWidget), 1); 1549 1550 m_sidebars[KMultiTabBar::Right] = std::make_unique<Sidebar>(KMultiTabBar::Right, m_hSplitter, this, hb); 1551 hlayout->addWidget(m_sidebars[KMultiTabBar::Right].get()); 1552 1553 auto separator = new QFrame(this); 1554 separator->setFrameShape(QFrame::HLine); 1555 separator->setFixedHeight(1); 1556 toplevelVBox->addWidget(separator); 1557 1558 // bottom side bar spans full windows, include status bar, too 1559 m_sidebars[KMultiTabBar::Bottom] = std::make_unique<Sidebar>(KMultiTabBar::Bottom, m_vSplitter, this, vb); 1560 m_bottomSidebarLayout = new QHBoxLayout; 1561 m_bottomSidebarLayout->addWidget(m_sidebars[KMultiTabBar::Bottom].get()); 1562 m_statusBarStackedWidget = new QStackedWidget(this); 1563 m_statusBarStackedWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); 1564 // button that shows git branch 1565 // m_branchLabel = new CurrentGitBranchButton(this); 1566 // m_bottomSidebarLayout->addWidget(m_branchLabel); 1567 // widget that hold statusbar of active kte-view 1568 m_bottomSidebarLayout->addWidget(m_statusBarStackedWidget); 1569 m_bottomSidebarLayout->setStretch(0, 100); 1570 toplevelVBox->addLayout(m_bottomSidebarLayout); 1571 1572 // ensure proper toolview style 1573 setToolViewStyle(KMultiTabBar::KDEV3ICON); 1574 1575 for (const auto &sidebar : m_sidebars) { 1576 connect(sidebar.get(), &Sidebar::sigShowPluginConfigPage, this, &MainWindow::sigShowPluginConfigPage); 1577 1578 // Drag/Drop 1579 connect(sidebar.get(), &Sidebar::dragStarted, this, [this]() { 1580 for (const auto &sb : m_sidebars) { 1581 m_dragState.m_wasVisible[(int)sb->position()] = sb->isVisible(); 1582 if (!sb->isVisible()) { 1583 sb->setMinimumSize({50, 50}); 1584 sb->QSplitter::setVisible(true); 1585 } 1586 } 1587 }); 1588 connect(sidebar.get(), &Sidebar::dragEnded, this, [this]() { 1589 for (const auto &sb : m_sidebars) { 1590 bool wasVisible = m_dragState.m_wasVisible[(int)sb->position()]; 1591 if (!wasVisible) { 1592 sb->setMinimumSize({0, 0}); 1593 sb->QSplitter::setVisible(false); 1594 } 1595 } 1596 }); 1597 } 1598 } 1599 1600 MainWindow::~MainWindow() 1601 { 1602 // kill all toolviews, they will deregister themself 1603 while (!m_toolviews.empty()) { 1604 delete m_toolviews.begin()->second; 1605 } 1606 1607 // seems like we really should delete this by hand ;) 1608 delete m_centralWidget; 1609 } 1610 1611 QWidget *MainWindow::centralWidget() const 1612 { 1613 return m_centralWidget; 1614 } 1615 1616 void MainWindow::insertWidgetBeforeStatusbar(QWidget *widget) 1617 { 1618 Q_ASSERT(m_bottomSidebarLayout); 1619 const auto idxOfStatusbar = m_bottomSidebarLayout->indexOf(m_statusBarStackedWidget); 1620 Q_ASSERT(idxOfStatusbar != -1); 1621 m_bottomSidebarLayout->insertWidget(idxOfStatusbar, widget); 1622 } 1623 1624 ToolView *MainWindow::createToolView(KTextEditor::Plugin *plugin, 1625 const QString &identifier, 1626 KMultiTabBar::KMultiTabBarPosition pos, 1627 const QIcon &icon, 1628 const QString &text) 1629 { 1630 // clashing names are not allowed 1631 if (toolView(identifier)) { 1632 return nullptr; 1633 } 1634 1635 // try the restore config to figure out real pos 1636 if (m_restoreConfig && m_restoreConfig->hasGroup(m_restoreGroup)) { 1637 KConfigGroup cg(m_restoreConfig, m_restoreGroup); 1638 pos = static_cast<KMultiTabBar::KMultiTabBarPosition>(cg.readEntry(QStringLiteral("Kate-MDI-ToolView-%1-Position").arg(identifier), int(pos))); 1639 } 1640 1641 ToolView *v = m_sidebars[pos]->addToolView(icon, text, identifier, nullptr); 1642 v->plugin = plugin; 1643 1644 m_toolviews.emplace(identifier, v); 1645 1646 // register for menu stuff 1647 m_guiClient->registerToolView(v); 1648 1649 return v; 1650 } 1651 1652 ToolView *MainWindow::toolView(const QString &identifier) const 1653 { 1654 auto it = m_toolviews.find(identifier); 1655 if (it != m_toolviews.end()) { 1656 return it->second; 1657 } 1658 return nullptr; 1659 } 1660 1661 void MainWindow::toolViewDeleted(ToolView *widget) 1662 { 1663 if (!widget) { 1664 return; 1665 } 1666 1667 if (widget->mainWindow() != this) { 1668 return; 1669 } 1670 1671 // unregister from menu stuff 1672 m_guiClient->unregisterToolView(widget); 1673 1674 widget->sidebar()->removeToolView(widget); 1675 1676 m_toolviews.erase(widget->id); 1677 } 1678 1679 void MainWindow::setSidebarsVisibleInternal(bool visible, bool hideFullySilent) 1680 { 1681 bool old_visible = m_sidebarsVisible; 1682 m_sidebarsVisible = visible; 1683 1684 for (auto &sidebar : m_sidebars) { 1685 sidebar->setVisible(visible); 1686 1687 // fully hide the stuff, see bug 464320 1688 if (hideFullySilent) { 1689 sidebar->collapseSidebar(); 1690 } 1691 } 1692 1693 m_guiClient->updateSidebarsVisibleAction(); 1694 1695 // show information message box, if the users hides the sidebars 1696 if (!hideFullySilent && old_visible && (!m_sidebarsVisible)) { 1697 KMessageBox::information(this, 1698 i18n("<qt>You are about to hide the sidebars. With " 1699 "hidden sidebars it is not possible to directly " 1700 "access the tool views with the mouse anymore, " 1701 "so if you need to access the sidebars again " 1702 "invoke <b>View > Tool Views > Show Sidebars</b> " 1703 "in the menu. It is still possible to show/hide " 1704 "the tool views with the assigned shortcuts.</qt>"), 1705 QString(), 1706 QStringLiteral("Kate hide sidebars notification message")); 1707 } 1708 } 1709 1710 bool MainWindow::sidebarsVisible() const 1711 { 1712 return m_sidebarsVisible; 1713 } 1714 1715 void MainWindow::setToolViewStyle(KMultiTabBar::KMultiTabBarStyle style) 1716 { 1717 for (auto &sidebar : m_sidebars) { 1718 sidebar->setStyle(style); 1719 } 1720 } 1721 1722 KMultiTabBar::KMultiTabBarStyle MainWindow::toolViewStyle() const 1723 { 1724 // all sidebars have the same style, so just take Top 1725 return m_sidebars[KMultiTabBar::Top]->tabStyle(); 1726 } 1727 1728 bool MainWindow::moveToolView(ToolView *widget, KMultiTabBar::KMultiTabBarPosition pos, bool isDND) 1729 { 1730 if (!widget || widget->mainWindow() != this) { 1731 return false; 1732 } 1733 1734 // try the restore config to figure out real pos 1735 if (m_restoreConfig && m_restoreConfig->hasGroup(m_restoreGroup)) { 1736 KConfigGroup cg(m_restoreConfig, m_restoreGroup); 1737 pos = static_cast<KMultiTabBar::KMultiTabBarPosition>(cg.readEntry(QStringLiteral("Kate-MDI-ToolView-%1-Position").arg(widget->id), int(pos))); 1738 } 1739 1740 if (isDND) { 1741 // Ensure that after dropping, sidebar becomes visiblee 1742 // Sidebar might have been hidden because it was empty i.e., 1743 // had no toolviews 1744 m_dragState.m_wasVisible[pos] = true; 1745 1746 // If source sidebar contains only 1 toolview, then hide it 1747 // because after the drop it will have nothing. 1748 auto source = widget->sidebar(); 1749 if (source->toolviewCount() == 1) { 1750 m_dragState.m_wasVisible[source->position()] = false; 1751 } 1752 } 1753 1754 m_sidebars[pos]->addToolView(widget->icon, widget->text, widget->id, widget); 1755 1756 if (isDND) { 1757 // reduce min size so that sidebar can adjust size properly 1758 m_sidebars[pos]->setMinimumSize({0, 0}); 1759 } 1760 1761 return true; 1762 } 1763 1764 bool MainWindow::showToolView(ToolView *widget) 1765 { 1766 if (!widget || widget->mainWindow() != this) { 1767 return false; 1768 } 1769 1770 // skip this if happens during restoring, or we will just see flicker 1771 if (m_restoreConfig && m_restoreConfig->hasGroup(m_restoreGroup)) { 1772 return true; 1773 } 1774 1775 return widget->sidebar()->showToolView(widget); 1776 } 1777 1778 bool MainWindow::hideToolView(ToolView *widget) 1779 { 1780 if (!widget || widget->mainWindow() != this) { 1781 return false; 1782 } 1783 1784 // skip this if happens during restoring, or we will just see flicker 1785 if (m_restoreConfig && m_restoreConfig->hasGroup(m_restoreGroup)) { 1786 return true; 1787 } 1788 1789 const bool ret = widget->sidebar()->hideToolView(widget); 1790 triggerFocusForCentralWidget(); 1791 return ret; 1792 } 1793 1794 void MainWindow::hideToolViews() 1795 { 1796 for (const auto &tv : m_toolviews) { 1797 tv.second->sidebar()->hideToolView(tv.second); 1798 } 1799 triggerFocusForCentralWidget(); 1800 } 1801 1802 void MainWindow::startRestore(KConfigBase *config, const QString &group) 1803 { 1804 // first save this stuff 1805 m_restoreConfig = config; 1806 m_restoreGroup = group; 1807 1808 if (!m_restoreConfig || !m_restoreConfig->hasGroup(m_restoreGroup)) { 1809 m_restoreConfig = nullptr; 1810 m_restoreGroup.clear(); 1811 return; 1812 } 1813 1814 // apply size once, to get sizes ready ;) 1815 KConfigGroup cg(m_restoreConfig, m_restoreGroup); 1816 KWindowConfig::restoreWindowSize(windowHandle(), cg); 1817 1818 // KWrite uses no sidebars, avoid all work beside windows sizes restoring above 1819 if (KateApp::isKWrite()) { 1820 m_restoreConfig = nullptr; 1821 m_restoreGroup.clear(); 1822 return; 1823 } 1824 1825 // restore the sidebars 1826 for (auto &sidebar : qAsConst(m_sidebars)) { 1827 sidebar->startRestoreSession(cg); 1828 } 1829 1830 setToolViewStyle(static_cast<KMultiTabBar::KMultiTabBarStyle>(cg.readEntry("Kate-MDI-Sidebar-Style", static_cast<int>(toolViewStyle())))); 1831 // after reading m_sidebarsVisible, update the GUI toggle action 1832 m_sidebarsVisible = cg.readEntry("Kate-MDI-Sidebar-Visible", true); 1833 m_guiClient->updateSidebarsVisibleAction(); 1834 } 1835 1836 void MainWindow::finishRestore() 1837 { 1838 if (!m_restoreConfig) { 1839 return; 1840 } 1841 1842 if (m_restoreConfig->hasGroup(m_restoreGroup)) { 1843 // apply all settings, like toolbar pos and more ;) 1844 KConfigGroup cg(m_restoreConfig, m_restoreGroup); 1845 applyMainWindowSettings(cg); 1846 1847 // reshuffle toolviews only if needed 1848 for (const auto &[id, tv] : m_toolviews) { 1849 KMultiTabBar::KMultiTabBarPosition newPos = static_cast<KMultiTabBar::KMultiTabBarPosition>( 1850 cg.readEntry(QStringLiteral("Kate-MDI-ToolView-%1-Position").arg(id), int(tv->sidebar()->position()))); 1851 1852 if (tv->sidebar()->position() != newPos) { 1853 moveToolView(tv, newPos); 1854 } 1855 } 1856 1857 // Restore the sidebars before we restore h/vSplitter.. 1858 for (auto &sidebar : m_sidebars) { 1859 sidebar->restoreSession(cg); 1860 } 1861 1862 // get main splitter sizes ;) 1863 m_hSplitter->setSizes(cg.readEntry("Kate-MDI-H-Splitter", QList<int>{200, 100, 200})); 1864 m_vSplitter->setSizes(cg.readEntry("Kate-MDI-V-Splitter", QList<int>{150, 100, 200})); 1865 1866 // Expand again to trigger splitter sync tabs/tools, but for any reason works this sometimes only after enough delay 1867 QTimer::singleShot(400, this, [this]() { 1868 // ensure we don't steal the focus, remember old focus widget 1869 QPointer<QWidget> oldFocusWidget(QApplication::focusWidget()); 1870 1871 for (auto &sidebar : m_sidebars) { 1872 sidebar->updateSidebar(); 1873 } 1874 1875 // ensure focus is not stolen, pass back to widget or at least central area 1876 if (oldFocusWidget) { 1877 oldFocusWidget->setFocus(); 1878 } else { 1879 triggerFocusForCentralWidget(); 1880 } 1881 }); 1882 } 1883 1884 // clear this stuff, we are done ;) 1885 m_restoreConfig = nullptr; 1886 m_restoreGroup.clear(); 1887 } 1888 1889 void MainWindow::saveSession(KConfigGroup &config) 1890 { 1891 saveMainWindowSettings(config); 1892 1893 // KWrite uses no sidebars, avoid all work beside windows sizes saving 1894 if (KateApp::isKWrite()) { 1895 return; 1896 } 1897 1898 // save main splitter sizes ;) 1899 config.writeEntry("Kate-MDI-H-Splitter", m_hSplitter->sizes()); 1900 config.writeEntry("Kate-MDI-V-Splitter", m_vSplitter->sizes()); 1901 1902 // save sidebar style 1903 config.writeEntry("Kate-MDI-Sidebar-Style", static_cast<int>(toolViewStyle())); 1904 config.writeEntry("Kate-MDI-Sidebar-Visible", m_sidebarsVisible); 1905 1906 // save the sidebars 1907 for (auto &sidebar : m_sidebars) { 1908 sidebar->saveSession(config); 1909 } 1910 } 1911 1912 QWidget *MainWindow::createContainer(QWidget *parent, int index, const QDomElement &element, QAction *&containerAction) 1913 { 1914 // ensure we don't have toolbar accelerators that clash with other stuff 1915 QWidget *createdContainer = KParts::MainWindow::createContainer(parent, index, element, containerAction); 1916 if (element.tagName() == QLatin1String("ToolBar")) { 1917 KAcceleratorManager::setNoAccel(createdContainer); 1918 } 1919 return createdContainer; 1920 } 1921 1922 // END MAIN WINDOW 1923 1924 } // namespace KateMDI 1925 1926 #include "moc_katemdi.cpp"