Fix crash if key bindings specified in profile cannot be found. Improve
[personal-kdebase.git] / apps / konsole / src / MainWindow.cpp
blobfdb071ab979452e1c33fc90226e5d84315c6cf75
1 /*
2 Copyright 2006-2008 by Robert Knight <robertknight@gmail.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301 USA.
20 // Own
21 #include "MainWindow.h"
22 #include "SessionManager.h"
24 // Qt
25 #include <QtGui/QBoxLayout>
27 // KDE
28 #include <KAcceleratorManager>
29 #include <KAction>
30 #include <KActionCollection>
31 #include <KActionMenu>
32 #include <KApplication>
33 #include <KShortcutsDialog>
34 #include <KLocale>
35 #include <KMenu>
36 #include <KMenuBar>
37 #include <KMessageBox>
38 #include <KService>
39 #include <KToggleAction>
40 #include <KToggleFullScreenAction>
41 #include <KToolInvocation>
42 #include <KStandardAction>
43 #include <KStandardGuiItem>
44 #include <KXMLGUIFactory>
45 #include <KNotifyConfigWidget>
47 // Konsole
48 #include "BookmarkHandler.h"
49 #include "IncrementalSearchBar.h"
50 #include "RemoteConnectionDialog.h"
51 #include "SessionController.h"
52 #include "ProfileList.h"
53 #include "ManageProfilesDialog.h"
54 #include "Session.h"
55 #include "ViewManager.h"
56 #include "ViewSplitter.h"
58 using namespace Konsole;
60 MainWindow::MainWindow()
61 : KXmlGuiWindow() ,
62 _bookmarkHandler(0),
63 _pluggedController(0),
64 _menuBarVisibilitySet(false)
66 // create actions for menus
67 // the directory ('konsole') is included in the path here so that the XML
68 // file can be found when this code is being used in the Konsole part.
69 setXMLFile("konsole/konsoleui.rc");
70 setupActions();
72 // create view manager
73 _viewManager = new ViewManager(this,actionCollection());
74 connect( _viewManager , SIGNAL(empty()) , this , SLOT(close()) );
75 connect( _viewManager , SIGNAL(activeViewChanged(SessionController*)) , this ,
76 SLOT(activeViewChanged(SessionController*)) );
77 connect( _viewManager , SIGNAL(viewPropertiesChanged(const QList<ViewProperties*>&)) ,
78 bookmarkHandler() , SLOT(setViews(const QList<ViewProperties*>&)) );
80 connect( _viewManager , SIGNAL(setMenuBarVisibleRequest(bool)) , this ,
81 SLOT(setMenuBarVisibleOnce(bool)) );
82 connect( _viewManager , SIGNAL(newViewRequest(Profile::Ptr)) ,
83 this , SLOT(newFromProfile(Profile::Ptr)) );
84 connect( _viewManager , SIGNAL(newViewRequest()) ,
85 this , SLOT(newTab()));
87 // create main window widgets
88 setupWidgets();
90 // disable automatically generated accelerators in top-level
91 // menu items - to avoid conflicting with Alt+[Letter] shortcuts
92 // in terminal applications
93 KAcceleratorManager::setNoAccel(menuBar());
94 // create menus
95 createGUI();
96 // remove accelerators for standard menu items (eg. &File, &View, &Edit)
97 // etc. which are defined in kdelibs/kdeui/xmlgui/ui_standards.rc, again,
98 // to avoid conflicting with Alt+[Letter] terminal shortcuts
100 // TODO - Modify XMLGUI so that it allows the text for standard actions
101 // defined in ui_standards.rc to be re-defined in the local application
102 // XMLGUI file (konsoleui.rc in this case) - the text for standard items
103 // can then be redefined there to exclude the standard accelerators
104 removeMenuAccelerators();
105 // replace standard shortcuts which cannot be used in a terminal
106 // (as they are reserved for use by terminal programs)
107 correctShortcuts();
109 // enable save and restore of window size
110 setAutoSaveSettings("MainWindow",true);
112 void MainWindow::removeMenuAccelerators()
114 foreach(QAction* menuItem, menuBar()->actions())
116 QString itemText = menuItem->text();
117 itemText = KGlobal::locale()->removeAcceleratorMarker(itemText);
118 menuItem->setText(itemText);
121 void MainWindow::setMenuBarVisibleOnce(bool visible)
123 if (_menuBarVisibilitySet || menuBar()->isTopLevelMenu() )
124 return;
126 menuBar()->setVisible(visible);
127 _toggleMenuBarAction->setChecked(visible);
129 _menuBarVisibilitySet = true;
132 void MainWindow::correctShortcuts()
134 // replace F1 shortcut for help contents
135 QAction* helpAction = actionCollection()->action("help_contents");
137 Q_ASSERT( helpAction );
139 helpAction->setShortcut(QKeySequence());
141 // replace Ctrl+B shortcut for bookmarks
142 // TODO - Make this configurable
143 QAction* bookmarkAction = actionCollection()->action("add_bookmark");
144 Q_ASSERT(bookmarkAction);
145 bookmarkAction->setShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_B));
148 void MainWindow::setDefaultProfile(Profile::Ptr profile)
150 _defaultProfile = profile;
152 Profile::Ptr MainWindow::defaultProfile() const
154 return _defaultProfile;
157 ViewManager* MainWindow::viewManager() const
159 return _viewManager;
162 void MainWindow::disconnectController(SessionController* controller)
164 disconnect( controller , SIGNAL(titleChanged(ViewProperties*))
165 , this , SLOT(activeViewTitleChanged(ViewProperties*)) );
167 // KXmlGuiFactory::removeClient() will try to access actions associated
168 // with the controller internally, which may not be valid after the controller
169 // itself is no longer valid (after the associated session and or view have
170 // been destroyed)
171 if (controller->isValid())
172 guiFactory()->removeClient(controller);
174 controller->setSearchBar(0);
177 void MainWindow::activeViewChanged(SessionController* controller)
179 // associate bookmark menu with current session
180 bookmarkHandler()->setActiveView(controller);
181 disconnect( bookmarkHandler() , SIGNAL(openUrl(const KUrl&)) , 0 , 0 );
182 connect( bookmarkHandler() , SIGNAL(openUrl(const KUrl&)) , controller ,
183 SLOT(openUrl(const KUrl&)) );
185 if ( _pluggedController )
186 disconnectController(_pluggedController);
188 // listen for title changes from the current session
189 Q_ASSERT( controller );
191 connect( controller , SIGNAL(titleChanged(ViewProperties*)) ,
192 this , SLOT(activeViewTitleChanged(ViewProperties*)) );
194 controller->setShowMenuAction( _toggleMenuBarAction );
195 guiFactory()->addClient(controller);
197 // set the current session's search bar
198 controller->setSearchBar( searchBar() );
200 // update session title to match newly activated session
201 activeViewTitleChanged(controller);
203 _pluggedController = controller;
206 void MainWindow::activeViewTitleChanged(ViewProperties* properties)
208 setPlainCaption(properties->title());
211 IncrementalSearchBar* MainWindow::searchBar() const
213 return _viewManager->searchBar();
216 void MainWindow::setupActions()
218 KActionCollection* collection = actionCollection();
220 // File Menu
221 KAction* newTabAction = collection->addAction("new-tab");
222 newTabAction->setIcon( KIcon("tab-new") );
223 newTabAction->setText( i18n("New &Tab") );
224 newTabAction->setShortcut( QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_N) );
225 connect( newTabAction , SIGNAL(triggered()) , this , SLOT(newTab()) );
227 KAction* newWindowAction = collection->addAction("new-window");
228 newWindowAction->setIcon( KIcon("window-new") );
229 newWindowAction->setText( i18n("New &Window") );
230 newWindowAction->setShortcut( QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_M) );
231 connect( newWindowAction , SIGNAL(triggered()) , this , SLOT(newWindow()) );
233 KAction* remoteConnectionAction = collection->addAction("remote-connection");
234 remoteConnectionAction->setText( i18n("Remote Connection...") );
235 remoteConnectionAction->setIcon( KIcon("network-connect") );
236 remoteConnectionAction->setShortcut( QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_R) );
237 connect( remoteConnectionAction , SIGNAL(triggered()) , this , SLOT(showRemoteConnectionDialog()) );
239 KAction* quitAction = KStandardAction::quit( this , SLOT(close()) , collection );
240 // the default shortcut for quit is typically Ctrl+[Some Letter, usually Q] but that is reserved for
241 // use by terminal applications
242 quitAction->setShortcut(Qt::CTRL+Qt::SHIFT+Qt::Key_Q);
244 // Bookmark Menu
245 KActionMenu* bookmarkMenu = new KActionMenu(i18n("&Bookmarks") , collection );
246 _bookmarkHandler = new BookmarkHandler( collection , bookmarkMenu->menu() , true , this );
247 collection->addAction("bookmark" , bookmarkMenu);
249 connect( _bookmarkHandler , SIGNAL(openUrls(QList<KUrl>)) , this , SLOT(openUrls(QList<KUrl>)) );
251 //TODO - The 'Add Bookmark' menu action currently has a Ctrl+B shortcut by
252 // default which cannot be overridden
254 // View Menu
255 _toggleMenuBarAction = new KToggleAction(this);
256 _toggleMenuBarAction->setText( i18n("Show Menu Bar") );
257 _toggleMenuBarAction->setIcon( KIcon("show-menu") );
258 _toggleMenuBarAction->setChecked( !menuBar()->isHidden() );
259 connect( _toggleMenuBarAction , SIGNAL(toggled(bool)) , menuBar() , SLOT(setVisible(bool)) );
260 collection->addAction("show-menubar",_toggleMenuBarAction);
262 // Hide the Show/Hide menubar item if the menu bar is a MacOS-style menu bar
263 if ( menuBar()->isTopLevelMenu() )
264 _toggleMenuBarAction->setVisible(false);
266 // Full Screen
267 KToggleFullScreenAction* fullScreenAction = new KToggleFullScreenAction(this);
268 fullScreenAction->setWindow(this);
269 fullScreenAction->setShortcut( Qt::CTRL + Qt::SHIFT + Qt::Key_F11 );
270 collection->addAction("view-full-screen",fullScreenAction);
271 connect( fullScreenAction , SIGNAL(toggled(bool)) , this , SLOT(viewFullScreen(bool)) );
273 // Settings Menu
274 KStandardAction::configureNotifications( this , SLOT(configureNotifications()) , collection );
275 KStandardAction::keyBindings( this , SLOT(showShortcutsDialog()) , collection );
277 KAction* manageProfilesAction = collection->addAction("manage-profiles");
278 manageProfilesAction->setText( i18n("Manage Profiles...") );
279 manageProfilesAction->setIcon( KIcon("configure") );
280 connect( manageProfilesAction , SIGNAL(triggered()) , this , SLOT(showManageProfilesDialog()) );
284 void MainWindow::viewFullScreen(bool fullScreen)
286 if ( fullScreen )
287 setWindowState( windowState() | Qt::WindowFullScreen );
288 else
289 setWindowState( windowState() & ~Qt::WindowFullScreen );
292 BookmarkHandler* MainWindow::bookmarkHandler() const
294 return _bookmarkHandler;
297 void MainWindow::setSessionList(ProfileList* list)
299 sessionListChanged(list->actions());
301 connect( list , SIGNAL(profileSelected(Profile::Ptr)) , this ,
302 SLOT(newFromProfile(Profile::Ptr)) );
304 connect( list , SIGNAL(actionsChanged(const QList<QAction*>&)) , this ,
305 SLOT(sessionListChanged(const QList<QAction*>&)) );
308 void MainWindow::sessionListChanged(const QList<QAction*>& actions)
310 unplugActionList("favorite-profiles");
311 plugActionList("favorite-profiles",actions);
314 QString MainWindow::activeSessionDir() const
316 if ( _pluggedController )
317 return _pluggedController->currentDir();
318 else
319 return QString();
322 void MainWindow::openUrls(const QList<KUrl>& urls)
324 // TODO Implement support for SSH bookmarks here
325 foreach( const KUrl& url , urls )
327 if ( url.isLocalFile() )
328 emit newSessionRequest( _defaultProfile , url.path() , _viewManager );
332 void MainWindow::newTab()
334 emit newSessionRequest( _defaultProfile , activeSessionDir() , _viewManager);
337 void MainWindow::newWindow()
339 emit newWindowRequest( _defaultProfile , activeSessionDir() );
342 bool MainWindow::queryClose()
344 if (kapp->sessionSaving() ||
345 _viewManager->viewProperties().count() < 2)
346 return true;
348 int result = KMessageBox::warningYesNoCancel(this,
349 i18n("You have multiple tabs in this window, "
350 "are you sure you want to quit?"),
351 i18n("Confirm Close"),
352 KStandardGuiItem::quit(),
353 KGuiItem(i18n("Close Current Tab"), "tab-close"),
354 KStandardGuiItem::cancel(),
355 "CloseAllTabs");
357 switch (result)
359 case KMessageBox::Yes:
360 return true;
361 case KMessageBox::No:
362 if (_pluggedController && _pluggedController->session())
364 disconnectController(_pluggedController);
365 _pluggedController->session()->close();
367 return false;
368 case KMessageBox::Cancel:
369 return false;
372 return true;
375 void MainWindow::saveProperties(KConfigGroup& group)
377 if (_defaultProfile)
378 group.writePathEntry("Default Profile", _defaultProfile->path());
379 _viewManager->saveSessions(group);
382 void MainWindow::readProperties(const KConfigGroup& group)
384 SessionManager *manager = SessionManager::instance();
385 QString profilePath = group.readPathEntry("Default Profile", QString());
386 Profile::Ptr profile = manager->defaultProfile();
387 if (!profilePath.isEmpty())
388 profile = manager->loadProfile(profilePath);
389 setDefaultProfile(profile);
390 _viewManager->restoreSessions(group);
393 void MainWindow::saveGlobalProperties(KConfig* config)
395 SessionManager::instance()->saveSessions(config);
398 void MainWindow::readGlobalProperties(KConfig* config)
400 SessionManager::instance()->restoreSessions(config);
403 void MainWindow::syncActiveShortcuts(KActionCollection* dest, const KActionCollection* source)
405 foreach(QAction* qAction, source->actions())
407 if (KAction* kAction = qobject_cast<KAction*>(qAction))
409 if (KAction* destKAction = qobject_cast<KAction*>(dest->action(kAction->objectName())))
410 destKAction->setShortcut(kAction->shortcut(KAction::ActiveShortcut),KAction::ActiveShortcut);
414 void MainWindow::showShortcutsDialog()
416 KShortcutsDialog dialog(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsDisallowed, this);
418 // add actions from this window and the current session controller
419 foreach(KXMLGUIClient* client, guiFactory()->clients())
420 dialog.addCollection(client->actionCollection());
422 if (dialog.configure())
424 // sync shortcuts for non-session actions (defined in "konsoleui.rc") in other main windows
425 foreach(QWidget* widget, QApplication::topLevelWidgets())
427 MainWindow* window = qobject_cast<MainWindow*>(widget);
428 if (window && window != this)
429 syncActiveShortcuts(window->actionCollection(),actionCollection());
431 // sync shortcuts for session actions (defined in "sessionui.rc") in other session controllers.
432 // Controllers which are currently plugged in (ie. their actions are part of the current menu)
433 // must be updated immediately via syncActiveShortcuts(). Other controllers will be updated
434 // when they are plugged into a main window.
435 foreach(SessionController* controller, SessionController::allControllers())
437 controller->reloadXML();
438 if (controller->factory() && controller != _pluggedController)
439 syncActiveShortcuts(controller->actionCollection(),_pluggedController->actionCollection());
444 void MainWindow::newFromProfile(Profile::Ptr profile)
446 emit newSessionRequest(profile, activeSessionDir(), _viewManager);
448 void MainWindow::showManageProfilesDialog()
450 ManageProfilesDialog* dialog = new ManageProfilesDialog(this);
451 dialog->show();
454 void MainWindow::showRemoteConnectionDialog()
456 // RemoteConnectionDialog dialog(this);
457 // if ( dialog.exec() == QDialog::Accepted )
458 // emit newSessionRequest(dialog.sessionKey(),QString(),_viewManager);
461 void MainWindow::setupWidgets()
463 QWidget* widget = new QWidget(this);
464 QVBoxLayout* layout = new QVBoxLayout();
466 layout->addWidget( _viewManager->widget() );
467 layout->setMargin(0);
468 layout->setSpacing(0);
470 widget->setLayout(layout);
472 setCentralWidget(widget);
475 void MainWindow::configureNotifications()
477 KNotifyConfigWidget::configure( this );
480 #include "MainWindow.moc"
483 Local Variables:
484 mode: c++
485 c-file-style: "stroustrup"
486 indent-tabs-mode: nil
487 tab-width: 4
488 End: