Show invite menu in wlm chat window immediately
[kdenetwork.git] / krdc / mainwindow.cpp
blobfa9e613bed5e187b95a5437f6ed1d757d3d87256
1 /****************************************************************************
2 **
3 ** Copyright (C) 2007 - 2009 Urs Wolfer <uwolfer @ kde.org>
4 **
5 ** This file is part of KDE.
6 **
7 ** This program is free software; you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License as published by
9 ** the Free Software Foundation; either version 2 of the License, or
10 ** (at your option) any later version.
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; see the file COPYING. If not, write to
19 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 ** Boston, MA 02110-1301, USA.
22 ****************************************************************************/
24 #include "mainwindow.h"
26 #include "remoteview.h"
27 #include "settings.h"
28 #include "config/preferencesdialog.h"
29 #include "floatingtoolbar.h"
30 #include "bookmarkmanager.h"
31 #include "remotedesktopsmodel.h"
32 #include "systemtrayicon.h"
33 #include "hostpreferences.h"
35 #ifdef BUILD_ZEROCONF
36 #include "zeroconf/zeroconfpage.h"
37 #endif
39 #include <KAction>
40 #include <KActionCollection>
41 #include <KActionMenu>
42 #include <KApplication>
43 #include <KComboBox>
44 #include <KEditToolBar>
45 #include <KIcon>
46 #include <KLocale>
47 #include <KMenu>
48 #include <KMenuBar>
49 #include <KMessageBox>
50 #include <KNotifyConfigWidget>
51 #include <KPluginInfo>
52 #include <KPushButton>
53 #include <KShortcut>
54 #include <KShortcutsDialog>
55 #include <KStatusBar>
56 #include <KTabWidget>
57 #include <KToggleAction>
58 #include <KToggleFullScreenAction>
59 #include <KUrlNavigator>
60 #include <KServiceTypeTrader>
61 #include <KStandardDirs>
63 #include <QClipboard>
64 #include <QCloseEvent>
65 #include <QDesktopWidget>
66 #include <QDockWidget>
67 #include <QFontMetrics>
68 #include <QHeaderView>
69 #include <QLabel>
70 #include <QLayout>
71 #include <QScrollArea>
72 #include <QTimer>
73 #include <QToolButton>
74 #include <QToolTip>
75 #include <QTreeView>
77 MainWindow::MainWindow(QWidget *parent)
78 : KXmlGuiWindow(parent),
79 m_fullscreenWindow(0),
80 m_toolBar(0),
81 m_topBottomBorder(0),
82 m_leftRightBorder(0),
83 m_currentRemoteView(-1),
84 m_showStartPage(false),
85 m_systemTrayIcon(0),
86 m_zeroconfPage(0)
88 loadAllPlugins();
90 setupActions();
92 setStandardToolBarMenuEnabled(true);
94 m_tabWidget = new KTabWidget(this);
95 m_tabWidget->setTabBarHidden(!Settings::showTabBar());
96 m_tabWidget->setTabPosition((KTabWidget::TabPosition) Settings::tabPosition());
98 #if QT_VERSION <= 0x040500
99 m_tabWidget->setTabsClosable(Settings::tabCloseButton());
100 #else
101 m_tabWidget->setCloseButtonEnabled(Settings::tabCloseButton());
102 #endif
104 connect(m_tabWidget, SIGNAL(closeRequest(QWidget *)), SLOT(closeTab(QWidget *)));
106 if (Settings::tabMiddleClick())
107 connect(m_tabWidget, SIGNAL(mouseMiddleClick(QWidget *)), SLOT(closeTab(QWidget *)));
109 connect(m_tabWidget, SIGNAL(mouseDoubleClick(QWidget *)), SLOT(openTabSettings(QWidget *)));
110 connect(m_tabWidget, SIGNAL(contextMenu(QWidget *, const QPoint &)), SLOT(tabContextMenu(QWidget *, const QPoint &)));
112 m_tabWidget->setMinimumSize(600, 400);
113 setCentralWidget(m_tabWidget);
115 QDockWidget *remoteDesktopsDockWidget = new QDockWidget(this);
116 remoteDesktopsDockWidget->setObjectName("remoteDesktopsDockWidget"); // required for saving position / state
117 remoteDesktopsDockWidget->setWindowTitle(i18n("Remote desktops"));
118 QFontMetrics fontMetrics(remoteDesktopsDockWidget->font());
119 remoteDesktopsDockWidget->setMinimumWidth(fontMetrics.width("vnc://192.168.100.100:6000"));
120 actionCollection()->addAction("remote_desktop_dockwidget",
121 remoteDesktopsDockWidget->toggleViewAction());
122 m_remoteDesktopsTreeView = new QTreeView(remoteDesktopsDockWidget);
123 RemoteDesktopsModel *remoteDesktopsModel = new RemoteDesktopsModel(this);
124 connect(remoteDesktopsModel, SIGNAL(modelReset()), this, SLOT(expandTreeViewItems()));
125 m_remoteDesktopsTreeView->setModel(remoteDesktopsModel);
126 m_remoteDesktopsTreeView->header()->hide();
127 m_remoteDesktopsTreeView->expandAll();
128 m_remoteDesktopsTreeView->setItemsExpandable(false);
129 m_remoteDesktopsTreeView->setRootIsDecorated(false);
130 connect(m_remoteDesktopsTreeView, SIGNAL(doubleClicked(const QModelIndex &)),
131 SLOT(openFromDockWidget(const QModelIndex &)));
133 remoteDesktopsDockWidget->setWidget(m_remoteDesktopsTreeView);
134 addDockWidget(Qt::LeftDockWidgetArea, remoteDesktopsDockWidget);
136 createGUI("krdcui.rc");
138 if (Settings::systemTrayIcon()) {
139 m_systemTrayIcon = new SystemTrayIcon(this);
140 m_systemTrayIcon->setVisible(true);
143 connect(m_tabWidget, SIGNAL(currentChanged(int)), SLOT(tabChanged(int)));
145 statusBar()->showMessage(i18n("KDE Remote Desktop Client started"));
147 updateActionStatus(); // disable remote view actions
149 if (Settings::showStartPage())
150 createStartPage();
152 setAutoSaveSettings(); // e.g toolbar position, mainwindow size, ...
154 m_addressNavigator->setFocus();
156 if (Settings::rememberSessions()) // give some time to create and show the window first
157 QTimer::singleShot(100, this, SLOT(restoreOpenSessions()));
160 MainWindow::~MainWindow()
164 void MainWindow::setupActions()
166 foreach(RemoteViewFactory *factory, m_remoteViewFactories) {
167 QAction *connectionAction = actionCollection()->addAction("new_" + factory->scheme() + "_connection");
168 connectionAction->setProperty("schemeString", factory->scheme());
169 connectionAction->setProperty("toolTipString", factory->connectToolTipText());
170 connectionAction->setText(factory->connectActionText());
171 connectionAction->setIcon(KIcon("network-connect"));
172 connect(connectionAction, SIGNAL(triggered()), SLOT(newConnectionToolTip()));
175 QAction *zeroconfAction = actionCollection()->addAction("zeroconf_page");
176 zeroconfAction->setText(i18n("Browse Remote Desktop Services on Local Network..."));
177 zeroconfAction->setIcon(KIcon("network-connect"));
178 connect(zeroconfAction, SIGNAL(triggered()), SLOT(createZeroconfPage()));
179 #ifndef BUILD_ZEROCONF
180 zeroconfAction->deleteLater();
181 #endif
183 QAction *screenshotAction = actionCollection()->addAction("take_screenshot");
184 screenshotAction->setText(i18n("Copy Screenshot to Clipboard"));
185 screenshotAction->setIcon(KIcon("ksnapshot"));
186 connect(screenshotAction, SIGNAL(triggered()), SLOT(takeScreenshot()));
188 QAction *fullscreenAction = actionCollection()->addAction("switch_fullscreen");
189 fullscreenAction->setText(i18n("Switch to Fullscreen Mode"));
190 fullscreenAction->setIcon(KIcon("view-fullscreen"));
191 connect(fullscreenAction, SIGNAL(triggered()), SLOT(switchFullscreen()));
193 QAction *viewOnlyAction = actionCollection()->addAction("view_only");
194 viewOnlyAction->setCheckable(true);
195 viewOnlyAction->setText(i18n("View Only"));
196 viewOnlyAction->setIcon(KIcon("document-preview"));
197 connect(viewOnlyAction, SIGNAL(triggered(bool)), SLOT(viewOnly(bool)));
199 QAction *disconnectAction = actionCollection()->addAction("disconnect");
200 disconnectAction->setText(i18n("Disconnect"));
201 disconnectAction->setIcon(KIcon("system-log-out"));
202 disconnectAction->setShortcut(QKeySequence::Close);
203 connect(disconnectAction, SIGNAL(triggered()), SLOT(disconnectHost()));
205 QAction *showLocalCursorAction = actionCollection()->addAction("show_local_cursor");
206 showLocalCursorAction->setCheckable(true);
207 showLocalCursorAction->setIcon(KIcon("input-mouse"));
208 showLocalCursorAction->setText(i18n("Show Local Cursor"));
209 connect(showLocalCursorAction, SIGNAL(triggered(bool)), SLOT(showLocalCursor(bool)));
211 QAction *grabAllKeysAction = actionCollection()->addAction("grab_all_keys");
212 grabAllKeysAction->setCheckable(true);
213 grabAllKeysAction->setIcon(KIcon("configure-shortcuts"));
214 grabAllKeysAction->setText(i18n("Grab all possible keys"));
215 connect(grabAllKeysAction, SIGNAL(triggered(bool)), SLOT(grabAllKeys(bool)));
217 QAction *scaleAction = actionCollection()->addAction("scale");
218 scaleAction->setCheckable(true);
219 scaleAction->setIcon(KIcon("zoom-fit-best"));
220 scaleAction->setText(i18n("Scale remote screen to fit window size"));
221 connect(scaleAction, SIGNAL(triggered(bool)), SLOT(scale(bool)));
223 KStandardAction::quit(this, SLOT(quit()), actionCollection());
224 KStandardAction::preferences(this, SLOT(preferences()), actionCollection());
225 KStandardAction::configureToolbars(this, SLOT(configureToolbars()), actionCollection());
226 KStandardAction::keyBindings(this, SLOT(configureKeys()), actionCollection());
227 QAction *configNotifyAction = KStandardAction::configureNotifications(this, SLOT(configureNotifications()), actionCollection());
228 configNotifyAction->setVisible(false);
229 m_menubarAction = KStandardAction::showMenubar(this, SLOT(showMenubar()), actionCollection());
230 m_menubarAction->setChecked(!menuBar()->isHidden());
232 const QString initialProtocol(!m_remoteViewFactories.isEmpty() ? (*m_remoteViewFactories.begin())->scheme() : QString());
233 m_addressNavigator = new KUrlNavigator(0, KUrl(initialProtocol + "://"), this);
235 QStringList schemes;
236 foreach(RemoteViewFactory *factory, m_remoteViewFactories) {
237 schemes << factory->scheme();
239 m_addressNavigator->setCustomProtocols(schemes);
241 m_addressNavigator->setUrlEditable(Settings::normalUrlInputLine());
242 connect(m_addressNavigator, SIGNAL(returnPressed()), SLOT(newConnection()));
244 QLabel *addressLabel = new QLabel(i18n("Remote desktop:"), this);
246 QWidget *addressWidget = new QWidget(this);
247 QHBoxLayout *addressLayout = new QHBoxLayout(addressWidget);
248 addressLayout->setMargin(0);
249 addressLayout->addWidget(addressLabel);
250 addressLayout->addWidget(m_addressNavigator, 1);
252 KAction *addressLineAction = new KAction(i18nc("Title for remote address input action", "Address"), this);
253 actionCollection()->addAction("address_line", addressLineAction);
254 addressLineAction->setDefaultWidget(addressWidget);
256 QAction *gotoAction = actionCollection()->addAction("goto_address");
257 gotoAction->setText(i18n("Goto Address"));
258 gotoAction->setIcon(KIcon("go-jump-locationbar"));
259 connect(gotoAction, SIGNAL(triggered()), SLOT(newConnection()));
261 KActionMenu *bookmarkMenu = new KActionMenu(i18n("Bookmarks"), actionCollection());
262 m_bookmarkManager = new BookmarkManager(actionCollection(), bookmarkMenu->menu(), this);
263 actionCollection()->addAction("bookmark" , bookmarkMenu);
264 connect(m_bookmarkManager, SIGNAL(openUrl(KUrl)), SLOT(newConnection(KUrl)));
267 void MainWindow::loadAllPlugins()
269 const KService::List offers = KServiceTypeTrader::self()->query("KRDC/Plugin");
271 KConfigGroup conf(KGlobal::config(), "Plugins");
273 for (int i = 0; i < offers.size(); i++) {
274 KService::Ptr offer = offers[i];
276 RemoteViewFactory *remoteView;
278 KPluginInfo description(offer);
279 description.load(conf);
281 const bool selected = description.isPluginEnabled();
283 if (selected) {
284 if ((remoteView = createPluginFromService(offer)) != 0) {
285 kDebug(5010) << "### Plugin " + description.name() + " found ###";
286 kDebug(5010) << "# Version:" << description.version();
287 kDebug(5010) << "# Description:" << description.comment();
288 kDebug(5010) << "# Author:" << description.author();
289 const int sorting = offer->property("X-KDE-KRDC-Sorting").toInt();
290 kDebug(5010) << "# Sorting:" << sorting;
292 m_remoteViewFactories.insert(sorting, remoteView);
293 } else {
294 kDebug(5010) << "Error loading KRDC plugin (" << (offers[i])->library() << ')';
296 } else {
297 kDebug(5010) << "# Plugin " + description.name() + " found, however it's not activated, skipping...";
298 continue;
303 RemoteViewFactory *MainWindow::createPluginFromService(const KService::Ptr &service)
305 //try to load the specified library
306 KPluginFactory *factory = KPluginLoader(service->library()).factory();
308 if (!factory) {
309 kError(5010) << "KPluginFactory could not load the plugin:" << service->library();
310 return 0;
313 RemoteViewFactory *plugin = factory->create<RemoteViewFactory>();
315 return plugin;
318 void MainWindow::restoreOpenSessions()
320 const QStringList list = Settings::openSessions();
321 QStringList::ConstIterator it = list.begin();
322 QStringList::ConstIterator end = list.end();
323 while (it != end) {
324 newConnection(*it);
325 ++it;
329 void MainWindow::newConnection(const KUrl &newUrl, bool switchFullscreenWhenConnected)
331 m_switchFullscreenWhenConnected = switchFullscreenWhenConnected;
333 const KUrl url = newUrl.isEmpty() ? m_addressNavigator->uncommittedUrl() : newUrl;
335 if (!url.isValid() || (url.host().isEmpty() && url.port() < 0)
336 || !url.path().isEmpty()) {
337 KMessageBox::error(this,
338 i18n("The entered address does not have the required form."),
339 i18n("Malformed URL"));
340 return;
343 m_addressNavigator->setUrl(KUrl(url.scheme().toLower() + "://"));
345 RemoteView *view = 0;
346 KConfigGroup configGroup = Settings::self()->config()->group("hostpreferences").group(url.prettyUrl(KUrl::RemoveTrailingSlash));
348 foreach(RemoteViewFactory *factory, m_remoteViewFactories) {
349 if (factory->supportsUrl(url)) {
350 view = factory->createView(this, url, configGroup);
351 kDebug(5010) << "Found plugin to handle url (" + url.url() + "): " + view->metaObject()->className();
352 break;
356 if (!view) {
357 KMessageBox::error(this,
358 i18n("The entered address cannot be handled."),
359 i18n("Unusable URL"));
360 return;
363 // Configure the view
364 HostPreferences* prefs = view->hostPreferences();
365 if (! prefs->showDialogIfNeeded()) {
366 delete view;
367 return;
370 saveHostPrefs();
372 view->setGrabAllKeys(prefs->grabAllKeys());
373 view->showDotCursor(prefs->showLocalCursor() ? RemoteView::CursorOn : RemoteView::CursorOff);
374 view->setViewOnly(prefs->viewOnly());
375 if (! switchFullscreenWhenConnected) view->enableScaling(prefs->windowedScale());
377 connect(view, SIGNAL(framebufferSizeChanged(int, int)), this, SLOT(resizeTabWidget(int, int)));
378 connect(view, SIGNAL(statusChanged(RemoteView::RemoteStatus)), this, SLOT(statusChanged(RemoteView::RemoteStatus)));
380 m_remoteViewList.append(view);
382 // view->resize(0, 0);
384 int numNonRemoteView = 0;
385 if (m_showStartPage)
386 numNonRemoteView++;
387 if (m_zeroconfPage)
388 numNonRemoteView++;
390 if (m_remoteViewList.size() == 1) {
391 kDebug(5010) << "First connection, restoring window size)";
392 restoreWindowSize(view->hostPreferences()->configGroup());
395 QScrollArea *scrollArea = createScrollArea(m_tabWidget, view);
397 const int newIndex = m_tabWidget->addTab(scrollArea, KIcon("krdc"), url.prettyUrl(KUrl::RemoveTrailingSlash));
398 m_tabWidget->setCurrentIndex(newIndex);
399 tabChanged(newIndex); // force to update m_currentRemoteView (tabChanged is not emitted when start page has been disabled)
401 view->start();
404 void MainWindow::openFromDockWidget(const QModelIndex &index)
406 const QString data = index.data(Qt::UserRole).toString();
407 if (!data.isEmpty()) {
408 const KUrl url(data);
409 // first check if url has already been opened; in case show the tab
410 for (int i = 0; i < m_remoteViewList.count(); ++i) {
411 if (m_remoteViewList.at(i)->url() == url) {
412 int numNonRemoteView = 0;
413 if (m_showStartPage)
414 numNonRemoteView++;
415 if (m_zeroconfPage)
416 numNonRemoteView++;
417 m_tabWidget->setCurrentIndex(i + numNonRemoteView);
418 return;
421 newConnection(url);
425 void MainWindow::resizeTabWidget(int w, int h)
427 kDebug(5010) << "tabwidget resize: w: " << w << ", h: " << h;
429 RemoteView* view = m_currentRemoteView >= 0 ? m_remoteViewList.at(m_currentRemoteView) : NULL;
430 if (view && view->scaling()) return;
432 if (m_topBottomBorder == 0) { // the values are not cached yet
433 QScrollArea *tmp = qobject_cast<QScrollArea *>(m_tabWidget->currentWidget());
435 m_leftRightBorder = m_tabWidget->width() - m_tabWidget->currentWidget()->width() + (2 * tmp->frameWidth());
436 m_topBottomBorder = m_tabWidget->height() - m_tabWidget->currentWidget()->height() + (2 * tmp->frameWidth());
438 kDebug(5010) << "tabwidget border: w: " << m_leftRightBorder << ", h: " << m_topBottomBorder;
441 const int newTabWidth = w + m_leftRightBorder;
442 const int newTabHeight = h + m_topBottomBorder;
444 const QSize newWindowSize = size() - m_tabWidget->size() + QSize(newTabWidth, newTabHeight);
446 const QSize desktopSize = QSize(QApplication::desktop()->availableGeometry().width(),
447 QApplication::desktop()->availableGeometry().height());
449 if ((newWindowSize.height() >= desktopSize.height()) || (newWindowSize.width() >= desktopSize.width())) {
450 kDebug(5010) << "remote desktop needs more place than available -> show window maximized";
451 setWindowState(windowState() | Qt::WindowMaximized);
452 return;
455 //WORKAROUND: QTabWidget resize problem. Let's see if there is a clean solution for this issue.
456 m_tabWidget->setMinimumSize(newTabWidth, newTabHeight);
457 m_tabWidget->adjustSize();
458 QCoreApplication::processEvents();
459 m_tabWidget->setMinimumSize(500, 400);
462 void MainWindow::statusChanged(RemoteView::RemoteStatus status)
464 kDebug(5010) << status;
466 // the remoteview is already deleted, so don't show it; otherwise it would crash
467 if (status == RemoteView::Disconnecting || status == RemoteView::Disconnected)
468 return;
470 const QString host = m_remoteViewList.at(m_currentRemoteView)->host();
472 QString iconName = "krdc";
473 QString message;
475 switch (status) {
476 case RemoteView::Connecting:
477 iconName = "network-connect";
478 message = i18n("Connecting to %1", host);
479 break;
480 case RemoteView::Authenticating:
481 iconName = "dialog-password";
482 message = i18n("Authenticating at %1", host);
483 break;
484 case RemoteView::Preparing:
485 iconName = "view-history";
486 message = i18n("Preparing connection to %1", host);
487 break;
488 case RemoteView::Connected:
489 iconName = "krdc";
490 message = i18n("Connected to %1", host);
492 // when started with command line fullscreen argument
493 if (m_switchFullscreenWhenConnected) {
494 m_switchFullscreenWhenConnected = false;
495 switchFullscreen();
498 m_bookmarkManager->addHistoryBookmark();
500 break;
501 default:
502 break;
505 m_tabWidget->setTabIcon(m_tabWidget->currentIndex(), KIcon(iconName));
506 statusBar()->showMessage(message);
509 void MainWindow::takeScreenshot()
511 const QPixmap snapshot = QPixmap::grabWidget(m_remoteViewList.at(m_currentRemoteView));
513 QApplication::clipboard()->setPixmap(snapshot);
516 void MainWindow::switchFullscreen()
518 kDebug(5010);
520 RemoteView* view = m_remoteViewList.at(m_currentRemoteView);
522 if (m_fullscreenWindow) {
523 // Leaving fullscreen mode
524 view->enableScaling(view->hostPreferences()->windowedScale());
525 show();
526 restoreGeometry(m_mainWindowGeometry);
528 m_fullscreenWindow->setWindowState(0);
529 m_fullscreenWindow->hide();
531 QScrollArea *scrollArea = createScrollArea(m_tabWidget, view);
533 const int currentTab = m_tabWidget->currentIndex();
534 m_tabWidget->insertTab(currentTab, scrollArea, m_tabWidget->tabIcon(currentTab), m_tabWidget->tabText(currentTab));
535 m_tabWidget->removeTab(m_tabWidget->currentIndex());
536 m_tabWidget->setCurrentIndex(currentTab);
538 resizeTabWidget(view->sizeHint().width(), view->sizeHint().height());
540 if (m_toolBar) {
541 m_toolBar->hideAndDestroy();
542 m_toolBar->deleteLater();
543 m_toolBar = 0;
546 actionCollection()->action("switch_fullscreen")->setIcon(KIcon("view-fullscreen"));
547 actionCollection()->action("switch_fullscreen")->setText(i18n("Switch to Fullscreen Mode"));
549 m_fullscreenWindow->deleteLater();
551 m_fullscreenWindow = 0;
552 } else {
553 // Entering fullscreen mode
554 m_fullscreenWindow = new QWidget(this, Qt::Window);
555 m_fullscreenWindow->setWindowTitle(i18nc("window title when in fullscreen mode (for example displayed in tasklist)",
556 "KDE Remote Desktop Client (Fullscreen)"));
558 QScrollArea *scrollArea = createScrollArea(m_fullscreenWindow, view);
559 scrollArea->setFrameShape(QFrame::NoFrame);
561 QVBoxLayout *fullscreenLayout = new QVBoxLayout(m_fullscreenWindow);
562 fullscreenLayout->setMargin(0);
563 fullscreenLayout->addWidget(scrollArea);
565 MinimizePixel *minimizePixel = new MinimizePixel(m_fullscreenWindow);
566 minimizePixel->winId(); // force it to be a native widget (prevents problem with QX11EmbedContainer)
567 connect(minimizePixel, SIGNAL(rightClicked()), m_fullscreenWindow, SLOT(showMinimized()));
569 view->enableScaling(view->hostPreferences()->fullscreenScale());
571 m_fullscreenWindow->show();
573 KToggleFullScreenAction::setFullScreen(m_fullscreenWindow, true);
575 m_mainWindowGeometry = saveGeometry();
576 hide();
578 showRemoteViewToolbar();
582 QScrollArea *MainWindow::createScrollArea(QWidget *parent, RemoteView *remoteView)
584 RemoteViewScrollArea *scrollArea = new RemoteViewScrollArea(parent);
585 scrollArea->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
587 connect(scrollArea, SIGNAL(resized(int, int)), remoteView, SLOT(scaleResize(int, int)));
589 QPalette palette = scrollArea->palette();
590 palette.setColor(QPalette::Dark, Settings::backgroundColor());
591 scrollArea->setPalette(palette);
593 scrollArea->setBackgroundRole(QPalette::Dark);
594 scrollArea->setWidget(remoteView);
596 return scrollArea;
599 void MainWindow::disconnectHost()
601 kDebug(5010);
603 if (m_fullscreenWindow) { // first close fullscreen view
604 switchFullscreen();
607 QWidget *tmp = m_tabWidget->currentWidget();
608 m_remoteViewList.removeAt(m_currentRemoteView);
609 m_tabWidget->removeTab(m_tabWidget->currentIndex());
610 tmp->deleteLater();
612 saveHostPrefs();
615 void MainWindow::closeTab(QWidget *widget)
617 const int index = m_tabWidget->indexOf(widget);
619 kDebug(5010) << index;
621 if (m_showStartPage && index == 0) {
622 KMessageBox::information(this, i18n("You can enable the start page in the settings again."));
624 Settings::setShowStartPage(false);
625 m_tabWidget->removeTab(0);
626 m_showStartPage = false;
627 return;
630 #ifdef BUILD_ZEROCONF
631 if (widget == m_zeroconfPage) {
632 closeZeroconfPage();
633 return;
635 #endif
637 int numNonRemoteView = 0;
638 if (m_showStartPage)
639 numNonRemoteView++;
640 if (m_zeroconfPage)
641 numNonRemoteView++;
643 if (index - numNonRemoteView >= 0)
644 m_remoteViewList.removeAt(index - numNonRemoteView);
646 m_tabWidget->removeTab(index);
648 widget->deleteLater();
651 void MainWindow::openTabSettings(QWidget *widget)
653 RemoteViewScrollArea *scrollArea = qobject_cast<RemoteViewScrollArea*>(widget);
654 if (!scrollArea) return;
655 RemoteView *view = qobject_cast<RemoteView*>(scrollArea->widget());
656 if (!view) return;
658 const QString url = view->url().url();
659 kDebug(5010) << url;
661 HostPreferences *prefs = 0;
663 foreach(RemoteViewFactory *factory, remoteViewFactoriesList()) {
664 if (factory->supportsUrl(url)) {
665 prefs = factory->createHostPreferences(Settings::self()->config()->group("hostpreferences").group(url), this);
666 if (prefs) {
667 kDebug(5010) << "Found plugin to handle url (" + url + "): " + prefs->metaObject()->className();
668 } else {
669 kDebug(5010) << "Found plugin to handle url (" + url + "), but plugin does not provide preferences";
674 if (prefs) {
675 prefs->setShownWhileConnected(true);
676 prefs->showDialog();
677 delete prefs;
678 } else {
679 KMessageBox::error(this,
680 i18n("The selected host cannot be handled."),
681 i18n("Unusable URL"));
685 void MainWindow::tabContextMenu(QWidget *widget, const QPoint &point)
687 RemoteViewScrollArea *scrollArea = qobject_cast<RemoteViewScrollArea*>(widget);
688 if (!scrollArea) return;
689 RemoteView *view = qobject_cast<RemoteView*>(scrollArea->widget());
690 if (!view) return;
692 const QString url = view->url().url();
693 kDebug(5010) << url;
695 KMenu *menu = new KMenu(this);
696 menu->addTitle(url);
697 QAction *bookmarkAction = menu->addAction(KIcon("bookmark-new"), i18n("Add Bookmark"));
698 QAction *closeAction = menu->addAction(KIcon("tab-close"), i18n("Close Tab"));
699 QAction *selectedAction = menu->exec(point);
700 if (selectedAction) {
701 if (selectedAction == closeAction) {
702 closeTab(widget);
703 } else if (selectedAction == bookmarkAction) {
704 m_bookmarkManager->addManualBookmark(url, url);
707 menu->deleteLater();
710 void MainWindow::showLocalCursor(bool showLocalCursor)
712 kDebug(5010) << showLocalCursor;
714 RemoteView* view = m_remoteViewList.at(m_currentRemoteView);
715 view->showDotCursor(showLocalCursor ? RemoteView::CursorOn : RemoteView::CursorOff);
716 view->hostPreferences()->setViewOnly(showLocalCursor);
717 saveHostPrefs();
720 void MainWindow::viewOnly(bool viewOnly)
722 kDebug(5010) << viewOnly;
724 RemoteView* view = m_remoteViewList.at(m_currentRemoteView);
725 view->setViewOnly(viewOnly);
726 view->hostPreferences()->setViewOnly(viewOnly);
727 saveHostPrefs();
730 void MainWindow::grabAllKeys(bool grabAllKeys)
732 kDebug(5010);
734 RemoteView* view = m_remoteViewList.at(m_currentRemoteView);
735 view->setGrabAllKeys(grabAllKeys);
736 view->hostPreferences()->setGrabAllKeys(grabAllKeys);
737 saveHostPrefs();
740 void MainWindow::scale(bool scale)
742 kDebug(5010);
744 RemoteView* view = m_remoteViewList.at(m_currentRemoteView);
745 view->enableScaling(scale);
746 if (m_fullscreenWindow)
747 view->hostPreferences()->setFullscreenScale(scale);
748 else
749 view->hostPreferences()->setWindowedScale(scale);
751 saveHostPrefs();
754 void MainWindow::showRemoteViewToolbar()
756 kDebug(5010);
758 if (!m_toolBar) {
759 actionCollection()->action("switch_fullscreen")->setIcon(KIcon("view-restore"));
760 actionCollection()->action("switch_fullscreen")->setText(i18n("Switch to Window Mode"));
762 m_toolBar = new FloatingToolBar(m_fullscreenWindow, m_fullscreenWindow);
763 m_toolBar->winId(); // force it to be a native widget (prevents problem with QX11EmbedContainer)
764 m_toolBar->setSide(FloatingToolBar::Top);
766 QLabel *hostLabel = new QLabel(m_remoteViewList.at(m_currentRemoteView)->url().prettyUrl(KUrl::RemoveTrailingSlash), m_toolBar);
767 hostLabel->setMargin(4);
768 QFont font(hostLabel->font());
769 font.setBold(true);
770 hostLabel->setFont(font);
771 m_toolBar->addWidget(hostLabel);
773 #if 0 //TODO: implement functionality
774 KComboBox *sessionComboBox = new KComboBox(m_toolBar);
775 sessionComboBox->setEditable(false);
776 sessionComboBox->addItem(i18n("Switch to..."));
777 for (int i = 0; i < m_remoteViewList.count(); i++) {
778 sessionComboBox->addItem(m_remoteViewList.at(i)->url().prettyUrl(KUrl::RemoveTrailingSlash));
780 sessionComboBox->setVisible(m_remoteViewList.count() > 1); // just show it if there are sessions to switch
781 m_toolBar->addWidget(sessionComboBox);
782 #endif
784 m_toolBar->addAction(actionCollection()->action("switch_fullscreen"));
786 QAction *minimizeAction = new QAction(m_toolBar);
787 minimizeAction->setIcon(KIcon("window-suppressed"));
788 minimizeAction->setText(i18n("Minimize Fullscreen Window"));
789 connect(minimizeAction, SIGNAL(triggered()), m_fullscreenWindow, SLOT(showMinimized()));
790 m_toolBar->addAction(minimizeAction);
792 m_toolBar->addAction(actionCollection()->action("take_screenshot"));
793 m_toolBar->addAction(actionCollection()->action("view_only"));
794 m_toolBar->addAction(actionCollection()->action("show_local_cursor"));
795 m_toolBar->addAction(actionCollection()->action("grab_all_keys"));
796 m_toolBar->addAction(actionCollection()->action("scale"));
797 m_toolBar->addAction(actionCollection()->action("disconnect"));
799 QAction *stickToolBarAction = new QAction(m_toolBar);
800 stickToolBarAction->setCheckable(true);
801 stickToolBarAction->setIcon(KIcon("object-locked"));
802 stickToolBarAction->setText(i18n("Stick Toolbar"));
803 connect(stickToolBarAction, SIGNAL(triggered(bool)), m_toolBar, SLOT(setSticky(bool)));
804 m_toolBar->addAction(stickToolBarAction);
807 m_toolBar->showAndAnimate();
810 void setActionStatus(QAction* action, bool enabled, bool visible, bool checked)
812 action->setEnabled(enabled);
813 action->setVisible(visible);
814 action->setChecked(checked);
817 void MainWindow::updateActionStatus()
819 kDebug(5010) << m_tabWidget->currentIndex();
821 bool enabled;
823 if ((m_showStartPage && (m_tabWidget->currentIndex() == 0)) ||
824 #ifdef BUILD_ZEROCONF
825 (m_zeroconfPage && (m_tabWidget->currentIndex() == m_tabWidget->indexOf(m_zeroconfPage))) ||
826 #endif
827 (!m_showStartPage && (m_tabWidget->currentIndex() < 0)))
828 enabled = false;
829 else
830 enabled = true;
832 RemoteView* view = m_currentRemoteView >= 0 ? m_remoteViewList.at(m_currentRemoteView) : NULL;
834 actionCollection()->action("switch_fullscreen")->setEnabled(enabled);
835 actionCollection()->action("take_screenshot")->setEnabled(enabled);
836 actionCollection()->action("disconnect")->setEnabled(enabled);
838 setActionStatus(actionCollection()->action("view_only"),
839 enabled,
840 true,
841 view ? view->viewOnly() : false);
843 setActionStatus(actionCollection()->action("show_local_cursor"),
844 enabled,
845 view ? view->supportsLocalCursor() : false,
846 view ? view->dotCursorState() == RemoteView::CursorOn : false);
848 setActionStatus(actionCollection()->action("scale"),
849 enabled,
850 view ? view->supportsScaling() : false,
851 view ? view->scaling() : false);
853 setActionStatus(actionCollection()->action("grab_all_keys"),
854 enabled,
855 enabled,
856 view ? view->grabAllKeys() : false);
859 void MainWindow::preferences()
861 // An instance of your dialog could be already created and could be
862 // cached, in which case you want to display the cached dialog
863 // instead of creating another one
864 if (PreferencesDialog::showDialog("preferences"))
865 return;
867 // KConfigDialog didn't find an instance of this dialog, so lets
868 // create it:
869 PreferencesDialog *dialog = new PreferencesDialog(this, Settings::self());
871 // User edited the configuration - update your local copies of the
872 // configuration data
873 connect(dialog, SIGNAL(settingsChanged(const QString&)),
874 this, SLOT(updateConfiguration()));
876 dialog->show();
879 void MainWindow::updateConfiguration()
881 m_addressNavigator->setUrlEditable(Settings::normalUrlInputLine());
883 m_tabWidget->setTabBarHidden(!Settings::showTabBar());
884 m_tabWidget->setTabPosition((KTabWidget::TabPosition) Settings::tabPosition());
885 #if QT_VERSION <= 0x040500
886 m_tabWidget->setTabsClosable(Settings::tabCloseButton());
887 #else
888 m_tabWidget->setCloseButtonEnabled(Settings::tabCloseButton());
889 #endif
890 disconnect(m_tabWidget, SIGNAL(mouseMiddleClick(QWidget *)), this, SLOT(closeTab(QWidget *))); // just be sure it is not connected twice
891 if (Settings::tabMiddleClick())
892 connect(m_tabWidget, SIGNAL(mouseMiddleClick(QWidget *)), SLOT(closeTab(QWidget *)));
894 if (Settings::systemTrayIcon() && !m_systemTrayIcon) {
895 m_systemTrayIcon = new SystemTrayIcon(this);
896 m_systemTrayIcon->setVisible(true);
897 } else if (m_systemTrayIcon) {
898 delete m_systemTrayIcon;
899 m_systemTrayIcon = 0;
902 if (Settings::showStartPage() && !m_showStartPage)
903 createStartPage();
904 else if (!Settings::showStartPage() && m_showStartPage) {
905 m_tabWidget->removeTab(0);
906 m_showStartPage = false;
908 updateActionStatus();
910 // update the scroll areas background color
911 int numNonRemoteView = 0;
912 if (m_showStartPage)
913 numNonRemoteView++;
914 if (m_zeroconfPage)
915 numNonRemoteView++;
916 for (int i = numNonRemoteView; i < m_tabWidget->count(); ++i) {
917 QPalette palette = m_tabWidget->widget(i)->palette();
918 palette.setColor(QPalette::Dark, Settings::backgroundColor());
919 m_tabWidget->widget(i)->setPalette(palette);
922 // Send update configuration message to all views
923 for (int i = 0; i < m_remoteViewList.count(); ++i) {
924 m_remoteViewList.at(i)->updateConfiguration();
929 void MainWindow::quit(bool systemEvent)
931 const bool haveRemoteConnections = !m_remoteViewList.isEmpty();
932 if (systemEvent || !haveRemoteConnections || KMessageBox::warningContinueCancel(this,
933 i18n("Are you sure you want to quit the KDE Remote Desktop Client?"),
934 i18n("Confirm Quit"),
935 KStandardGuiItem::quit(), KStandardGuiItem::cancel(),
936 "DoNotAskBeforeExit") == KMessageBox::Continue) {
938 if (Settings::rememberSessions()) { // remember open remote views for next startup
939 QStringList list;
940 for (int i = 0; i < m_remoteViewList.count(); ++i) {
941 kDebug(5010) << m_remoteViewList.at(i)->url();
942 list.append(m_remoteViewList.at(i)->url().prettyUrl(KUrl::RemoveTrailingSlash));
944 Settings::setOpenSessions(list);
947 saveHostPrefs();
949 Settings::self()->writeConfig();
951 qApp->quit();
955 void MainWindow::configureNotifications()
957 KNotifyConfigWidget::configure(this);
960 void MainWindow::configureKeys()
962 KShortcutsDialog::configure(actionCollection());
965 void MainWindow::configureToolbars()
967 KEditToolBar edit(actionCollection());
968 connect(&edit, SIGNAL(newToolbarConfig()), this, SLOT(newToolbarConfig()));
969 edit.exec();
972 void MainWindow::showMenubar()
974 if (m_menubarAction->isChecked())
975 menuBar()->show();
976 else
977 menuBar()->hide();
980 void MainWindow::closeEvent(QCloseEvent *event)
982 if (event->spontaneous()) { // Returns true if the event originated outside the application (a system event); otherwise returns false.
983 event->ignore();
984 if (Settings::systemTrayIcon()) {
985 hide(); // just hide the mainwindow, keep it in systemtray
986 } else {
987 quit();
989 } else {
990 quit(true);
994 void MainWindow::saveProperties(KConfigGroup &group)
996 kDebug(5010);
997 KMainWindow::saveProperties(group);
998 saveHostPrefs();
1001 void MainWindow::saveHostPrefs()
1003 // Save default window size for currently active view
1004 RemoteView* view = m_currentRemoteView >= 0 ? m_remoteViewList.at(m_currentRemoteView) : NULL;
1005 if (view)
1006 saveWindowSize(view->hostPreferences()->configGroup());
1008 Settings::self()->config()->sync();
1011 void MainWindow::tabChanged(int index)
1013 kDebug(5010) << index;
1015 int numNonRemoteView = 0;
1016 if (m_showStartPage)
1017 numNonRemoteView++;
1018 if (m_zeroconfPage)
1019 numNonRemoteView++;
1021 m_currentRemoteView = index - numNonRemoteView;
1023 const QString tabTitle = m_tabWidget->tabText(index).remove('&');
1024 setCaption(tabTitle == i18n("Start Page") ? QString() : tabTitle);
1026 updateActionStatus();
1029 void MainWindow::createStartPage()
1031 m_showStartPage = true;
1033 QWidget *startWidget = new QWidget(this);
1034 startWidget->setStyleSheet("QWidget { background-color: palette(base) }");
1036 QVBoxLayout *startLayout = new QVBoxLayout(startWidget);
1038 QLabel *headerLabel = new QLabel(this);
1039 headerLabel->setText(i18n("<h1>KDE Remote Desktop Client</h1><br /><br />What would you like to do?<br />"));
1041 QLabel *headerIconLabel = new QLabel(this);
1042 headerIconLabel->setPixmap(KIcon("krdc").pixmap(128));
1044 QHBoxLayout *headerLayout = new QHBoxLayout;
1045 headerLayout->setMargin(20);
1046 headerLayout->addWidget(headerLabel, 1, Qt::AlignTop);
1047 headerLayout->addWidget(headerIconLabel);
1048 startLayout->addLayout(headerLayout);
1050 foreach(RemoteViewFactory *factory, m_remoteViewFactories) {
1051 KPushButton *connectButton = new KPushButton(this);
1052 connectButton->setProperty("schemeString", factory->scheme());
1053 connectButton->setProperty("toolTipString", factory->connectToolTipText());
1054 connectButton->setStyleSheet("KPushButton { padding: 12px; margin: 10px; }");
1055 connectButton->setIcon(KIcon(actionCollection()->action("new_" + factory->scheme() + "_connection")->icon()));
1056 connectButton->setText(factory->connectButtonText());
1057 connect(connectButton, SIGNAL(clicked()), SLOT(newConnectionToolTip()));
1058 startLayout->addWidget(connectButton);
1061 KPushButton *zeroconfButton = new KPushButton(this);
1062 zeroconfButton->setStyleSheet("KPushButton { padding: 12px; margin: 10px; }");
1063 zeroconfButton->setIcon(KIcon(actionCollection()->action("zeroconf_page")->icon()));
1064 zeroconfButton->setText(i18n("Browse Remote Desktop Services on Local Network"));
1065 connect(zeroconfButton, SIGNAL(clicked()), SLOT(createZeroconfPage()));
1066 #ifndef BUILD_ZEROCONF
1067 zeroconfButton->setVisible(false);
1068 #endif
1070 startLayout->addWidget(zeroconfButton);
1071 startLayout->addStretch();
1073 m_tabWidget->insertTab(0, startWidget, KIcon("krdc"), i18n("Start Page"));
1076 void MainWindow::newConnectionToolTip()
1078 QObject *senderObject = qobject_cast<QObject*>(sender());
1079 const QString toolTip(senderObject->property("toolTipString").toString());
1080 const QString scheme(senderObject->property("schemeString").toString());
1082 m_addressNavigator->setUrl(KUrl(scheme + "://"));
1083 m_addressNavigator->setFocus();
1085 QToolTip::showText(m_addressNavigator->pos() + pos() + QPoint(m_addressNavigator->width(),
1086 m_addressNavigator->height() / 2),
1087 toolTip, this);
1090 void MainWindow::createZeroconfPage()
1092 #ifdef BUILD_ZEROCONF
1093 if (m_zeroconfPage)
1094 return;
1096 m_zeroconfPage = new ZeroconfPage(this);
1097 connect(m_zeroconfPage, SIGNAL(newConnection(const KUrl, bool)), this, SLOT(newConnection(const KUrl, bool)));
1098 connect(m_zeroconfPage, SIGNAL(closeZeroconfPage()), this, SLOT(closeZeroconfPage()));
1099 const int zeroconfTabIndex = m_tabWidget->insertTab(m_showStartPage ? 1 : 0, m_zeroconfPage, KIcon("krdc"), i18n("Browse Local Network"));
1100 m_tabWidget->setCurrentIndex(zeroconfTabIndex);
1101 #endif
1104 void MainWindow::closeZeroconfPage()
1106 #ifdef BUILD_ZEROCONF
1107 const int index = m_tabWidget->indexOf(m_zeroconfPage);
1108 m_tabWidget->removeTab(index);
1109 m_zeroconfPage->deleteLater();
1110 m_zeroconfPage = 0;
1111 #endif
1114 QList<RemoteView *> MainWindow::remoteViewList() const
1116 return m_remoteViewList;
1119 QList<RemoteViewFactory *> MainWindow::remoteViewFactoriesList() const
1121 return m_remoteViewFactories.values();
1124 int MainWindow::currentRemoteView() const
1126 return m_currentRemoteView;
1129 void MainWindow::expandTreeViewItems()
1131 metaObject()->invokeMethod(m_remoteDesktopsTreeView, "expandAll", Qt::QueuedConnection);
1134 #include "mainwindow.moc"