MainWindow.cpp 30.5 KB
Newer Older
1
/*
2
    Copyright 2006-2008 by Robert Knight <robertknight@gmail.com>
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

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

    This program 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 General Public License for more details.

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

20 21 22
// Own
#include "MainWindow.h"

23
// Qt
24
#include <QVBoxLayout>
25

26
// KDE
27
#include <KAcceleratorManager>
28 29
#include <KActionCollection>
#include <KActionMenu>
30
#include <KShortcutsDialog>
Laurent Montel's avatar
Laurent Montel committed
31
#include <KLocalizedString>
32 33
#include <KToggleAction>
#include <KToggleFullScreenAction>
Alex Richardson's avatar
Alex Richardson committed
34

Laurent Montel's avatar
Laurent Montel committed
35
#include <QMenu>
Laurent Montel's avatar
Laurent Montel committed
36
#include <QMenuBar>
37 38 39
#include <KMessageBox>
#include <KStandardAction>
#include <KStandardGuiItem>
40
#include <KWindowSystem>
41
#include <KXMLGUIFactory>
42
#include <KNotifyConfigWidget>
Jekyll Wu's avatar
Jekyll Wu committed
43
#include <KConfigDialog>
Michal Humpula's avatar
Michal Humpula committed
44
#include <KIconLoader>
45 46

// Konsole
47
#include "BookmarkHandler.h"
48
#include "SessionController.h"
49
#include "ProfileList.h"
50
#include "Session.h"
51
#include "ViewManager.h"
Jekyll Wu's avatar
Jekyll Wu committed
52
#include "SessionManager.h"
53
#include "ProfileManager.h"
Jekyll Wu's avatar
Jekyll Wu committed
54
#include "KonsoleSettings.h"
Eike Hein's avatar
Eike Hein committed
55
#include "WindowSystemInfo.h"
56
#include "settings/FileLocationSettings.h"
Jekyll Wu's avatar
Jekyll Wu committed
57
#include "settings/GeneralSettings.h"
58
#include "settings/ProfileSettings.h"
Jekyll Wu's avatar
Jekyll Wu committed
59
#include "settings/TabBarSettings.h"
60

61 62
using namespace Konsole;

63
MainWindow::MainWindow()
Jekyll Wu's avatar
Jekyll Wu committed
64 65 66
    : KXmlGuiWindow()
    , _bookmarkHandler(0)
    , _pluggedController(0)
67
    , _menuBarInitialVisibility(true)
Jekyll Wu's avatar
Jekyll Wu committed
68
    , _menuBarInitialVisibilityApplied(false)
Kurt Hindenburg's avatar
Kurt Hindenburg committed
69
{
70 71 72 73
    if (!KonsoleSettings::saveGeometryOnExit()) {
        // If we are not using the global Konsole save geometry on exit,
        // remove all Height and Width from [MainWindow] from konsolerc
        // Each screen resolution will have entries (Width 1280=619)
74
        KSharedConfigPtr konsoleConfig = KSharedConfig::openConfig(QStringLiteral("konsolerc"));
75 76 77 78 79
        KConfigGroup group = konsoleConfig->group("MainWindow");
        QMap<QString, QString> configEntries = group.entryMap();
        QMapIterator<QString, QString> i(configEntries);
        while (i.hasNext()) {
            i.next();
Kurt Hindenburg's avatar
Kurt Hindenburg committed
80
            if (i.key().startsWith(QLatin1String("Width"))
81 82 83 84 85 86
                    || i.key().startsWith(QLatin1String("Height"))) {
                group.deleteEntry(i.key());
            }
        }
    }

Eike Hein's avatar
Eike Hein committed
87
    updateUseTransparency();
88

89 90 91 92
    // create actions for menus
    setupActions();

    // create view manager
Kurt Hindenburg's avatar
Kurt Hindenburg committed
93
    _viewManager = new ViewManager(this, actionCollection());
94
    connect(_viewManager, &Konsole::ViewManager::empty, this, &Konsole::MainWindow::close);
Laurent Montel's avatar
Laurent Montel committed
95 96 97 98 99 100 101 102
    connect(_viewManager, &Konsole::ViewManager::activeViewChanged, this, &Konsole::MainWindow::activeViewChanged);
    connect(_viewManager, &Konsole::ViewManager::unplugController, this, &Konsole::MainWindow::disconnectController);
    connect(_viewManager, &Konsole::ViewManager::viewPropertiesChanged, bookmarkHandler(), &Konsole::BookmarkHandler::setViews);

    connect(_viewManager, &Konsole::ViewManager::updateWindowIcon, this, &Konsole::MainWindow::updateWindowIcon);
    connect(_viewManager, static_cast<void(ViewManager::*)(Profile::Ptr)>(&Konsole::ViewManager::newViewRequest), this, &Konsole::MainWindow::newFromProfile);
    connect(_viewManager, static_cast<void(ViewManager::*)()>(&Konsole::ViewManager::newViewRequest), this, &Konsole::MainWindow::newTab);
    connect(_viewManager, &Konsole::ViewManager::viewDetached, this, &Konsole::MainWindow::viewDetached);
103

Jekyll Wu's avatar
Jekyll Wu committed
104 105
    // create the main widget
    setupMainWidget();
106

107 108 109 110
    // disable automatically generated accelerators in top-level
    // menu items - to avoid conflicting with Alt+[Letter] shortcuts
    // in terminal applications
    KAcceleratorManager::setNoAccel(menuBar());
111

112 113
    // create menus
    createGUI();
114

115
    // remember the original menu accelerators for later use
116 117
    rememberMenuAccelerators();

118
    // replace standard shortcuts which cannot be used in a terminal
119
    // emulator (as they are reserved for use by terminal applications)
Jekyll Wu's avatar
Jekyll Wu committed
120
    correctStandardShortcuts();
121

122 123
    setProfileList(new ProfileList(true, this));

124
    // this must come at the end
Jekyll Wu's avatar
Jekyll Wu committed
125
    applyKonsoleSettings();
126
    connect(KonsoleSettings::self(), &Konsole::KonsoleSettings::configChanged, this, &Konsole::MainWindow::applyKonsoleSettings);
127
}
128

Eike Hein's avatar
Eike Hein committed
129 130
void MainWindow::updateUseTransparency()
{
131 132 133 134 135
    if (!WindowSystemInfo::HAVE_TRANSPARENCY) {
        return;
    }

    bool useTranslucency = KWindowSystem::compositingActive();
Eike Hein's avatar
Eike Hein committed
136 137 138 139 140 141

    setAttribute(Qt::WA_TranslucentBackground, useTranslucency);
    setAttribute(Qt::WA_NoSystemBackground, false);
    WindowSystemInfo::HAVE_TRANSPARENCY = useTranslucency;
}

142 143
void MainWindow::rememberMenuAccelerators()
{
144
    foreach(QAction* menuItem, menuBar()->actions()) {
145 146 147 148 149
        QString itemText = menuItem->text();
        menuItem->setData(itemText);
    }
}

150 151 152 153 154 155 156 157
// remove accelerators for standard menu items (eg. &File, &View, &Edit)
// etc. which are defined in kdelibs/kdeui/xmlgui/ui_standards.rc, again,
// to avoid conflicting with Alt+[Letter] terminal shortcuts
//
// TODO - Modify XMLGUI so that it allows the text for standard actions
// defined in ui_standards.rc to be re-defined in the local application
// XMLGUI file (konsoleui.rc in this case) - the text for standard items
// can then be redefined there to exclude the standard accelerators
158 159
void MainWindow::removeMenuAccelerators()
{
160
    foreach(QAction* menuItem, menuBar()->actions()) {
Lukáš Tinkl's avatar
Lukáš Tinkl committed
161
        menuItem->setText(menuItem->text().replace('&', QString()));
162 163
    }
}
164

Jekyll Wu's avatar
Jekyll Wu committed
165
void MainWindow::restoreMenuAccelerators()
166
{
167
    foreach(QAction* menuItem, menuBar()->actions()) {
168 169 170 171 172
        QString itemText = menuItem->data().toString();
        menuItem->setText(itemText);
    }
}

Jekyll Wu's avatar
Jekyll Wu committed
173
void MainWindow::correctStandardShortcuts()
174 175
{
    // replace F1 shortcut for help contents
176
    QAction* helpAction = actionCollection()->action(QStringLiteral("help_contents"));
177
    if (helpAction != nullptr) {
178
        actionCollection()->setDefaultShortcut(helpAction, QKeySequence());
179
    }
180

181 182 183
    // replace Ctrl+B shortcut for bookmarks only if user hasn't already
    // changed the shortcut; however, if the user changed it to Ctrl+B
    // this will still get changed to Ctrl+Shift+B
184
    QAction* bookmarkAction = actionCollection()->action(QStringLiteral("add_bookmark"));
185
    if ((bookmarkAction != nullptr) && bookmarkAction->shortcut() == QKeySequence(Konsole::ACCEL + Qt::Key_B)) {
186
        actionCollection()->setDefaultShortcut(bookmarkAction, Konsole::ACCEL + Qt::SHIFT + Qt::Key_B);
187
    }
188 189
}

190
ViewManager* MainWindow::viewManager() const
191 192 193 194
{
    return _viewManager;
}

195 196
void MainWindow::disconnectController(SessionController* controller)
{
197 198 199 200
    disconnect(controller, &Konsole::SessionController::titleChanged,
               this, &Konsole::MainWindow::activeViewTitleChanged);
    disconnect(controller, &Konsole::SessionController::rawTitleChanged,
               this, &Konsole::MainWindow::updateWindowCaption);
201 202
    disconnect(controller, &Konsole::SessionController::iconChanged,
               this, &Konsole::MainWindow::updateWindowIcon);
Robert Knight's avatar
 
Robert Knight committed
203

204 205 206 207 208 209
    // KXmlGuiFactory::removeClient() will try to access actions associated
    // with the controller internally, which may not be valid after the controller
    // itself is no longer valid (after the associated session and or view have
    // been destroyed)
    if (controller->isValid())
        guiFactory()->removeClient(controller);
Robert Knight's avatar
 
Robert Knight committed
210

211 212 213
    controller->setSearchBar(0);
}

214 215
void MainWindow::activeViewChanged(SessionController* controller)
{
216
    // associate bookmark menu with current session
217
    bookmarkHandler()->setActiveView(controller);
218
    disconnect(bookmarkHandler(), &Konsole::BookmarkHandler::openUrl, 0, 0);
Laurent Montel's avatar
Laurent Montel committed
219
    connect(bookmarkHandler(), &Konsole::BookmarkHandler::openUrl, controller, &Konsole::SessionController::openUrl);
220

221
    if (_pluggedController != nullptr)
222
        disconnectController(_pluggedController);
223

Kurt Hindenburg's avatar
Kurt Hindenburg committed
224
    Q_ASSERT(controller);
225
    _pluggedController = controller;
226

227
    // listen for title changes from the current session
Laurent Montel's avatar
Laurent Montel committed
228 229
    connect(controller, &Konsole::SessionController::titleChanged, this, &Konsole::MainWindow::activeViewTitleChanged);
    connect(controller, &Konsole::SessionController::rawTitleChanged, this, &Konsole::MainWindow::updateWindowCaption);
230
    connect(controller, &Konsole::SessionController::iconChanged, this, &Konsole::MainWindow::updateWindowIcon);
231

Kurt Hindenburg's avatar
Kurt Hindenburg committed
232
    controller->setShowMenuAction(_toggleMenuBarAction);
233 234
    guiFactory()->addClient(controller);

235
    // set the current session's search bar
Kurt Hindenburg's avatar
Kurt Hindenburg committed
236
    controller->setSearchBar(searchBar());
237

238 239 240
    // update session title to match newly activated session
    activeViewTitleChanged(controller);

241 242
    // Update window icon to newly activated session's icon
    updateWindowIcon();
243 244 245 246
}

void MainWindow::activeViewTitleChanged(ViewProperties* properties)
{
247 248 249 250 251 252
    Q_UNUSED(properties);
    updateWindowCaption();
}

void MainWindow::updateWindowCaption()
{
253
    if (_pluggedController == nullptr)
254 255 256 257 258 259 260 261 262
        return;

    const QString& title = _pluggedController->title();
    const QString& userTitle = _pluggedController->userTitle();

    // use tab title as caption by default
    QString caption = title;

    // use window title as caption only when enabled and it is not empty
Kurt Hindenburg's avatar
Kurt Hindenburg committed
263
    if (KonsoleSettings::showWindowTitleOnTitleBar() && !userTitle.isEmpty()) {
264 265 266
        caption = userTitle;
    }

267 268 269 270 271
    if (KonsoleSettings::showAppNameOnTitleBar()) {
        setCaption(caption);
    } else {
        setPlainCaption(caption);
    }
272 273
}

274 275
void MainWindow::updateWindowIcon()
{
276
    if ((_pluggedController != nullptr) && !_pluggedController->icon().isNull())
277 278 279
        setWindowIcon(_pluggedController->icon());
}

280
IncrementalSearchBar* MainWindow::searchBar() const
281
{
282
    return _viewManager->searchBar();
283 284
}

285
void MainWindow::setupActions()
286
{
287
    KActionCollection* collection = actionCollection();
Alex Richardson's avatar
Alex Richardson committed
288
    QAction* menuAction = 0;
289

290
    // File Menu
Michal Humpula's avatar
Michal Humpula committed
291
    _newTabMenuAction = new KActionMenu(QIcon::fromTheme(QStringLiteral("tab-new")), i18nc("@action:inmenu", "&New Tab"), collection);
292
    collection->setDefaultShortcut(_newTabMenuAction, Konsole::ACCEL + Qt::SHIFT + Qt::Key_T);
293
    collection->setShortcutsConfigurable(_newTabMenuAction, true);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
294
    _newTabMenuAction->setAutoRepeat(false);
295
    connect(_newTabMenuAction, &KActionMenu::triggered, this, &Konsole::MainWindow::newTab);
296
    collection->addAction(QStringLiteral("new-tab"), _newTabMenuAction);
297
    collection->setShortcutsConfigurable(_newTabMenuAction, true);
298

299
    menuAction = collection->addAction(QStringLiteral("clone-tab"));
Michal Humpula's avatar
Michal Humpula committed
300
    menuAction->setIcon(QIcon::fromTheme(QStringLiteral("tab-duplicate")));
Kurt Hindenburg's avatar
Kurt Hindenburg committed
301
    menuAction->setText(i18nc("@action:inmenu", "&Clone Tab"));
302
    collection->setDefaultShortcut(menuAction, QKeySequence());
Kurt Hindenburg's avatar
Kurt Hindenburg committed
303
    menuAction->setAutoRepeat(false);
304
    connect(menuAction, &QAction::triggered, this, &Konsole::MainWindow::cloneTab);
305

306
    menuAction = collection->addAction(QStringLiteral("new-window"));
Michal Humpula's avatar
Michal Humpula committed
307
    menuAction->setIcon(QIcon::fromTheme(QStringLiteral("window-new")));
308
    menuAction->setText(i18nc("@action:inmenu", "New &Window"));
309
    collection->setDefaultShortcut(menuAction, Konsole::ACCEL + Qt::SHIFT + Qt::Key_N);
310
    menuAction->setAutoRepeat(false);
311
    connect(menuAction, &QAction::triggered, this, &Konsole::MainWindow::newWindow);
312

313
    menuAction = collection->addAction(QStringLiteral("close-window"));
Michal Humpula's avatar
Michal Humpula committed
314
    menuAction->setIcon(QIcon::fromTheme(QStringLiteral("window-close")));
315
    menuAction->setText(i18nc("@action:inmenu", "Close Window"));
316
    collection->setDefaultShortcut(menuAction, Konsole::ACCEL + Qt::SHIFT + Qt::Key_Q);
317
    connect(menuAction, &QAction::triggered, this, &Konsole::MainWindow::close);
318 319

    // Bookmark Menu
Kurt Hindenburg's avatar
Kurt Hindenburg committed
320 321
    KActionMenu* bookmarkMenu = new KActionMenu(i18nc("@title:menu", "&Bookmarks"), collection);
    _bookmarkHandler = new BookmarkHandler(collection, bookmarkMenu->menu(), true, this);
322
    collection->addAction(QStringLiteral("bookmark"), bookmarkMenu);
323
    connect(_bookmarkHandler, &Konsole::BookmarkHandler::openUrls, this, &Konsole::MainWindow::openUrls);
324

Jekyll Wu's avatar
Jekyll Wu committed
325
    // Settings Menu
326
    _toggleMenuBarAction = KStandardAction::showMenubar(menuBar(), SLOT(setVisible(bool)), collection);
327
    collection->setDefaultShortcut(_toggleMenuBarAction, Konsole::ACCEL + Qt::SHIFT + Qt::Key_M);
328

329
    // Full Screen
330
    menuAction = KStandardAction::fullScreen(this, SLOT(viewFullScreen(bool)), this, collection);
331
    collection->setDefaultShortcut(menuAction, Qt::Key_F11);
332

Kurt Hindenburg's avatar
Kurt Hindenburg committed
333 334
    KStandardAction::configureNotifications(this, SLOT(configureNotifications()), collection);
    KStandardAction::keyBindings(this, SLOT(showShortcutsDialog()), collection);
Jekyll Wu's avatar
Jekyll Wu committed
335
    KStandardAction::preferences(this, SLOT(showSettingsDialog()), collection);
336

337
    menuAction = collection->addAction(QStringLiteral("manage-profiles"));
338
    menuAction->setText(i18nc("@action:inmenu", "Manage Profiles..."));
Michal Humpula's avatar
Michal Humpula committed
339
    menuAction->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
340
    connect(menuAction, &QAction::triggered, this, &Konsole::MainWindow::showManageProfilesDialog);
341

342
    // Set up an shortcut-only action for activating menu bar.
343
    menuAction = collection->addAction(QStringLiteral("activate-menu"));
Kurt Hindenburg's avatar
Kurt Hindenburg committed
344
    menuAction->setText(i18nc("@item", "Activate Menu"));
345
    collection->setDefaultShortcut(menuAction, Konsole::ACCEL + Qt::SHIFT + Qt::Key_F10);
346
    connect(menuAction, &QAction::triggered, this, &Konsole::MainWindow::activateMenuBar);
347 348
}

349
void MainWindow::viewFullScreen(bool fullScreen)
350
{
Kurt Hindenburg's avatar
Kurt Hindenburg committed
351 352
    if (fullScreen)
        setWindowState(windowState() | Qt::WindowFullScreen);
353
    else
Kurt Hindenburg's avatar
Kurt Hindenburg committed
354
        setWindowState(windowState() & ~Qt::WindowFullScreen);
355
}
356

357
BookmarkHandler* MainWindow::bookmarkHandler() const
358 359 360 361
{
    return _bookmarkHandler;
}

Jekyll Wu's avatar
Jekyll Wu committed
362
void MainWindow::setProfileList(ProfileList* list)
363
{
364
    profileListChanged(list->actions());
365

Laurent Montel's avatar
Laurent Montel committed
366
    connect(list, &Konsole::ProfileList::profileSelected, this, &Konsole::MainWindow::newFromProfile);
367

Laurent Montel's avatar
Laurent Montel committed
368
    connect(list, &Konsole::ProfileList::actionsChanged, this, &Konsole::MainWindow::profileListChanged);
369 370
}

371
void MainWindow::profileListChanged(const QList<QAction*>& sessionActions)
372
{
373 374
    // If only 1 profile is to be shown in the menu, only display
    // it if it is the non-default profile.
375
    if (sessionActions.size() > 2) {
376
        // Update the 'New Tab' KActionMenu
377
        if (_newTabMenuAction->menu() != nullptr) {
378 379 380 381
            _newTabMenuAction->menu()->clear();
        } else {
            _newTabMenuAction->setMenu(new QMenu());
        }
382
        foreach(QAction* sessionAction, sessionActions) {
383
            _newTabMenuAction->menu()->addAction(sessionAction);
384

385
            // NOTE: defaultProfile seems to not work here, sigh.
386
            Profile::Ptr profile = ProfileManager::instance()->defaultProfile();
387
            if (profile && profile->name() == sessionAction->text().remove('&')) {
388
                QIcon icon(KIconLoader::global()->loadIcon(profile->icon(), KIconLoader::Small, 0, KIconLoader::DefaultState, QStringList(QStringLiteral("emblem-favorite"))));
Michal Humpula's avatar
Michal Humpula committed
389
                sessionAction->setIcon(icon);
390
                _newTabMenuAction->menu()->setDefaultAction(sessionAction);
391 392 393
                QFont actionFont = sessionAction->font();
                actionFont.setBold(true);
                sessionAction->setFont(actionFont);
394
            }
395
        }
Kurt Hindenburg's avatar
Kurt Hindenburg committed
396
    } else {
397
        if (_newTabMenuAction->menu() != nullptr) {
398 399 400 401
            _newTabMenuAction->menu()->clear();
        } else {
           _newTabMenuAction->setMenu(new QMenu());
        }
402
        Profile::Ptr profile = ProfileManager::instance()->defaultProfile();
403

404
        // NOTE: Compare names w/o any '&'
405
        if (sessionActions.size() == 2 &&  sessionActions[1]->text().remove('&') != profile->name()) {
406
            _newTabMenuAction->menu()->addAction(sessionActions[1]);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
407
        } else {
408
            _newTabMenuAction->menu()->deleteLater();
409 410
        }
    }
411 412
}

413 414
QString MainWindow::activeSessionDir() const
{
415
    if (_pluggedController != nullptr) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
416
        if (Session* session = _pluggedController->session()) {
417 418 419 420
            // For new tabs to get the correct working directory,
            // force the updating of the currentWorkingDirectory.
            session->getDynamicTitle();
        }
421
        return _pluggedController->currentDir();
Kurt Hindenburg's avatar
Kurt Hindenburg committed
422
    } else {
423
        return QString();
424
    }
425 426
}

Alex Richardson's avatar
Alex Richardson committed
427
void MainWindow::openUrls(const QList<QUrl>& urls)
428
{
429
    Profile::Ptr defaultProfile = ProfileManager::instance()->defaultProfile();
430

431
    Q_FOREACH (const auto& url, urls) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
432
        if (url.isLocalFile())
Kurt Hindenburg's avatar
Kurt Hindenburg committed
433
            createSession(defaultProfile, url.path());
434

435
        else if (url.scheme() == QLatin1String("ssh"))
Kurt Hindenburg's avatar
Kurt Hindenburg committed
436
            createSSHSession(defaultProfile, url);
437
    }
438 439
}

440
void MainWindow::newTab()
441
{
442
    Profile::Ptr defaultProfile = ProfileManager::instance()->defaultProfile();
Kurt Hindenburg's avatar
Kurt Hindenburg committed
443
    createSession(defaultProfile, activeSessionDir());
444 445
}

446 447 448 449 450 451
void MainWindow::cloneTab()
{
    Q_ASSERT(_pluggedController);

    Session* session = _pluggedController->session();
    Profile::Ptr profile = SessionManager::instance()->sessionProfile(session);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
452 453
    if (profile) {
        createSession(profile, activeSessionDir());
454
    } else {
455 456 457 458 459 460
        // something must be wrong: every session should be associated with profile
        Q_ASSERT(false);
        newTab();
    }
}

461 462 463
Session* MainWindow::createSession(Profile::Ptr profile, const QString& directory)
{
    if (!profile)
464
        profile = ProfileManager::instance()->defaultProfile();
465 466 467

    Session* session = SessionManager::instance()->createSession(profile);

Kurt Hindenburg's avatar
Kurt Hindenburg committed
468
    if (!directory.isEmpty() && profile->startInCurrentSessionDir())
469 470
        session->setInitialWorkingDirectory(directory);

471
    session->addEnvironmentEntry(QStringLiteral("KONSOLE_DBUS_WINDOW=/Windows/%1").arg(_viewManager->managerId()));
472 473 474 475 476

    // create view before starting the session process so that the session
    // doesn't suffer a change in terminal size right after the session
    // starts.  Some applications such as GNU Screen and Midnight Commander
    // don't like this happening
477
    createView(session);
478 479 480 481

    return session;
}

Kurt Hindenburg's avatar
Kurt Hindenburg committed
482
Session* MainWindow::createSSHSession(Profile::Ptr profile, const QUrl& url)
483 484
{
    if (!profile)
485
        profile = ProfileManager::instance()->defaultProfile();
486 487 488

    Session* session = SessionManager::instance()->createSession(profile);

489
    QString sshCommand = QStringLiteral("ssh ");
490
    if (url.port() > -1) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
491
        sshCommand += QStringLiteral("-p %1 ").arg(url.port());
492
    }
Kurt Hindenburg's avatar
Kurt Hindenburg committed
493 494
    if (!url.userName().isEmpty()) {
        sshCommand += (url.userName() + '@');
495
    }
Kurt Hindenburg's avatar
Kurt Hindenburg committed
496
    if (!url.host().isEmpty()) {
497 498 499
        sshCommand += url.host();
    }

500
    session->sendTextToTerminal(sshCommand, '\r');
501 502 503 504 505

    // create view before starting the session process so that the session
    // doesn't suffer a change in terminal size right after the session
    // starts.  some applications such as GNU Screen and Midnight Commander
    // don't like this happening
506
    createView(session);
507 508 509 510

    return session;
}

511 512 513 514 515 516 517 518 519 520
void MainWindow::createView(Session* session)
{
    _viewManager->createView(session);
}

void MainWindow::setFocus()
{
    _viewManager->activeView()->setFocus();
}

521
void MainWindow::newWindow()
522
{
523
    Profile::Ptr defaultProfile = ProfileManager::instance()->defaultProfile();
Kurt Hindenburg's avatar
Kurt Hindenburg committed
524
    emit newWindowRequest(defaultProfile, activeSessionDir());
525 526
}

527 528
bool MainWindow::queryClose()
{
529 530 531
    // Do not ask for confirmation during log out and power off
    // TODO: rework the dealing of this case to make it has its own confirmation
    // dialog.
532
    if (qApp->isSavingSession()) {
533 534 535
        return true;
    }

536
    // Check what processes are running, excluding the shell
537 538
    QStringList processesRunning;
    foreach(Session *session, _viewManager->sessions()) {
539
        if ((session == nullptr) || !session->isForegroundProcessActive()) {
540
            continue;
541
        }
542 543 544

        const QString defaultProc = session->program().split('/').last();
        const QString currentProc = session->foregroundProcessName().split('/').last();
545 546 547 548

        if (currentProc.isEmpty())
            continue;

549 550 551 552
        if (defaultProc != currentProc) {
            processesRunning.append(currentProc);
        }
    }
553 554 555 556 557 558

    // Get number of open tabs
    const int openTabs = _viewManager->viewProperties().count();

    // If no processes running (except the shell) and no extra tabs, just close
    if (processesRunning.count() == 0 && openTabs < 2) {
559
        return true;
560
    }
561

562 563 564
    // NOTE: Some, if not all, of the below KWindowSystem calls are only
    //       implemented under x11 (KDE4.8 kdelibs/kdeui/windowmanagement).

565 566
    // make sure the window is shown on current desktop and is not minimized
    KWindowSystem::setOnDesktop(winId(), KWindowSystem::currentDesktop());
567
    if (isMinimized()) {
568 569
        KWindowSystem::unminimizeWindow(winId(), true);
    }
570 571 572 573 574 575 576 577 578
    int result;

    if (processesRunning.count() > 0) {
        result = KMessageBox::warningYesNoCancelList(this,
                     i18ncp("@info", "There is a process running in this window. "
                                     "Do you still want to quit?",
                            "There are %1 processes running in this window. "
                            "Do you still want to quit?",
                            processesRunning.count()),
579
                 processesRunning,
580
                 i18nc("@title", "Confirm Close"),
581 582
                 KGuiItem(i18nc("@action:button", "Close &Window"), QStringLiteral("window-close")),
                 KGuiItem(i18nc("@action:button", "Close Current &Tab"), QStringLiteral("tab-close")),
Kurt Hindenburg's avatar
Kurt Hindenburg committed
583
                 KStandardGuiItem::cancel(),
584
                 QStringLiteral("CloseAllTabs"));
585 586 587 588 589 590 591 592 593 594 595 596 597
    } else {
        result = KMessageBox::warningYesNoCancel(this,
                    i18nc("@info",
                           "There are %1 open tabs in this window. "
                           "Do you still want to quit?",
                           openTabs),
                    i18nc("@title", "Confirm Close"),
                    KGuiItem(i18nc("@action:button", "Close &Window"), QStringLiteral("window-close")),
                    KGuiItem(i18nc("@action:button", "Close Current &Tab"), QStringLiteral("tab-close")),
                    KStandardGuiItem::cancel(),
                    QStringLiteral("CloseAllEmptyTabs"));

    }
Kurt Hindenburg's avatar
Kurt Hindenburg committed
598 599

    switch (result) {
600 601 602
    case KMessageBox::Yes:
        return true;
    case KMessageBox::No:
603
        if ((_pluggedController != nullptr) && (_pluggedController->session() != nullptr)) {
604
            disconnectController(_pluggedController);
605
            _pluggedController->session()->closeInNormalWay();
606
        }
607 608 609
        return false;
    case KMessageBox::Cancel:
        return false;
610 611 612 613
    }

    return true;
}
Robert Knight's avatar
 
Robert Knight committed
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634

void MainWindow::saveProperties(KConfigGroup& group)
{
    _viewManager->saveSessions(group);
}

void MainWindow::readProperties(const KConfigGroup& group)
{
    _viewManager->restoreSessions(group);
}

void MainWindow::saveGlobalProperties(KConfig* config)
{
    SessionManager::instance()->saveSessions(config);
}

void MainWindow::readGlobalProperties(KConfig* config)
{
    SessionManager::instance()->restoreSessions(config);
}

635 636
void MainWindow::syncActiveShortcuts(KActionCollection* dest, const KActionCollection* source)
{
637
    foreach(QAction *qAction, source->actions()) {
638 639
        if (QAction *destQAction = dest->action(qAction->objectName())) {
            destQAction->setShortcut(qAction->shortcut());
640 641 642
        }
    }
}
643

644
void MainWindow::showShortcutsDialog()
645
{
646 647 648
    KShortcutsDialog dialog(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsDisallowed, this);

    // add actions from this window and the current session controller
Jekyll Wu's avatar
Jekyll Wu committed
649 650 651
    foreach(KXMLGUIClient * client, guiFactory()->clients()) {
        dialog.addCollection(client->actionCollection());
    }
652

Kurt Hindenburg's avatar
Kurt Hindenburg committed
653
    if (dialog.configure()) {
654
        // sync shortcuts for non-session actions (defined in "konsoleui.rc") in other main windows
655 656
        foreach(QWidget* mainWindowWidget, QApplication::topLevelWidgets()) {
            MainWindow* mainWindow = qobject_cast<MainWindow*>(mainWindowWidget);
657
            if ((mainWindow != nullptr) && mainWindow != this)
658
                syncActiveShortcuts(mainWindow->actionCollection(), actionCollection());
659
        }
660
        // sync shortcuts for session actions (defined in "sessionui.rc") in other session controllers.
661 662 663
        // Controllers which are currently plugged in (ie. their actions are part of the current menu)
        // must be updated immediately via syncActiveShortcuts().  Other controllers will be updated
        // when they are plugged into a main window.
Kurt Hindenburg's avatar
Kurt Hindenburg committed
664
        foreach(SessionController * controller, SessionController::allControllers()) {
665
            controller->reloadXML();
666
            if ((controller->factory() != nullptr) && controller != _pluggedController)
Kurt Hindenburg's avatar
Kurt Hindenburg committed
667
                syncActiveShortcuts(controller->actionCollection(), _pluggedController->actionCollection());
668 669
        }
    }
670 671
}

672
void MainWindow::newFromProfile(Profile::Ptr profile)
673
{
Kurt Hindenburg's avatar
Kurt Hindenburg committed
674
    createSession(profile, activeSessionDir());
675
}
676
void MainWindow::showManageProfilesDialog()
677
{
678
    showSettingsDialog(true);
679
}
680

681
void MainWindow::showSettingsDialog(const bool showProfilePage)
Jekyll Wu's avatar
Jekyll Wu committed
682
{
683
    if (KConfigDialog::showDialog(QStringLiteral("settings")))
Jekyll Wu's avatar
Jekyll Wu committed
684 685
        return;

686
    KConfigDialog* settingsDialog = new KConfigDialog(this, QStringLiteral("settings"), KonsoleSettings::self());
687
    settingsDialog->setFaceType(KPageDialog::Tabbed);
Jekyll Wu's avatar
Jekyll Wu committed
688

Kurt Hindenburg's avatar
Kurt Hindenburg committed
689
    auto generalSettings = new GeneralSettings(settingsDialog);
Jekyll Wu's avatar
Jekyll Wu committed
690 691
    settingsDialog->addPage(generalSettings,
                            i18nc("@title Preferences page name", "General"),
692
                            QStringLiteral("utilities-terminal"));
Jekyll Wu's avatar
Jekyll Wu committed
693

Kurt Hindenburg's avatar
Kurt Hindenburg committed
694
    auto profileSettings = new ProfileSettings(settingsDialog);
695 696
    KPageWidgetItem* profilePage = settingsDialog->addPage(profileSettings,
                            i18nc("@title Preferences page name", "Profiles"),
697
                            QStringLiteral("configure"));
698

Kurt Hindenburg's avatar
Kurt Hindenburg committed
699
    auto tabBarSettings = new TabBarSettings(settingsDialog);
Jekyll Wu's avatar
Jekyll Wu committed
700 701
    settingsDialog->addPage(tabBarSettings,
                            i18nc("@title Preferences page name", "TabBar"),
702
                            QStringLiteral("system-run"));
Jekyll Wu's avatar
Jekyll Wu committed
703

Kurt Hindenburg's avatar
Kurt Hindenburg committed
704
    auto fileLocationSettings = new FileLocationSettings(settingsDialog);
705 706
    settingsDialog->addPage(fileLocationSettings,
                            i18nc("@title Preferences page name", "File Location"),
707
                            QStringLiteral("configure"));
708

709 710 711
    if (showProfilePage)
        settingsDialog->setCurrentPage(profilePage);

Jekyll Wu's avatar
Jekyll Wu committed
712 713 714
    settingsDialog->show();
}

Jekyll Wu's avatar
Jekyll Wu committed
715
void MainWindow::applyKonsoleSettings()
716
{
717 718
    setMenuBarInitialVisibility(KonsoleSettings::showMenuBarByDefault());

Kurt Hindenburg's avatar
Kurt Hindenburg committed
719
    if (KonsoleSettings::allowMenuAccelerators()) {
Jekyll Wu's avatar
Jekyll Wu committed
720
        restoreMenuAccelerators();
721
    } else {
722 723
        removeMenuAccelerators();
    }
724

725 726 727 728
    setNavigationVisibility(KonsoleSettings::tabBarVisibility());
    setNavigationPosition(KonsoleSettings::tabBarPosition());
    setNavigationBehavior(KonsoleSettings::newTabBehavior());
    setShowQuickButtons(KonsoleSettings::showQuickButtons());
729

730 731 732 733 734 735 736
    if (KonsoleSettings::tabBarUseUserStyleSheet()) {
        setNavigationStyleSheetFromFile(KonsoleSettings::tabBarUserStyleSheetFile());
    } else {
        // Apply default values
        setNavigationStyleSheet(KonsoleSettings::tabBarStyleSheet());
    }

737
    setAutoSaveSettings(QStringLiteral("MainWindow"), KonsoleSettings::saveGeometryOnExit());
738 739

    updateWindowCaption();
740 741
}

742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
void MainWindow::setNavigationVisibility(int visibility)
{
    _viewManager->setNavigationVisibility(visibility);
}

void MainWindow::setNavigationPosition(int position)
{
    _viewManager->setNavigationPosition(position);
}

void MainWindow::setNavigationStyleSheet(const QString& styleSheet)
{
    _viewManager->setNavigationStyleSheet(styleSheet);
}

void MainWindow::setNavigationBehavior(int behavior)
{
    _viewManager->setNavigationBehavior(behavior);
}

Kurt Hindenburg's avatar
Kurt Hindenburg committed
762
void MainWindow::setNavigationStyleSheetFromFile(const QUrl& styleSheetFile)
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
{
    // Let's only deal w/ local files for now
    if (!styleSheetFile.isLocalFile()) {
        setNavigationStyleSheet(KonsoleSettings::tabBarStyleSheet());
    }

    QFile file(styleSheetFile.toLocalFile());
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        setNavigationStyleSheet(KonsoleSettings::tabBarStyleSheet());
    }

    QString styleSheetText;
    QTextStream in(&file);
    while (!in.atEnd()) {
        styleSheetText.append(in.readLine());
    }

    // Replace current style sheet w/ loaded file
    setNavigationStyleSheet(styleSheetText);
}

784 785 786 787 788
void MainWindow::setShowQuickButtons(bool show)
{
    _viewManager->setShowQuickButtons(show);
}

789 790
void MainWindow::activateMenuBar()
{
791
    const QList<QAction*> menuActions = menuBar()->actions();
792

793 794 795
    if (menuActions.isEmpty())
        return;

796 797
    // Show menubar if it is hidden at the moment
    if (menuBar()->isHidden()) {
798
        menuBar()->setVisible(true);
799
        _toggleMenuBarAction->setChecked(true);
800 801
    }

802 803 804
    // First menu action should be 'File'
    QAction* menuAction = menuActions.first();

805
    // TODO: Handle when menubar is top level (MacOS)
806
    menuBar()->setActiveAction(menuAction);
807 808
}

Jekyll Wu's avatar