Implement scaling of remote desktop for VNC protocol.
[kdenetwork.git] / krdc / mainwindow.cpp
blobc2c13b142fd5a6d2a86e5a7b7bb7425cc486fcad
1 /****************************************************************************
2 **
3 ** Copyright (C) 2007 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 #ifdef BUILD_RDP
34 #include "rdpview.h"
35 #endif
36 #ifdef BUILD_NX
37 #include "nxview.h"
38 #endif
39 #ifdef BUILD_VNC
40 #include "vncview.h"
41 #endif
42 #ifdef BUILD_ZEROCONF
43 #include "zeroconfpage.h"
44 #endif
46 #include <KAction>
47 #include <KActionCollection>
48 #include <KActionMenu>
49 #include <KApplication>
50 #include <KComboBox>
51 #include <KEditToolBar>
52 #include <KIcon>
53 #include <KLocale>
54 #include <KMenuBar>
55 #include <KMessageBox>
56 #include <KNotifyConfigWidget>
57 #include <KPushButton>
58 #include <KShortcut>
59 #include <KShortcutsDialog>
60 #include <KStatusBar>
61 #include <KTabWidget>
62 #include <KToggleAction>
63 #include <KToggleFullScreenAction>
64 #include <KUrlNavigator>
66 #include <QClipboard>
67 #include <QCloseEvent>
68 #include <QDesktopWidget>
69 #include <QDockWidget>
70 #include <QHeaderView>
71 #include <QLabel>
72 #include <QLayout>
73 #include <QScrollArea>
74 #include <QTimer>
75 #include <QToolButton>
76 #include <QToolTip>
77 #include <QTreeView>
79 MainWindow::MainWindow(QWidget *parent)
80 : KXmlGuiWindow(parent),
81 m_fullscreenWindow(0),
82 m_toolBar(0),
83 m_topBottomBorder(0),
84 m_leftRightBorder(0),
85 m_currentRemoteView(-1),
86 m_showStartPage(false),
87 m_systemTrayIcon(0),
88 m_zeroconfPage(0)
90 setupActions();
92 setStandardToolBarMenuEnabled(true);
94 m_tabWidget = new KTabWidget(this);
95 m_tabWidget->setMinimumSize(600, 400);
96 setCentralWidget(m_tabWidget);
98 QDockWidget *remoteDesktopsDockWidget = new QDockWidget(this);
99 remoteDesktopsDockWidget->setObjectName("remoteDesktopsDockWidget");
100 remoteDesktopsDockWidget->setWindowTitle("Remote desktops");
101 actionCollection()->addAction("remote_desktop_dockwidget",
102 remoteDesktopsDockWidget->toggleViewAction());
103 QTreeView *remoteDesktopsTreeView = new QTreeView(remoteDesktopsDockWidget);
104 remoteDesktopsTreeView->setModel(new RemoteDesktopsModel(this));
105 remoteDesktopsTreeView->header()->hide();
106 remoteDesktopsTreeView->expandAll();
107 connect(remoteDesktopsTreeView, SIGNAL(doubleClicked(const QModelIndex &)),
108 SLOT(openFromDockWidget(const QModelIndex &)));
110 remoteDesktopsDockWidget->setWidget(remoteDesktopsTreeView);
111 addDockWidget(Qt::LeftDockWidgetArea, remoteDesktopsDockWidget);
113 createGUI("krdcui.rc");
115 if (Settings::systemTrayIcon()) {
116 m_systemTrayIcon = new SystemTrayIcon(this);
117 m_systemTrayIcon->setVisible(true);
120 connect(m_tabWidget, SIGNAL(currentChanged(int)), SLOT(tabChanged(int)));
122 statusBar()->showMessage(i18n("KDE Remote Desktop Client started"));
124 updateActionStatus(); // disable remote view actions
126 if (Settings::showStartPage())
127 createStartPage();
129 setAutoSaveSettings(); // e.g toolbar position, mainwindow size, ...
131 if (Settings::rememberSessions()) // give some time to create and show the window first
132 QTimer::singleShot(100, this, SLOT(restoreOpenSessions()));
134 remoteDesktopsDockWidget->setVisible(false); //TODO: remove when fully implemented
137 MainWindow::~MainWindow()
141 void MainWindow::setupActions()
143 QAction *vncConnectionAction = actionCollection()->addAction("new_vnc_connection");
144 vncConnectionAction->setText(i18n("New VNC Connection..."));
145 vncConnectionAction->setIcon(KIcon("network-connect"));
146 connect(vncConnectionAction, SIGNAL(triggered()), SLOT(newVncConnection()));
147 #ifndef BUILD_VNC
148 vncConnectionAction->setVisible(false);
149 #endif
151 QAction *nxConnectionAction = actionCollection()->addAction("new_nx_connection");
152 nxConnectionAction->setText(i18n("New NX Connection..."));
153 nxConnectionAction->setIcon(KIcon("network-connect"));
154 connect(nxConnectionAction, SIGNAL(triggered()), SLOT(newNxConnection()));
155 #ifndef BUILD_NX
156 nxConnectionAction->setVisible(false);
157 #endif
159 QAction *rdpConnectionAction = actionCollection()->addAction("new_rdp_connection");
160 rdpConnectionAction->setText(i18n("New RDP Connection..."));
161 rdpConnectionAction->setIcon(KIcon("network-connect"));
162 connect(rdpConnectionAction, SIGNAL(triggered()), SLOT(newRdpConnection()));
163 #ifndef BUILD_RDP
164 rdpConnectionAction->setVisible(false);
165 #endif
167 QAction *zeroconfAction = actionCollection()->addAction("zeroconf_page");
168 zeroconfAction->setText(i18n("Browse Remote Desktop Services on Local Network..."));
169 zeroconfAction->setIcon(KIcon("network-connect"));
170 connect(zeroconfAction, SIGNAL(triggered()), SLOT(createZeroconfPage()));
171 #ifndef BUILD_ZEROCONF
172 zeroconfAction->setVisible(false);
173 #endif
175 QAction *screenshotAction = actionCollection()->addAction("take_screenshot");
176 screenshotAction->setText(i18n("Copy Screenshot to Clipboard"));
177 screenshotAction->setIcon(KIcon("ksnapshot"));
178 connect(screenshotAction, SIGNAL(triggered()), SLOT(takeScreenshot()));
180 QAction *fullscreenAction = actionCollection()->addAction("switch_fullscreen");
181 fullscreenAction->setText(i18n("Switch to Fullscreen Mode"));
182 fullscreenAction->setIcon(KIcon("view-fullscreen"));
183 connect(fullscreenAction, SIGNAL(triggered()), SLOT(switchFullscreen()));
185 QAction *viewOnlyAction = actionCollection()->addAction("view_only");
186 viewOnlyAction->setCheckable(true);
187 viewOnlyAction->setText(i18n("View Only"));
188 viewOnlyAction->setIcon(KIcon("document-preview"));
189 connect(viewOnlyAction, SIGNAL(triggered(bool)), SLOT(viewOnly(bool)));
191 QAction *logoutAction = actionCollection()->addAction("logout");
192 logoutAction->setText(i18n("Log Out"));
193 logoutAction->setIcon(KIcon("system-log-out"));
194 connect(logoutAction, SIGNAL(triggered()), SLOT(logout()));
196 QAction *showLocalCursorAction = actionCollection()->addAction("show_local_cursor");
197 showLocalCursorAction->setCheckable(true);
198 showLocalCursorAction->setIcon(KIcon("input-mouse"));
199 showLocalCursorAction->setText(i18n("Show Local Cursor"));
200 connect(showLocalCursorAction, SIGNAL(triggered(bool)), SLOT(showLocalCursor(bool)));
202 QAction *grabAllKeysAction = actionCollection()->addAction("grab_all_keys");
203 grabAllKeysAction->setCheckable(true);
204 grabAllKeysAction->setIcon(KIcon("configure-shortcuts"));
205 grabAllKeysAction->setText(i18n("Grab all possible keys"));
206 connect(grabAllKeysAction, SIGNAL(triggered(bool)), SLOT(grabAllKeys(bool)));
208 QAction *scaleAction = actionCollection()->addAction("scale");
209 scaleAction->setCheckable(true);
210 scaleAction->setIcon(KIcon("zoom-fit-best"));
211 scaleAction->setText(i18n("Scale remote screen to fit window size"));
212 connect(scaleAction, SIGNAL(triggered(bool)), SLOT(scale(bool)));
214 QAction *quitAction = KStandardAction::quit(this, SLOT(quit()), actionCollection());
215 actionCollection()->addAction("quit", quitAction);
216 QAction *preferencesAction = KStandardAction::preferences(this, SLOT(preferences()), actionCollection());
217 actionCollection()->addAction("preferences", preferencesAction);
218 QAction *configToolbarAction = KStandardAction::configureToolbars(this, SLOT(configureToolbars()), actionCollection());
219 actionCollection()->addAction("configure_toolbars", configToolbarAction);
220 QAction *keyBindingsAction = KStandardAction::keyBindings(this, SLOT(configureKeys()), actionCollection());
221 actionCollection()->addAction("configure_keys", keyBindingsAction);
222 QAction *cinfigNotifyAction = KStandardAction::configureNotifications(this, SLOT(configureNotifications()), actionCollection());
223 cinfigNotifyAction->setVisible(false);
224 actionCollection()->addAction("configure_notifications", cinfigNotifyAction);
225 m_menubarAction = KStandardAction::showMenubar(this, SLOT(showMenubar()), actionCollection());
226 m_menubarAction->setChecked(!menuBar()->isHidden());
227 actionCollection()->addAction("settings_showmenubar", m_menubarAction);
229 QString initialProtocol;
230 #ifdef BUILD_RDP
231 initialProtocol = "rdp";
232 #endif
233 #ifdef BUILD_NX
234 initialProtocol = "nx";
235 #endif
236 #ifdef BUILD_VNC
237 initialProtocol = "vnc";
238 #endif
240 m_addressNavigator = new KUrlNavigator(0, KUrl(initialProtocol + "://"), this);
241 m_addressNavigator->setCustomProtocols(QStringList()
242 #ifdef BUILD_VNC
243 << "vnc"
244 #endif
245 #ifdef BUILD_NX
246 << "nx"
247 #endif
248 #ifdef BUILD_RDP
249 << "rdp"
250 #endif
252 m_addressNavigator->setUrlEditable(Settings::normalUrlInputLine());
253 connect(m_addressNavigator, SIGNAL(returnPressed()), SLOT(newConnection()));
255 QLabel *addressLabel = new QLabel(i18n("Remote desktop:"), this);
257 QWidget *addressWidget = new QWidget(this);
258 QHBoxLayout *addressLayout = new QHBoxLayout(addressWidget);
259 addressLayout->setMargin(0);
260 addressLayout->addWidget(addressLabel);
261 addressLayout->addWidget(m_addressNavigator, 1);
263 KAction *addressLineAction = new KAction(i18nc("Title for remote address input action", "Address"), this);
264 actionCollection()->addAction("address_line", addressLineAction);
265 addressLineAction->setDefaultWidget(addressWidget);
267 QAction *gotoAction = actionCollection()->addAction("goto_address");
268 gotoAction->setText(i18n("Goto Address"));
269 gotoAction->setIcon(KIcon("go-jump-locationbar"));
270 connect(gotoAction, SIGNAL(triggered()), SLOT(newConnection()));
272 KActionMenu *bookmarkMenu = new KActionMenu(i18n("Bookmarks"), actionCollection());
273 m_bookmarkManager = new BookmarkManager(actionCollection(), bookmarkMenu->menu(), this);
274 actionCollection()->addAction("bookmark" , bookmarkMenu);
275 connect(m_bookmarkManager, SIGNAL(openUrl(KUrl)), SLOT(newConnection(KUrl)));
278 void MainWindow::restoreOpenSessions()
280 QStringList list = Settings::openSessions();
281 QStringList::Iterator it = list.begin();
282 QStringList::Iterator end = list.end();
283 while (it != end) {
284 newConnection(*it);
285 ++it;
289 void MainWindow::newConnection(const KUrl &newUrl, bool switchFullscreenWhenConnected)
291 m_switchFullscreenWhenConnected = switchFullscreenWhenConnected;
293 KUrl url = newUrl.isEmpty() ? m_addressNavigator->uncommittedUrl() : newUrl;
295 if (!url.isValid() || (url.host().isEmpty() && url.port() < 0)
296 || !url.path().isEmpty()) {
297 KMessageBox::error(this,
298 i18n("The entered address does not have the required form."),
299 i18n("Malformed URL"));
300 return;
303 m_addressNavigator->setUrl(KUrl(url.scheme().toLower() + "://"));
305 RemoteView *view;
307 #ifdef BUILD_VNC
308 if (url.scheme().toLower() == "vnc") {
309 view = new VncView(this, url);
310 } else
311 #endif
313 #ifdef BUILD_NX
314 if (url.scheme().toLower() == "nx") {
315 view = new NxView(this, url);
316 } else
317 #endif
319 #ifdef BUILD_RDP
320 if (url.scheme().toLower() == "rdp") {
321 view = new RdpView(this, url);
322 } else
323 #endif
325 KMessageBox::error(this,
326 i18n("The entered address cannot be handled."),
327 i18n("Unusable URL"));
328 return;
331 connect(view, SIGNAL(changeSize(int, int)), this, SLOT(resizeTabWidget(int, int)));
332 connect(view, SIGNAL(statusChanged(RemoteView::RemoteStatus)), this, SLOT(statusChanged(RemoteView::RemoteStatus)));
334 m_remoteViewList.append(view);
336 view->resize(0, 0);
338 int numNonRemoteView = 0;
339 if (m_showStartPage)
340 numNonRemoteView++;
341 if (m_zeroconfPage)
342 numNonRemoteView++;
344 QScrollArea *scrollArea = createScrollArea(m_tabWidget, m_remoteViewList.at(m_remoteViewList.count() - 1));
346 int newIndex = m_tabWidget->addTab(scrollArea, KIcon("krdc"), url.prettyUrl(KUrl::RemoveTrailingSlash));
347 m_tabWidget->setCurrentIndex(newIndex);
348 tabChanged(newIndex); // force to update m_currentRemoteView (tabChanged is not emitted when start page has been disabled)
350 view->start();
353 void MainWindow::openFromDockWidget(const QModelIndex &index)
355 if (index.data(Qt::UserRole).toBool()) {
356 KUrl url(index.data().toString());
357 // first check if url has already been opened; in case show the tab
358 for (int i = 0; i < m_remoteViewList.count(); i++) {
359 if (m_remoteViewList.at(i)->url() == url) {
360 int numNonRemoteView = 0;
361 if (m_showStartPage)
362 numNonRemoteView++;
363 if (m_zeroconfPage)
364 numNonRemoteView++;
365 m_tabWidget->setCurrentIndex(i + numNonRemoteView);
366 return;
369 newConnection(url);
373 void MainWindow::resizeTabWidget(int w, int h)
375 kDebug(5010) << "tabwidget resize: w: " << w << ", h: " << h;
377 if (m_topBottomBorder == 0) { // the values are not cached yet
378 QScrollArea *tmp = qobject_cast<QScrollArea *>(m_tabWidget->currentWidget());
380 m_leftRightBorder = m_tabWidget->width() - m_tabWidget->currentWidget()->width() + (2 * tmp->frameWidth());
381 m_topBottomBorder = m_tabWidget->height() - m_tabWidget->currentWidget()->height() + (2 * tmp->frameWidth());
383 kDebug(5010) << "tabwidget border: w: " << m_leftRightBorder << ", h: " << m_topBottomBorder;
386 int newTabWidth = w + m_leftRightBorder;
387 int newTabHeight = h + m_topBottomBorder;
389 QSize newWindowSize = size() - m_tabWidget->size() + QSize(newTabWidth, newTabHeight);
391 QSize desktopSize = QSize(QApplication::desktop()->availableGeometry().width(),
392 QApplication::desktop()->availableGeometry().height());
394 if ((newWindowSize.height() >= desktopSize.height()) || (newWindowSize.width() >= desktopSize.width())) {
395 kDebug(5010) << "remote desktop needs more place than available -> show window maximized";
396 setWindowState(windowState() | Qt::WindowMaximized);
397 return;
400 //WORKAROUND: QTabWidget resize problem. Let's see if there is a clean solution for this issue.
401 m_tabWidget->setMinimumSize(newTabWidth, newTabHeight);
402 m_tabWidget->adjustSize();
403 QCoreApplication::processEvents();
404 m_tabWidget->setMinimumSize(500, 400);
407 void MainWindow::statusChanged(RemoteView::RemoteStatus status)
409 kDebug(5010) << status;
411 // the remoteview is already deleted, so don't show it; otherwise it would crash
412 if (status == RemoteView::Disconnecting || status == RemoteView::Disconnected)
413 return;
415 QString host = m_remoteViewList.at(m_currentRemoteView)->host();
417 QString iconName = "krdc";
418 QString message;
420 switch (status) {
421 case RemoteView::Connecting:
422 iconName = "network-connect";
423 message = i18n("Connecting to %1", host);
424 break;
425 case RemoteView::Authenticating:
426 iconName = "dialog-password";
427 message = i18n("Authenticating at %1", host);
428 break;
429 case RemoteView::Preparing:
430 iconName = "view-history";
431 message = i18n("Preparing connection to %1", host);
432 break;
433 case RemoteView::Connected:
434 iconName = "krdc";
435 message = i18n("Connected to %1", host);
437 // when started with command line fullscreen argument
438 if (m_switchFullscreenWhenConnected) {
439 m_switchFullscreenWhenConnected = false;
440 switchFullscreen();
443 m_bookmarkManager->addHistoryBookmark();
445 break;
446 default:
447 iconName = "krdc";
448 message = QString();
451 m_tabWidget->setTabIcon(m_tabWidget->currentIndex(), KIcon(iconName));
452 statusBar()->showMessage(message);
455 void MainWindow::takeScreenshot()
457 QPixmap snapshot = QPixmap::grabWidget(m_remoteViewList.at(m_currentRemoteView));
459 QApplication::clipboard()->setPixmap(snapshot);
462 void MainWindow::switchFullscreen()
464 kDebug(5010);
466 if (m_fullscreenWindow) {
467 show();
468 restoreGeometry(m_mainWindowGeometry);
470 m_fullscreenWindow->setWindowState(0);
471 m_fullscreenWindow->hide();
473 QScrollArea *scrollArea = createScrollArea(m_tabWidget, m_remoteViewList.at(m_currentRemoteView));
475 int currentTab = m_tabWidget->currentIndex();
476 m_tabWidget->insertTab(currentTab, scrollArea, m_tabWidget->tabIcon(currentTab), m_tabWidget->tabText(currentTab));
477 m_tabWidget->removeTab(m_tabWidget->currentIndex());
478 m_tabWidget->setCurrentIndex(currentTab);
480 resizeTabWidget(m_remoteViewList.at(m_currentRemoteView)->sizeHint().width(),
481 m_remoteViewList.at(m_currentRemoteView)->sizeHint().height());
483 if (m_toolBar) {
484 m_toolBar->hideAndDestroy();
485 m_toolBar->deleteLater();
486 m_toolBar = 0;
489 actionCollection()->action("switch_fullscreen")->setIcon(KIcon("view-fullscreen"));
490 actionCollection()->action("switch_fullscreen")->setText(i18n("Switch to Fullscreen Mode"));
492 m_fullscreenWindow->deleteLater();
494 m_fullscreenWindow = 0;
495 } else {
496 m_fullscreenWindow = new QWidget(this, Qt::Window);
497 m_fullscreenWindow->setWindowTitle(i18nc("window title when in fullscreen mode (for example displayed in tasklist)",
498 "KDE Remote Desktop Client (Fullscreen)"));
500 QScrollArea *scrollArea = createScrollArea(m_fullscreenWindow, m_remoteViewList.at(m_currentRemoteView));
501 scrollArea->setFrameShape(QFrame::NoFrame);
503 QVBoxLayout *fullscreenLayout = new QVBoxLayout(m_fullscreenWindow);
504 fullscreenLayout->setMargin(0);
505 fullscreenLayout->addWidget(scrollArea);
507 MinimizePixel *minimizePixel = new MinimizePixel(m_fullscreenWindow);
508 connect(minimizePixel, SIGNAL(rightClicked()), m_fullscreenWindow, SLOT(showMinimized()));
510 m_fullscreenWindow->show();
512 KToggleFullScreenAction::setFullScreen(m_fullscreenWindow, true);
514 // show the toolbar after we have switched to fullscreen mode
515 QTimer::singleShot(100, this, SLOT(showRemoteViewToolbar()));
517 m_mainWindowGeometry = saveGeometry();
518 hide();
522 QScrollArea *MainWindow::createScrollArea(QWidget *parent, RemoteView *remoteView)
524 RemoteViewScrollArea *scrollArea = new RemoteViewScrollArea(parent);
525 scrollArea->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
527 connect(scrollArea, SIGNAL(resized(int, int)), remoteView, SLOT(scaleResize(int, int)));
529 QPalette palette = scrollArea->palette();
530 palette.setColor(QPalette::Dark, Settings::backgroundColor());
531 scrollArea->setPalette(palette);
533 scrollArea->setBackgroundRole(QPalette::Dark);
534 scrollArea->setWidget(remoteView);
536 return scrollArea;
539 void MainWindow::logout()
541 kDebug(5010);
543 if (m_fullscreenWindow) { // first close fullscreen view
544 switchFullscreen();
547 QWidget *tmp = m_tabWidget->currentWidget();
549 m_remoteViewList.removeAt(m_currentRemoteView);
551 m_tabWidget->removeTab(m_tabWidget->currentIndex());
553 tmp->deleteLater();
556 void MainWindow::showLocalCursor(bool showLocalCursor)
558 kDebug(5010) << showLocalCursor;
560 m_remoteViewList.at(m_currentRemoteView)->showDotCursor(showLocalCursor ? RemoteView::CursorOn : RemoteView::CursorOff);
563 void MainWindow::viewOnly(bool viewOnly)
565 kDebug(5010) << viewOnly;
567 m_remoteViewList.at(m_currentRemoteView)->setViewOnly(viewOnly);
570 void MainWindow::grabAllKeys(bool grabAllKeys)
572 kDebug(5010);
574 m_remoteViewList.at(m_currentRemoteView)->setGrabAllKeys(grabAllKeys);
577 void MainWindow::scale(bool scale)
579 kDebug(5010);
581 m_remoteViewList.at(m_currentRemoteView)->enableScaling(scale);
584 void MainWindow::showRemoteViewToolbar()
586 kDebug(5010);
588 if (!m_toolBar) {
589 actionCollection()->action("switch_fullscreen")->setIcon(KIcon("view-restore"));
590 actionCollection()->action("switch_fullscreen")->setText(i18n("Switch to Window Mode"));
592 m_toolBar = new FloatingToolBar(m_fullscreenWindow, m_fullscreenWindow);
593 m_toolBar->setSide(FloatingToolBar::Top);
595 QLabel *hostLabel = new QLabel(m_remoteViewList.at(m_currentRemoteView)->url().prettyUrl(KUrl::RemoveTrailingSlash), m_toolBar);
596 hostLabel->setMargin(4);
597 QFont font(hostLabel->font());
598 font.setBold(true);
599 hostLabel->setFont(font);
600 m_toolBar->addWidget(hostLabel);
602 #if 0 //TODO: implement functionality
603 KComboBox *sessionComboBox = new KComboBox(m_toolBar);
604 sessionComboBox->setEditable(false);
605 sessionComboBox->addItem(i18n("Switch to..."));
606 for (int i = 0; i < m_remoteViewList.count(); i++) {
607 sessionComboBox->addItem(m_remoteViewList.at(i)->url().prettyUrl(KUrl::RemoveTrailingSlash));
609 sessionComboBox->setVisible(m_remoteViewList.count() > 1); // just show it if there are sessions to switch
610 m_toolBar->addWidget(sessionComboBox);
611 #endif
613 m_toolBar->addAction(actionCollection()->action("switch_fullscreen"));
615 QAction *minimizeAction = new QAction(m_toolBar);
616 minimizeAction->setIcon(KIcon("window-suppressed"));
617 minimizeAction->setText(i18n("Minimize Fullscreen Window"));
618 connect(minimizeAction, SIGNAL(triggered()), m_fullscreenWindow, SLOT(showMinimized()));
619 m_toolBar->addAction(minimizeAction);
621 m_toolBar->addAction(actionCollection()->action("take_screenshot"));
622 m_toolBar->addAction(actionCollection()->action("view_only"));
623 m_toolBar->addAction(actionCollection()->action("show_local_cursor"));
624 m_toolBar->addAction(actionCollection()->action("grab_all_keys"));
625 m_toolBar->addAction(actionCollection()->action("scale"));
626 m_toolBar->addAction(actionCollection()->action("logout"));
628 QAction *stickToolBarAction = new QAction(m_toolBar);
629 stickToolBarAction->setCheckable(true);
630 stickToolBarAction->setIcon(KIcon("object-locked"));
631 stickToolBarAction->setText(i18n("Stick Toolbar"));
632 connect(stickToolBarAction, SIGNAL(triggered(bool)), m_toolBar, SLOT(setSticky(bool)));
633 m_toolBar->addAction(stickToolBarAction);
636 m_toolBar->showAndAnimate();
639 void MainWindow::updateActionStatus()
641 kDebug(5010) << m_tabWidget->currentIndex();
643 bool enabled;
645 if ((m_showStartPage && (m_tabWidget->currentIndex() == 0)) ||
646 #ifdef BUILD_ZEROCONF
647 (m_zeroconfPage && (m_tabWidget->currentIndex() == m_tabWidget->indexOf(m_zeroconfPage))) ||
648 #endif
649 (!m_showStartPage && (m_tabWidget->currentIndex() < 0)))
650 enabled = false;
651 else
652 enabled = true;
654 actionCollection()->action("switch_fullscreen")->setEnabled(enabled);
655 actionCollection()->action("take_screenshot")->setEnabled(enabled);
656 actionCollection()->action("view_only")->setEnabled(enabled);
657 actionCollection()->action("grab_all_keys")->setEnabled(enabled);
658 actionCollection()->action("scale")->setEnabled(enabled);
659 actionCollection()->action("logout")->setEnabled(enabled);
661 bool viewOnlyChecked = false;
662 if (m_currentRemoteView >= 0)
663 viewOnlyChecked = enabled && m_remoteViewList.at(m_currentRemoteView)->viewOnly();
664 actionCollection()->action("view_only")->setChecked(viewOnlyChecked);
666 bool showLocalCursorChecked = false;
667 if (m_currentRemoteView >= 0)
668 showLocalCursorChecked = enabled && m_remoteViewList.at(m_currentRemoteView)->dotCursorState() == RemoteView::CursorOn;
669 actionCollection()->action("show_local_cursor")->setChecked(showLocalCursorChecked);
671 bool showLocalCursorVisible = false;
672 if (m_currentRemoteView >= 0)
673 showLocalCursorVisible = enabled && m_remoteViewList.at(m_currentRemoteView)->supportsLocalCursor();
674 actionCollection()->action("show_local_cursor")->setVisible(showLocalCursorVisible);
676 bool scaleVisible = false;
677 if (m_currentRemoteView >= 0)
678 scaleVisible = enabled && m_remoteViewList.at(m_currentRemoteView)->supportsScaling();
679 actionCollection()->action("scale")->setVisible(scaleVisible);
682 void MainWindow::preferences()
684 // An instance of your dialog could be already created and could be
685 // cached, in which case you want to display the cached dialog
686 // instead of creating another one
687 if (PreferencesDialog::showDialog("preferences"))
688 return;
690 // KConfigDialog didn't find an instance of this dialog, so lets
691 // create it:
692 PreferencesDialog *dialog = new PreferencesDialog(this, Settings::self());
694 // User edited the configuration - update your local copies of the
695 // configuration data
696 connect(dialog, SIGNAL(settingsChanged(const QString&)),
697 this, SLOT(updateConfiguration()));
699 dialog->show();
702 void MainWindow::updateConfiguration()
704 m_addressNavigator->setUrlEditable(Settings::normalUrlInputLine());
706 if (Settings::systemTrayIcon() && !m_systemTrayIcon) {
707 m_systemTrayIcon = new SystemTrayIcon(this);
708 m_systemTrayIcon->setVisible(true);
709 } else if (m_systemTrayIcon) {
710 delete m_systemTrayIcon;
711 m_systemTrayIcon = 0;
714 if (Settings::showStartPage() && !m_showStartPage)
715 createStartPage();
716 else if (!Settings::showStartPage() && m_showStartPage) {
717 m_tabWidget->removeTab(0);
718 m_showStartPage = false;
720 updateActionStatus();
722 // update the scroll areas background color
723 int numNonRemoteView = 0;
724 if (m_showStartPage)
725 numNonRemoteView++;
726 if (m_zeroconfPage)
727 numNonRemoteView++;
728 for (int i = numNonRemoteView; i < m_tabWidget->count(); i++) {
729 QPalette palette = m_tabWidget->widget(i)->palette();
730 palette.setColor(QPalette::Dark, Settings::backgroundColor());
731 m_tabWidget->widget(i)->setPalette(palette);
735 void MainWindow::quit()
737 if (KMessageBox::warningContinueCancel(this,
738 i18n("Are you sure you want to quit the KDE Remote Desktop Client?"),
739 i18n("Confirm Quit"),
740 KStandardGuiItem::quit(), KStandardGuiItem::cancel(),
741 "DoNotAskBeforeExit") == KMessageBox::Continue) {
743 if (Settings::rememberSessions()) { // remember open remote views for next startup
744 QStringList list;
745 for (int i = 0; i < m_remoteViewList.count(); i++) {
746 kDebug(5010) << m_remoteViewList.at(i)->url();
747 list.append(m_remoteViewList.at(i)->url().prettyUrl(KUrl::RemoveTrailingSlash));
749 Settings::setOpenSessions(list);
752 Settings::self()->writeConfig();
754 qApp->quit();
758 void MainWindow::configureNotifications()
760 KNotifyConfigWidget::configure(this);
763 void MainWindow::configureKeys()
765 KShortcutsDialog::configure(actionCollection());
768 void MainWindow::configureToolbars()
770 KEditToolBar edit(actionCollection());
771 connect(&edit, SIGNAL(newToolbarConfig()), this, SLOT(newToolbarConfig()));
772 edit.exec();
775 void MainWindow::showMenubar()
777 if (m_menubarAction->isChecked())
778 menuBar()->show();
779 else
780 menuBar()->hide();
783 void MainWindow::closeEvent(QCloseEvent *event)
785 event->ignore();
787 if (Settings::systemTrayIcon()) {
788 hide(); // just hide the mainwindow, keep it in systemtray
789 } else {
790 quit();
794 void MainWindow::tabChanged(int index)
796 kDebug(5010) << index;
798 int numNonRemoteView = 0;
799 if (m_showStartPage)
800 numNonRemoteView++;
801 if (m_zeroconfPage)
802 numNonRemoteView++;
804 m_currentRemoteView = index - numNonRemoteView;
806 QString tabTitle = m_tabWidget->tabText(index).remove('&');
808 setCaption(tabTitle == i18n("Start Page") ? QString() : tabTitle);
810 updateActionStatus();
813 void MainWindow::createStartPage()
815 m_showStartPage = true;
817 QWidget *startWidget = new QWidget(this);
818 startWidget->setStyleSheet("QWidget { background-color: palette(base) }");
820 QVBoxLayout *startLayout = new QVBoxLayout(startWidget);
822 QLabel *headerLabel = new QLabel(this);
823 headerLabel->setText(i18n("<h1>KDE Remote Desktop Client</h1><br /><br />What would you like to do?<br />"));
825 QLabel *headerIconLabel = new QLabel(this);
826 headerIconLabel->setPixmap(KIcon("krdc").pixmap(128));
828 QHBoxLayout *headerLayout = new QHBoxLayout;
829 headerLayout->setMargin(20);
830 headerLayout->addWidget(headerLabel, 1, Qt::AlignTop);
831 headerLayout->addWidget(headerIconLabel);
833 KPushButton *vncConnectButton = new KPushButton(this);
834 vncConnectButton->setStyleSheet("KPushButton { padding: 12px; margin: 10px; }");
835 vncConnectButton->setIcon(KIcon(actionCollection()->action("new_vnc_connection")->icon()));
836 vncConnectButton->setText(i18n("Connect to a VNC Remote Desktop"));
837 connect(vncConnectButton, SIGNAL(clicked()), SLOT(newVncConnection()));
838 #ifndef BUILD_VNC
839 vncConnectButton->setVisible(false);
840 #endif
842 KPushButton *nxConnectButton = new KPushButton(this);
843 nxConnectButton->setStyleSheet("KPushButton { padding: 12px; margin: 10px; }");
844 nxConnectButton->setIcon(KIcon(actionCollection()->action("new_nx_connection")->icon()));
845 nxConnectButton->setText(i18n("Connect to a NX Remote Desktop"));
846 connect(nxConnectButton, SIGNAL(clicked()), SLOT(newNxConnection()));
847 #ifndef BUILD_NX
848 nxConnectButton->setVisible(false);
849 #endif
851 KPushButton *rdpConnectButton = new KPushButton(this);
852 rdpConnectButton->setStyleSheet("KPushButton { padding: 12px; margin: 10px; }");
853 rdpConnectButton->setIcon(KIcon(actionCollection()->action("new_rdp_connection")->icon()));
854 rdpConnectButton->setText(i18n("Connect to a Windows Remote Desktop (RDP)"));
855 connect(rdpConnectButton, SIGNAL(clicked()), SLOT(newRdpConnection()));
856 #ifndef BUILD_RDP
857 rdpConnectButton->setVisible(false);
858 #endif
860 KPushButton *zeroconfButton = new KPushButton(this);
861 zeroconfButton->setStyleSheet("KPushButton { padding: 12px; margin: 10px; }");
862 zeroconfButton->setIcon(KIcon(actionCollection()->action("zeroconf_page")->icon()));
863 zeroconfButton->setText(i18n("Browse Remote Desktop Services on Local Network"));
864 connect(zeroconfButton, SIGNAL(clicked()), SLOT(createZeroconfPage()));
865 #ifndef BUILD_ZEROCONF
866 zeroconfButton->setVisible(false);
867 #endif
869 startLayout->addLayout(headerLayout);
870 startLayout->addWidget(vncConnectButton);
871 startLayout->addWidget(nxConnectButton);
872 startLayout->addWidget(rdpConnectButton);
873 startLayout->addWidget(zeroconfButton);
874 startLayout->addStretch();
876 m_tabWidget->insertTab(0, startWidget, KIcon("krdc"), i18n("Start Page"));
879 void MainWindow::newVncConnection()
881 m_addressNavigator->setUrl(KUrl("vnc://"));
882 m_addressNavigator->setFocus();
884 QToolTip::showText(m_addressNavigator->pos() + pos() + QPoint(m_addressNavigator->width(),
885 m_addressNavigator->height() + 20),
886 i18n("<html>Enter the address here.<br />"
887 "<i>Example: vncserver:1 (host:port / screen)</i></html>"), this);
890 void MainWindow::newNxConnection()
892 m_addressNavigator->setUrl(KUrl("nx://"));
893 m_addressNavigator->setFocus();
895 QToolTip::showText(m_addressNavigator->pos() + pos() + QPoint(m_addressNavigator->width(),
896 m_addressNavigator->height() + 20),
897 i18n("<html>Enter the address here.<br />"
898 "<i>Example: nxserver (host)</i></html>"), this);
901 void MainWindow::newRdpConnection()
903 m_addressNavigator->setUrl(KUrl("rdp://"));
904 m_addressNavigator->setFocus();
906 QToolTip::showText(m_addressNavigator->pos() + pos() + QPoint(m_addressNavigator->width(),
907 m_addressNavigator->height() + 20),
908 i18n("<html>Enter the address here. Port is optional.<br />"
909 "<i>Example: rdpserver:3389 (host:port)</i></html>"), this);
912 void MainWindow::createZeroconfPage()
914 #ifdef BUILD_ZEROCONF
915 if (m_zeroconfPage)
916 return;
918 m_zeroconfPage = new ZeroconfPage(this);
919 connect(m_zeroconfPage, SIGNAL(newConnection(const KUrl, bool)), this, SLOT(newConnection(const KUrl, bool)));
920 connect(m_zeroconfPage, SIGNAL(closeZeroconfPage()), this, SLOT(closeZeroconfPage()));
921 int zeroconfTabIndex = m_tabWidget->insertTab(m_showStartPage ? 1 : 0, m_zeroconfPage, KIcon("krdc"), i18n("Browse Local Network"));
922 m_tabWidget->setCurrentIndex(zeroconfTabIndex);
923 #endif
926 void MainWindow::closeZeroconfPage()
928 #ifdef BUILD_ZEROCONF
929 int index = m_tabWidget->indexOf(m_zeroconfPage);
930 m_tabWidget->removeTab(index);
931 m_zeroconfPage->deleteLater();
932 m_zeroconfPage = 0;
933 tabChanged(index); // force update again because m_zeroconfPage was not null before
934 #endif
937 QList<RemoteView *> MainWindow::remoteViewList() const
939 return m_remoteViewList;
942 int MainWindow::currentRemoteView() const
944 return m_currentRemoteView;
947 #include "mainwindow.moc"