katemdi.cpp 30.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* This file is part of the KDE libraries
   Copyright (C) 2005 Christoph Cullmann <cullmann@kde.org>
   Copyright (C) 2002, 2003 Joseph Wenninger <jowenn@kde.org>

   GUIClient partly based on ktoolbarhandler.cpp: Copyright (C) 2002 Simon Hausmann <hausmann@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "katemdi.h"

25
#include "katedebug.h"
26

Michal Humpula's avatar
Michal Humpula committed
27
28
29
30
31
32
33
#include <KActionCollection>
#include <KActionMenu>
#include <KConfigGroup>
#include <KMessageBox>
#include <KXMLGUIFactory>
#include <KLocalizedString>
#include <KSharedConfig>
34
#include <kwindowconfig.h>
35
#include <KToolBar>
36

Michal Humpula's avatar
Michal Humpula committed
37
38
39
40
41
42
43
44
45
#include <QChildEvent>
#include <QEvent>
#include <QContextMenuEvent>
#include <QPixmap>
#include <QMenu>
#include <QShortcut>
#include <QSizePolicy>
#include <QStyle>
#include <QDomDocument>
Christoph Cullmann's avatar
Christoph Cullmann committed
46
#include <QVBoxLayout>
Michal Humpula's avatar
Michal Humpula committed
47

48
49
50
51
namespace KateMDI
{

//BEGIN TOGGLETOOLVIEWACTION
52
//
53
54
55
56
57
ToggleToolViewAction::ToggleToolViewAction(const QString &text, ToolView *tv,
        QObject *parent)
    : KToggleAction(text, parent)
    , m_tv(tv)
{
Laurent Montel's avatar
Laurent Montel committed
58
59
    connect(this, &ToggleToolViewAction::toggled, this, &ToggleToolViewAction::slotToggled);
    connect(m_tv, &ToolView::toolVisibleChanged, this, &ToggleToolViewAction::toolVisibleChanged);
60
61

    setChecked(m_tv->toolVisible());
62
63
64
65
66
67
68
69
70
}

ToggleToolViewAction::~ToggleToolViewAction()
{}

void ToggleToolViewAction::toolVisibleChanged(bool)
{
    if (isChecked() != m_tv->toolVisible()) {
        setChecked(m_tv->toolVisible());
71
    }
72
73
74
75
76
77
78
79
80
}

void ToggleToolViewAction::slotToggled(bool t)
{
    if (t) {
        m_tv->mainWindow()->showToolView(m_tv);
        m_tv->setFocus();
    } else {
        m_tv->mainWindow()->hideToolView(m_tv);
81
    }
82
}
83
84
85
86
87

//END TOGGLETOOLVIEWACTION

//BEGIN GUICLIENT

88
static const QString actionListName = QStringLiteral("kate_mdi_view_actions");
89

90
// please don't use QStringLiteral since it can't be used with a concatenated string parameter on all platforms
Laurent Montel's avatar
Laurent Montel committed
91
static const QString guiDescription = QStringLiteral(""
Christoph Cullmann's avatar
Christoph Cullmann committed
92
                                      "<!DOCTYPE kpartgui><kpartgui name=\"kate_mdi_view_actions\">"
93
                                      "<MenuBar>"
Christoph Cullmann's avatar
Christoph Cullmann committed
94
                                      "    <Menu name=\"view\">"
95
96
97
                                      "        <ActionList name=\"%1\" />"
                                      "    </Menu>"
                                      "</MenuBar>"
98
                                      "</kpartgui>");
99

100
101
102
103
104
GUIClient::GUIClient(MainWindow *mw)
    : QObject(mw)
    , KXMLGUIClient(mw)
    , m_mw(mw)
{
Laurent Montel's avatar
Laurent Montel committed
105
106
    connect(m_mw->guiFactory(), &KXMLGUIFactory::clientAdded,
            this, &GUIClient::clientAdded);
107

108
109
    if (domDocument().documentElement().isNull()) {
        QString completeDescription = guiDescription.arg(actionListName);
110

111
        setXML(completeDescription, false /*merge*/);
112
113
114
    }

    m_toolMenu = new KActionMenu(i18n("Tool &Views"), this);
115
    actionCollection()->addAction(QStringLiteral("kate_mdi_toolview_menu"), m_toolMenu);
116
117
    m_showSidebarsAction = new KToggleAction(i18n("Show Side&bars"), this);
    actionCollection()->addAction(QStringLiteral("kate_mdi_sidebar_visibility"), m_showSidebarsAction);
118
    actionCollection()->setDefaultShortcut(m_showSidebarsAction, Qt::CTRL | Qt::ALT | Qt::SHIFT | Qt::Key_F);
Christoph Cullmann's avatar
Christoph Cullmann committed
119

120
    m_showSidebarsAction->setChecked(m_mw->sidebarsVisible());
Laurent Montel's avatar
Laurent Montel committed
121
    connect(m_showSidebarsAction, &KToggleAction::toggled, m_mw, &MainWindow::setSidebarsVisible);
122

123
124
125
126
    m_toolMenu->addAction(m_showSidebarsAction);
    QAction *sep_act = new QAction(this);
    sep_act->setSeparator(true);
    m_toolMenu->addAction(sep_act);
127
128

    // read shortcuts
129
    actionCollection()->setConfigGroup(QStringLiteral("Shortcuts"));
130
    actionCollection()->readSettings();
131

132
    actionCollection()->addAssociatedWidget(m_mw);
133
134
135
    foreach(QAction * action, actionCollection()->actions())
    action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
}
136

137
GUIClient::~GUIClient()
138
139
{}

140
141
142
143
void GUIClient::updateSidebarsVisibleAction()
{
    m_showSidebarsAction->setChecked(m_mw->sidebarsVisible());
}
144

145
146
void GUIClient::registerToolView(ToolView *tv)
{
Laurent Montel's avatar
Laurent Montel committed
147
    QString aname = QLatin1String("kate_mdi_toolview_") + tv->id;
148
149

    // try to read the action shortcut
Michal Humpula's avatar
Michal Humpula committed
150
151
    QList<QKeySequence> shortcuts;

152
    KSharedConfigPtr cfg = KSharedConfig::openConfig();
Michal Humpula's avatar
Michal Humpula committed
153
154
    QString shortcutString = cfg->group("Shortcuts").readEntry(aname, QString());

155
156
    foreach(const QString & shortcut, shortcutString.split(QLatin1String(";"))) {
        shortcuts << QKeySequence::fromString(shortcut);
Michal Humpula's avatar
Michal Humpula committed
157
    }
158

159
    KToggleAction *a = new ToggleToolViewAction(i18n("Show %1", tv->text), tv, this);
160
    actionCollection()->setDefaultShortcuts(a, shortcuts);
161
    actionCollection()->addAction(aname, a);
162
163
164
165

    m_toolViewActions.append(a);
    m_toolMenu->addAction(a);

166
    m_toolToAction.insert(tv, a);
167
168

    updateActions();
169
}
170

171
172
void GUIClient::unregisterToolView(ToolView *tv)
{
173
    QAction *a = m_toolToAction[tv];
174

175
176
177
    if (!a) {
        return;
    }
178

179
    m_toolViewActions.removeAt(m_toolViewActions.indexOf(a));
180
181
    delete a;

182
    m_toolToAction.remove(tv);
183
184

    updateActions();
185
}
186

187
188
189
190
191
192
void GUIClient::clientAdded(KXMLGUIClient *client)
{
    if (client == this) {
        updateActions();
    }
}
193

194
195
196
197
198
void GUIClient::updateActions()
{
    if (!factory()) {
        return;
    }
199

200
    unplugActionList(actionListName);
201

202
    QList<QAction *> addList;
203
204
    addList.append(m_toolMenu);

205
206
    plugActionList(actionListName, addList);
}
207
208
209
210
211

//END GUICLIENT

//BEGIN TOOLVIEW

212
213
214
215
ToolView::ToolView(MainWindow *mainwin, Sidebar *sidebar, QWidget *parent)
    : QFrame(parent)
    , m_mainWin(mainwin)
    , m_sidebar(sidebar)
216
    , m_toolbar(nullptr)
217
218
219
    , m_toolVisible(false)
    , persistent(false)
{
220
    // try to fix resize policy
221
222
223
    QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Preferred);
    policy.setRetainSizeWhenHidden(true);
    setSizePolicy(policy);
Christoph Cullmann's avatar
Christoph Cullmann committed
224
225

    // per default vbox layout
226
    QVBoxLayout *layout = new QVBoxLayout(this);
Laurent Montel's avatar
Laurent Montel committed
227
    layout->setContentsMargins(0, 0, 0, 0);
Christoph Cullmann's avatar
Christoph Cullmann committed
228
229
230
231
    layout->setSpacing(0);
    setLayout(layout);

    // toolbar to collect actions
232
233
234
    m_toolbar = new KToolBar(this);
    m_toolbar->setVisible(false);
    m_toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly);
235
236
237
238
239

    // ensure reasonable icons sizes, like e.g. the quick-open and co. icons
    // the normal toolbar sizes are TOO large, e.g. for scaled stuff even more!
    const int iconSize = style()->pixelMetric(QStyle::PM_ButtonIconSize, nullptr, this);
    m_toolbar->setIconSize(QSize(iconSize, iconSize));
240
}
241

242
243
244
245
246
247
248
249
250
251
QSize ToolView::sizeHint() const
{
    return size();
}

QSize ToolView::minimumSizeHint() const
{
    return QSize(160, 160);
}

252
253
254
255
ToolView::~ToolView()
{
    m_mainWin->toolViewDeleted(this);
}
256

257
258
259
260
261
void ToolView::setToolVisible(bool vis)
{
    if (m_toolVisible == vis) {
        return;
    }
262
263

    m_toolVisible = vis;
264
265
    emit toolVisibleChanged(m_toolVisible);
}
266

267
268
bool ToolView::toolVisible() const
{
269
    return m_toolVisible;
270
}
271

272
273
void ToolView::childEvent(QChildEvent *ev)
{
274
    // set the widget to be focus proxy if possible
275
    if ((ev->type() == QEvent::ChildAdded) && qobject_cast<QWidget *>(ev->child())) {
276
277
278
        QWidget *widget = qobject_cast<QWidget *>(ev->child());
        setFocusProxy(widget);
        layout()->addWidget(widget);
279
    }
280

281
282
    QFrame::childEvent(ev);
}
283

284
285
286
287
288
289
290
291
292
293
294
void ToolView::actionEvent(QActionEvent* event)
{
    QFrame::actionEvent(event);
    if (event->type() == QEvent::ActionAdded) {
        m_toolbar->addAction(event->action());
    } else if (event->type() == QEvent::ActionRemoved) {
        m_toolbar->removeAction(event->action());
    }
    m_toolbar->setVisible(!m_toolbar->actions().isEmpty());
}

295
296
297
298
//END TOOLVIEW

//BEGIN SIDEBAR

299
300
301
Sidebar::Sidebar(KMultiTabBar::KMultiTabBarPosition pos, MainWindow *mainwin, QWidget *parent)
    : KMultiTabBar(pos, parent)
    , m_mainWin(mainwin)
302
303
    , m_splitter(nullptr)
    , m_ownSplit(nullptr)
304
305
306
307
308
309
310
311
312
313
    , m_lastSize(0)
{
    hide();
}

Sidebar::~Sidebar()
{}

void Sidebar::setSplitter(QSplitter *sp)
{
314
    m_splitter = sp;
315
316
317
318
    m_ownSplit = new QSplitter((position() == KMultiTabBar::Top || position() == KMultiTabBar::Bottom) ? Qt::Horizontal : Qt::Vertical, m_splitter);
    m_ownSplit->setChildrenCollapsible(false);
    m_ownSplit->hide();
}
319

Kevin Funk's avatar
Kevin Funk committed
320
ToolView *Sidebar::addWidget(const QIcon &icon, const QString &text, ToolView *widget)
321
{
322
323
    static int id = 0;

324
325
326
327
    if (widget) {
        if (widget->sidebar() == this) {
            return widget;
        }
328

329
        widget->sidebar()->removeWidget(widget);
330
331
332
333
    }

    int newId = ++id;

334
335
336
337
338
339
340
341
342
343
344
    appendTab(icon, newId, text);

    if (!widget) {
        widget = new ToolView(m_mainWin, this, m_ownSplit);
        widget->hide();
        widget->icon = icon;
        widget->text = text;
    } else {
        widget->hide();
        widget->setParent(m_ownSplit);
        widget->m_sidebar = this;
345
346
    }

Vegard Øye's avatar
Vegard Øye committed
347
    // save its pos ;)
348
349
    widget->persistent = false;

350
351
352
    m_idToWidget.insert(newId, widget);
    m_widgetToId.insert(widget, newId);
    m_toolviews.push_back(widget);
353

354
355
    // widget => size, for correct size restoration after hide/show
    // starts with invalid size
356
    m_widgetToSize.insert(widget, QSize());
357

358
    show();
359
360
361

    connect(tab(newId), SIGNAL(clicked(int)), this, SLOT(tabClicked(int)));
    tab(newId)->installEventFilter(this);
362
    tab(newId)->setToolTip(QString());
363
364

    return widget;
365
}
366

367
368
369
370
371
bool Sidebar::removeWidget(ToolView *widget)
{
    if (!m_widgetToId.contains(widget)) {
        return false;
    }
372
373
374

    removeTab(m_widgetToId[widget]);

375
376
377
378
    m_idToWidget.remove(m_widgetToId[widget]);
    m_widgetToId.remove(widget);
    m_widgetToSize.remove(widget);
    m_toolviews.removeAt(m_toolviews.indexOf(widget));
379
380

    bool anyVis = false;
381
382
383
    QMapIterator<int, ToolView *> it(m_idToWidget);
    while (it.hasNext()) {
        it.next();
384
385
        if ((anyVis = it.value()->isVisible())) {
            break;
386
        }
387
388
    }

389
390
391
392
393
    if (m_idToWidget.isEmpty()) {
        m_ownSplit->hide();
        hide();
    } else if (!anyVis) {
        m_ownSplit->hide();
394
395
396
    }

    return true;
397
}
398

399
400
401
402
403
bool Sidebar::showWidget(ToolView *widget)
{
    if (!m_widgetToId.contains(widget)) {
        return false;
    }
404
405

    // hide other non-persistent views
406
407
408
409
    QMapIterator<int, ToolView *> it(m_idToWidget);
    while (it.hasNext()) {
        it.next();
        if ((it.value() != widget) && !it.value()->persistent) {
410
            hideWidget(it.value());
411
        }
412
    }
413

414
    setTab(m_widgetToId[widget], true);
415

416
    /**
Yuri Chornoivan's avatar
Yuri Chornoivan committed
417
     * resize to right size again and show, else artifacts
418
     */
419
420
421
    if (m_widgetToSize[widget].isValid()) {
        widget->resize(m_widgetToSize[widget]);
    }
422
423

    /**
Yuri Chornoivan's avatar
Yuri Chornoivan committed
424
     * resize to right size again and show, else artifacts
425
426
     * same as for widget, both needed
     */
427
    if (m_preHideSize.isValid()) {
428
        widget->resize(m_preHideSize);
429
430
431
        m_ownSplit->resize(m_preHideSize);
    }
    m_ownSplit->show();
432
    widget->show();
433

434
435
436
    /**
     * we are visible again!
     */
437
    widget->setToolVisible(true);
438
    return true;
439
}
440

441
442
443
444
445
bool Sidebar::hideWidget(ToolView *widget)
{
    if (!m_widgetToId.contains(widget)) {
        return false;
    }
446
447
448

    bool anyVis = false;

449
450
451
452
453
454
455
456
457
458
    updateLastSize();

    QMapIterator<int, ToolView *> it(m_idToWidget);
    while (it.hasNext()) {
        it.next();
        if (it.value() == widget) {
            // remember size and hide
            if (widget->isVisible()) {
                m_widgetToSize[widget] = widget->size();
            }
459
460
        } else if ((anyVis = it.value()->isVisible())) {
            break;
461
        }
462
463
    }

464
465
    widget->hide();

466
    // lower tab
467
    setTab(m_widgetToId[widget], false);
468

469
    if (!anyVis) {
470
471
472
473
        if (m_ownSplit->isVisible()) {
            m_preHideSize = m_ownSplit->size();
        }
        m_ownSplit->hide();
474
    }
475
476

    widget->setToolVisible(false);
477
    return true;
478
}
479

480
481
void Sidebar::tabClicked(int i)
{
482
483
    ToolView *w = m_idToWidget[i];

484
485
    if (!w) {
        return;
486
    }
487
488
489
490
491
492

    if (isTabRaised(i)) {
        showWidget(w);
        w->setFocus();
    } else {
        hideWidget(w);
493
    }
494
}
495

496
497
498
499
500
501
502
bool Sidebar::eventFilter(QObject *obj, QEvent *ev)
{
    if (ev->type() == QEvent::ContextMenu) {
        QContextMenuEvent *e = (QContextMenuEvent *) ev;
        KMultiTabBarTab *bt = dynamic_cast<KMultiTabBarTab *>(obj);
        if (bt) {
            //qCDebug(LOG_KATE) << "Request for popup";
503

504
            m_popupButton = bt->id();
505

506
            ToolView *w = m_idToWidget[m_popupButton];
507

508
509
            if (w) {
                QMenu *menu = new QMenu(this);
510

511
                if (!w->plugin.isNull()) {
512
513
                    if (w->plugin.data()->configPages() > 0) {
                        menu->addAction(i18n("Configure ..."))->setData(20);
514
515
                    }
                }
516

517
                menu->addSection(QIcon::fromTheme(QStringLiteral("view_remove")), i18n("Behavior"));
518

519
520
                menu->addAction(w->persistent ? QIcon::fromTheme(QStringLiteral("view-restore")) : QIcon::fromTheme(QStringLiteral("view-fullscreen")),
                                w->persistent ? i18n("Make Non-Persistent") : i18n("Make Persistent")) -> setData(10);
521

522
                menu->addSection(QIcon::fromTheme(QStringLiteral("move")), i18n("Move To"));
523

524
525
526
                if (position() != 0) {
                    menu->addAction(QIcon::fromTheme(QStringLiteral("go-previous")), i18n("Left Sidebar"))->setData(0);
                }
527

528
529
530
                if (position() != 1) {
                    menu->addAction(QIcon::fromTheme(QStringLiteral("go-next")), i18n("Right Sidebar"))->setData(1);
                }
531

532
533
534
                if (position() != 2) {
                    menu->addAction(QIcon::fromTheme(QStringLiteral("go-up")), i18n("Top Sidebar"))->setData(2);
                }
535

536
537
538
                if (position() != 3) {
                    menu->addAction(QIcon::fromTheme(QStringLiteral("go-down")), i18n("Bottom Sidebar"))->setData(3);
                }
539

Laurent Montel's avatar
Laurent Montel committed
540
                connect(menu, &QMenu::triggered, this, &Sidebar::buttonPopupActivate);
541

542
543
                menu->exec(e->globalPos());
                delete menu;
544

545
546
                return true;
            }
547
548
549
550
        }
    }

    return false;
551
}
552

553
554
void Sidebar::setVisible(bool visible)
{
555
    // visible==true means show-request
556
557
558
    if (visible && (m_idToWidget.isEmpty() || !m_mainWin->sidebarsVisible())) {
        return;
    }
559
560

    KMultiTabBar::setVisible(visible);
561
}
562

563
564
void Sidebar::buttonPopupActivate(QAction *a)
{
565
566
567
    int id = a->data().toInt();
    ToolView *w = m_idToWidget[m_popupButton];

568
569
570
    if (!w) {
        return;
    }
571
572

    // move ids
573
574
575
576
    if (id < 4) {
        // move + show ;)
        m_mainWin->moveToolView(w, (KMultiTabBar::KMultiTabBarPosition) id);
        m_mainWin->showToolView(w);
577
578
579
    }

    // toggle persistent
580
581
582
    if (id == 10) {
        w->persistent = !w->persistent;
    }
583

584
    // configure actionCollection
585
586
    if (id == 20) {
        if (!w->plugin.isNull()) {
587
588
            if (w->plugin.data()->configPages() > 0) {
                emit sigShowPluginConfigPage(w->plugin.data(), 0);
589
            }
590
591
        }
    }
592
}
593

594
595
596
void Sidebar::updateLastSize()
{
    QList<int> s = m_splitter->sizes();
597
598

    int i = 0;
599
600
601
    if ((position() == KMultiTabBar::Right || position() == KMultiTabBar::Bottom)) {
        i = 2;
    }
602
603

    // little threshold
604
605
606
607
608
609
610
611
612
613
614
615
616
617
    if (s[i] > 2) {
        m_lastSize = s[i];
    }
}

class TmpToolViewSorter
{
public:
    ToolView *tv;
    unsigned int pos;
};

void Sidebar::restoreSession(KConfigGroup &config)
{
618
619
    // get the last correct placed toolview
    int firstWrong = 0;
620
621
    for (; firstWrong < m_toolviews.size(); ++firstWrong) {
        ToolView *tv = m_toolviews[firstWrong];
622

Laurent Montel's avatar
Laurent Montel committed
623
        int pos = config.readEntry(QStringLiteral("Kate-MDI-ToolView-%1-Sidebar-Position").arg(tv->id), firstWrong);
624

625
626
627
        if (pos != firstWrong) {
            break;
        }
628
629
630
    }

    // we need to reshuffle, ahhh :(
631
632
633
634
635
636
    if (firstWrong < m_toolviews.size()) {
        // first: collect the items to reshuffle
        QList<TmpToolViewSorter> toSort;
        for (int i = firstWrong; i < m_toolviews.size(); ++i) {
            TmpToolViewSorter s;
            s.tv = m_toolviews[i];
Laurent Montel's avatar
Laurent Montel committed
637
            s.pos = config.readEntry(QStringLiteral("Kate-MDI-ToolView-%1-Sidebar-Position").arg(m_toolviews[i]->id), i);
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
            toSort.push_back(s);
        }

        // now: sort the stuff we need to reshuffle
        for (int m = 0; m < toSort.size(); ++m)
            for (int n = m + 1; n < toSort.size(); ++n)
                if (toSort[n].pos < toSort[m].pos) {
                    TmpToolViewSorter tmp = toSort[n];
                    toSort[n] = toSort[m];
                    toSort[m] = tmp;
                }

        // then: remove this items from the button bar
        // do this backwards, to minimize the relayout efforts
        for (int i = m_toolviews.size() - 1; i >= (int)firstWrong; --i) {
            removeTab(m_widgetToId[m_toolviews[i]]);
        }

        // insert the reshuffled things in order :)
        for (int i = 0; i < toSort.size(); ++i) {
            ToolView *tv = toSort[i].tv;

            m_toolviews[firstWrong + i] = tv;

            // readd the button
            int newId = m_widgetToId[tv];
            appendTab(tv->icon, newId, tv->text);
            connect(tab(newId), SIGNAL(clicked(int)), this, SLOT(tabClicked(int)));
            tab(newId)->installEventFilter(this);
667
            tab(newId)->setToolTip(QString());
668
669
670
671

            // reshuffle in splitter: move to last
            m_ownSplit->addWidget(tv);
        }
672
673
674
    }

    // update last size if needed
675
    updateLastSize();
676
677

    // restore the own splitter sizes
Laurent Montel's avatar
Laurent Montel committed
678
    QList<int> s = config.readEntry(QStringLiteral("Kate-MDI-Sidebar-%1-Splitter").arg(position()), QList<int>());
679
    m_ownSplit->setSizes(s);
680
681
682

    // show only correct toolviews, remember persistent values ;)
    bool anyVis = false;
683
684
    for (int i = 0; i < m_toolviews.size(); ++i) {
        ToolView *tv = m_toolviews[i];
685

Laurent Montel's avatar
Laurent Montel committed
686
687
        tv->persistent = config.readEntry(QStringLiteral("Kate-MDI-ToolView-%1-Persistent").arg(tv->id), false);
        tv->setToolVisible(config.readEntry(QStringLiteral("Kate-MDI-ToolView-%1-Visible").arg(tv->id), false));
688

689
690
691
        if (!anyVis) {
            anyVis = tv->toolVisible();
        }
692

693
        setTab(m_widgetToId[tv], tv->toolVisible());
694

695
696
697
698
699
        if (tv->toolVisible()) {
            tv->show();
        } else {
            tv->hide();
        }
700
701
    }

702
703
704
705
706
707
    if (anyVis) {
        m_ownSplit->show();
    } else {
        m_ownSplit->hide();
    }
}
708

709
710
void Sidebar::saveSession(KConfigGroup &config)
{
711
712
    // store the own splitter sizes
    QList<int> s = m_ownSplit->sizes();
Laurent Montel's avatar
Laurent Montel committed
713
    config.writeEntry(QStringLiteral("Kate-MDI-Sidebar-%1-Splitter").arg(position()), s);
714
715

    // store the data about all toolviews in this sidebar ;)
716
717
718
    for (int i = 0; i < m_toolviews.size(); ++i) {
        ToolView *tv = m_toolviews[i];

Laurent Montel's avatar
Laurent Montel committed
719
720
721
722
        config.writeEntry(QStringLiteral("Kate-MDI-ToolView-%1-Position").arg(tv->id), int(tv->sidebar()->position()));
        config.writeEntry(QStringLiteral("Kate-MDI-ToolView-%1-Sidebar-Position").arg(tv->id), i);
        config.writeEntry(QStringLiteral("Kate-MDI-ToolView-%1-Visible").arg(tv->id), tv->toolVisible());
        config.writeEntry(QStringLiteral("Kate-MDI-ToolView-%1-Persistent").arg(tv->id), tv->persistent);
723
    }
724
}
725
726
727
728
729

//END SIDEBAR

//BEGIN MAIN WINDOW

730
731
732
MainWindow::MainWindow(QWidget *parentWidget)
    : KParts::MainWindow(parentWidget, Qt::Window)
    , m_sidebarsVisible(true)
733
    , m_restoreConfig(nullptr)
734
735
    , m_guiClient(new GUIClient(this))
{
736
    // init the internal widgets
737
738
    QFrame *hb = new QFrame(this);
    QHBoxLayout *hlayout = new QHBoxLayout(hb);
Laurent Montel's avatar
Laurent Montel committed
739
    hlayout->setContentsMargins(0, 0, 0, 0);
740
741
    hlayout->setSpacing(0);

742
743
    setCentralWidget(hb);

744
    m_sidebars[KMultiTabBar::Left] = new Sidebar(KMultiTabBar::Left, this, hb);
745
    hlayout->addWidget(m_sidebars[KMultiTabBar::Left]);
746

747
    m_hSplitter = new QSplitter(Qt::Horizontal, hb);
748
    hlayout->addWidget(m_hSplitter);
749

750
    m_sidebars[KMultiTabBar::Left]->setSplitter(m_hSplitter);
751

752
753
    QFrame *vb = new QFrame(m_hSplitter);
    QVBoxLayout *vlayout = new QVBoxLayout(vb);
Laurent Montel's avatar
Laurent Montel committed
754
    vlayout->setContentsMargins(0, 0, 0, 0);
755
756
    vlayout->setSpacing(0);

757
758
    m_hSplitter->setCollapsible(m_hSplitter->indexOf(vb), false);
    m_hSplitter->setStretchFactor(m_hSplitter->indexOf(vb), 1);
759

760
    m_sidebars[KMultiTabBar::Top] = new Sidebar(KMultiTabBar::Top, this, vb);
761
    vlayout->addWidget(m_sidebars[KMultiTabBar::Top]);
762

763
    m_vSplitter = new QSplitter(Qt::Vertical, vb);
764
    vlayout->addWidget(m_vSplitter);
765

766
    m_sidebars[KMultiTabBar::Top]->setSplitter(m_vSplitter);
767

768
769
770
    m_centralWidget = new QWidget(m_vSplitter);
    m_centralWidget->setLayout(new QVBoxLayout);
    m_centralWidget->layout()->setSpacing(0);
Laurent Montel's avatar
Laurent Montel committed
771
    m_centralWidget->layout()->setContentsMargins(0, 0, 0, 0);
772

773
774
    m_vSplitter->setCollapsible(m_vSplitter->indexOf(m_centralWidget), false);
    m_vSplitter->setStretchFactor(m_vSplitter->indexOf(m_centralWidget), 1);
775

776
    m_sidebars[KMultiTabBar::Bottom] = new Sidebar(KMultiTabBar::Bottom, this, vb);
777
    vlayout->addWidget(m_sidebars[KMultiTabBar::Bottom]);
778
    m_sidebars[KMultiTabBar::Bottom]->setSplitter(m_vSplitter);
779

780
    m_sidebars[KMultiTabBar::Right] = new Sidebar(KMultiTabBar::Right, this, hb);
781
    hlayout->addWidget(m_sidebars[KMultiTabBar::Right]);
782
    m_sidebars[KMultiTabBar::Right]->setSplitter(m_hSplitter);
783

784
    for (int i = 0; i < 4; i++) {
Laurent Montel's avatar
Laurent Montel committed
785
        connect(m_sidebars[i], &Sidebar::sigShowPluginConfigPage, this, &MainWindow::sigShowPluginConfigPage);
786
    }
787

788
}
789

790
791
MainWindow::~MainWindow()
{
792
    // cu toolviews
Christoph Cullmann's avatar
Christoph Cullmann committed
793
    qDeleteAll(m_toolviews);
794
795
796
797

    // seems like we really should delete this by hand ;)
    delete m_centralWidget;

Christoph Cullmann's avatar
Christoph Cullmann committed
798
    // cleanup the sidebars
799
800
801
802
    for (unsigned int i = 0; i < 4; ++i) {
        delete m_sidebars[i];
    }
}
803

804
805
QWidget *MainWindow::centralWidget() const
{
806
    return m_centralWidget;
807
}
808

Kevin Funk's avatar
Kevin Funk committed
809
ToolView *MainWindow::createToolView(KTextEditor::Plugin *plugin, const QString &identifier, KMultiTabBar::KMultiTabBarPosition pos, const QIcon &icon, const QString &text)
810
811
{
    if (m_idToWidget[identifier]) {
812
        return nullptr;
813
    }
814
815

    // try the restore config to figure out real pos
816
817
    if (m_restoreConfig && m_restoreConfig->hasGroup(m_restoreGroup)) {
        KConfigGroup cg(m_restoreConfig, m_restoreGroup);
Laurent Montel's avatar
Laurent Montel committed
818
        pos = (KMultiTabBar::KMultiTabBarPosition) cg.readEntry(QStringLiteral("Kate-MDI-ToolView-%1-Position").arg(identifier), int(pos));
819
820
    }

821
    ToolView *v  = m_sidebars[pos]->addWidget(icon, text, nullptr);
822
    v->id = identifier;
823
    v->plugin = plugin;
824

825
826
    m_idToWidget.insert(identifier, v);
    m_toolviews.push_back(v);
827

828
    // register for menu stuff
829
    m_guiClient->registerToolView(v);
830
831

    return v;
832
}
833

834
835
ToolView *MainWindow::toolView(const QString &identifier) const
{
836
    return m_idToWidget[identifier];
837
}
838

839
840
841
842
843
void MainWindow::toolViewDeleted(ToolView *widget)
{
    if (!widget) {
        return;
    }
844

845
846
847
    if (widget->mainWindow() != this) {
        return;
    }
848
849

    // unregister from menu stuff
850
    m_guiClient->unregisterToolView(widget);
851

852
    widget->sidebar()->removeWidget(widget);
853

854
855
    m_idToWidget.remove(widget->id);
    m_toolviews.removeAt(m_toolviews.indexOf(widget));
856

857
}
858

859
860
861
void MainWindow::setSidebarsVisible(bool visible)
{
    bool old_visible = m_sidebarsVisible;
862
863
864
865
866
867
868
869
870
871
    m_sidebarsVisible = visible;

    m_sidebars[0]->setVisible(visible);
    m_sidebars[1]->setVisible(visible);
    m_sidebars[2]->setVisible(visible);
    m_sidebars[3]->setVisible(visible);

    m_guiClient->updateSidebarsVisibleAction();

    // show information message box, if the users hides the sidebars
872
873
874
875
876
877
878
879
880
881
    if (old_visible && (!m_sidebarsVisible)) {
        KMessageBox::information(this,
                                 i18n("<qt>You are about to hide the sidebars. With "
                                      "hidden sidebars it is not possible to directly "
                                      "access the tool views with the mouse anymore, "
                                      "so if you need to access the sidebars again "
                                      "invoke <b>View &gt; Tool Views &gt; Show Sidebars</b> "
                                      "in the menu. It is still possible to show/hide "
                                      "the tool views with the assigned shortcuts.</qt>"),
                                 QString(), QStringLiteral("Kate hide sidebars notification message"));
882
    }
883
}
884

885
886
bool MainWindow::sidebarsVisible() const
{
887
    return m_sidebarsVisible;
888
}
889

890
891
void MainWindow::setToolViewStyle(KMultiTabBar::KMultiTabBarStyle style)
{
892
893
894
895
    m_sidebars[0]->setStyle(style);
    m_sidebars[1]->setStyle(style);
    m_sidebars[2]->setStyle(style);
    m_sidebars[3]->setStyle(style);
896
}
897

898
899
KMultiTabBar::KMultiTabBarStyle MainWindow::toolViewStyle() const
{
900
901
    // all sidebars have the same style, so just take Top
    return m_sidebars[KMultiTabBar::Top]->tabStyle();
902
}
903

904
905
906
907
908
bool MainWindow::moveToolView(ToolView *widget, KMultiTabBar::KMultiTabBarPosition pos)
{
    if (!widget || widget->mainWindow() != this) {
        return false;
    }
909
910

    // try the restore config to figure out real pos
911
912
    if (m_restoreConfig && m_restoreConfig->hasGroup(m_restoreGroup)) {
        KConfigGroup cg(m_restoreConfig, m_restoreGroup);
Laurent Montel's avatar
Laurent Montel committed
913
        pos = (KMultiTabBar::KMultiTabBarPosition) cg.readEntry(QStringLiteral("Kate-MDI-ToolView-%1-Position").arg(widget->id), int(pos));
914
915
    }

916
    m_sidebars[pos]->addWidget(widget->icon, widget->text, widget);
917
918

    return true;
919
}
920

921
922
923
924
925
bool MainWindow::showToolView(ToolView *widget)
{
    if (!widget || widget->mainWindow() != this) {
        return false;
    }
926
927

    // skip this if happens during restoring, or we will just see flicker
928
929
930
    if (m_restoreConfig && m_restoreConfig->hasGroup(m_restoreGroup)) {
        return true;
    }
931

932
933
    return widget->sidebar()->showWidget(widget);
}
934

935
936
937
938
939
bool MainWindow::hideToolView(ToolView *widget)
{
    if (!widget || widget->mainWindow() != this) {
        return false;
    }
940
941

    // skip this if happens during restoring, or we will just see flicker
942
943
944
    if (m_restoreConfig && m_restoreConfig->hasGroup(m_restoreGroup)) {
        return true;
    }
945

946
    const bool ret =  widget->sidebar()->hideWidget(widget);
947
948
    m_centralWidget->setFocus();
    return ret;
949
}
950

951
952
void MainWindow::startRestore(KConfigBase *config, const QString &group)
{
953
954
955
956
    // first save this stuff
    m_restoreConfig = config;
    m_restoreGroup = group;

957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
    if (!m_restoreConfig || !m_restoreConfig->hasGroup(m_restoreGroup)) {
        // if no config around, set already now sane default sizes
        // otherwise, set later in ::finishRestore(), since it does not work
        // if set already now (see bug #164438)
        QList<int> hs = (QList<int>() << 200 << 100 << 200);
        QList<int> vs = (QList<int>() << 150 << 100 << 200);

        m_sidebars[0]->setLastSize(hs[0]);
        m_sidebars[1]->setLastSize(hs[2]);
        m_sidebars[2]->setLastSize(vs[0]);
        m_sidebars[3]->setLastSize(vs[2]);

        m_hSplitter->setSizes(hs);
        m_vSplitter->setSizes(vs);
        return;
972
973
974
975
    }

    // apply size once, to get sizes ready ;)
    KConfigGroup cg(m_restoreConfig, m_restoreGroup);
976
    KWindowConfig::restoreWindowSize(windowHandle(), cg);
977

978
    setToolViewStyle((KMultiTabBar::KMultiTabBarStyle)cg.readEntry("Kate-MDI-Sidebar-Style", (int)toolViewStyle()));
979
    // after reading m_sidebarsVisible, update the GUI toggle action
980
    m_sidebarsVisible = cg.readEntry("Kate-MDI-Sidebar-Visible", true);
981
    m_guiClient->updateSidebarsVisibleAction();
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
}

void MainWindow::finishRestore()
{
    if (!m_restoreConfig) {
        return;
    }

    if (m_restoreConfig->hasGroup(m_restoreGroup)) {
        // apply all settings, like toolbar pos and more ;)
        KConfigGroup cg(m_restoreConfig, m_restoreGroup);
        applyMainWindowSettings(cg);

        // reshuffle toolviews only if needed