Use KDE standards for settings menu.
[kdenetwork.git] / krdc / mainwindow.cpp
blob6146f89b1d4fe45a944a0cb6a7812e12b1e40d26
1 /****************************************************************************
2 **
3 ** Copyright (C) 2007 - 2008 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
45 #ifdef BUILD_TEST
46 #include "testview.h"
47 #endif
49 #include <KAction>
50 #include <KActionCollection>
51 #include <KActionMenu>
52 #include <KApplication>
53 #include <KComboBox>
54 #include <KEditToolBar>
55 #include <KIcon>
56 #include <KLocale>
57 #include <KMenuBar>
58 #include <KMessageBox>
59 #include <KNotifyConfigWidget>
60 #include <KProcess>
61 #include <KPushButton>
62 #include <KShortcut>
63 #include <KShortcutsDialog>
64 #include <KStatusBar>
65 #include <KTabWidget>
66 #include <KToggleAction>
67 #include <KToggleFullScreenAction>
68 #include <KUrlNavigator>
70 #include <QClipboard>
71 #include <QCloseEvent>
72 #include <QDesktopWidget>
73 #include <QDockWidget>
74 #include <QFontMetrics>
75 #include <QHeaderView>
76 #include <QLabel>
77 #include <QLayout>
78 #include <QScrollArea>
79 #include <QTimer>
80 #include <QToolButton>
81 #include <QToolTip>
82 #include <QTreeView>
84 MainWindow::MainWindow(QWidget *parent)
85 : KXmlGuiWindow(parent),
86 m_fullscreenWindow(0),
87 m_toolBar(0),
88 m_topBottomBorder(0),
89 m_leftRightBorder(0),
90 m_currentRemoteView(-1),
91 m_showStartPage(false),
92 m_systemTrayIcon(0),
93 m_zeroconfPage(0)
95 setupActions();
97 setStandardToolBarMenuEnabled(true);
99 m_tabWidget = new KTabWidget(this);
100 m_tabWidget->setCloseButtonEnabled(true);
101 connect(m_tabWidget, SIGNAL(closeRequest(QWidget *)), SLOT(closeTab(QWidget *)));
103 m_tabWidget->setMinimumSize(600, 400);
104 setCentralWidget(m_tabWidget);
106 QDockWidget *remoteDesktopsDockWidget = new QDockWidget(this);
107 remoteDesktopsDockWidget->setObjectName("remoteDesktopsDockWidget"); // required for saving position / state
108 remoteDesktopsDockWidget->setWindowTitle(i18n("Remote desktops"));
109 QFontMetrics fontMetrics(remoteDesktopsDockWidget->font());
110 remoteDesktopsDockWidget->setMinimumWidth(fontMetrics.width("vnc://192.168.100.100:6000"));
111 actionCollection()->addAction("remote_desktop_dockwidget",
112 remoteDesktopsDockWidget->toggleViewAction());
113 QTreeView *remoteDesktopsTreeView = new QTreeView(remoteDesktopsDockWidget);
114 RemoteDesktopsModel *remoteDesktopsModel = new RemoteDesktopsModel(this);
115 connect(remoteDesktopsModel, SIGNAL(modelReset()), remoteDesktopsTreeView, SLOT(expandAll()));
116 remoteDesktopsTreeView->setModel(remoteDesktopsModel);
117 remoteDesktopsTreeView->header()->hide();
118 remoteDesktopsTreeView->expandAll();
119 connect(remoteDesktopsTreeView, SIGNAL(doubleClicked(const QModelIndex &)),
120 SLOT(openFromDockWidget(const QModelIndex &)));
122 remoteDesktopsDockWidget->setWidget(remoteDesktopsTreeView);
123 addDockWidget(Qt::LeftDockWidgetArea, remoteDesktopsDockWidget);
125 createGUI("krdcui.rc");
127 if (Settings::systemTrayIcon()) {
128 m_systemTrayIcon = new SystemTrayIcon(this);
129 m_systemTrayIcon->setVisible(true);
132 connect(m_tabWidget, SIGNAL(currentChanged(int)), SLOT(tabChanged(int)));
134 statusBar()->showMessage(i18n("KDE Remote Desktop Client started"));
136 updateActionStatus(); // disable remote view actions
138 if (Settings::showStartPage())
139 createStartPage();
141 setAutoSaveSettings(); // e.g toolbar position, mainwindow size, ...
143 m_addressNavigator->setFocus();
145 if (Settings::rememberSessions()) // give some time to create and show the window first
146 QTimer::singleShot(100, this, SLOT(restoreOpenSessions()));
149 MainWindow::~MainWindow()
153 void MainWindow::setupActions()
155 QAction *vncConnectionAction = actionCollection()->addAction("new_vnc_connection");
156 vncConnectionAction->setText(i18n("New VNC Connection..."));
157 vncConnectionAction->setIcon(KIcon("network-connect"));
158 connect(vncConnectionAction, SIGNAL(triggered()), SLOT(newVncConnection()));
159 #ifndef BUILD_VNC
160 vncConnectionAction->deleteLater();
161 #endif
163 QAction *nxConnectionAction = actionCollection()->addAction("new_nx_connection");
164 nxConnectionAction->setText(i18n("New NX Connection..."));
165 nxConnectionAction->setIcon(KIcon("network-connect"));
166 connect(nxConnectionAction, SIGNAL(triggered()), SLOT(newNxConnection()));
167 #ifndef BUILD_NX
168 nxConnectionAction->deleteLater();
169 #endif
171 QAction *rdpConnectionAction = actionCollection()->addAction("new_rdp_connection");
172 rdpConnectionAction->setText(i18n("New RDP Connection..."));
173 rdpConnectionAction->setIcon(KIcon("network-connect"));
174 connect(rdpConnectionAction, SIGNAL(triggered()), SLOT(newRdpConnection()));
175 #ifndef BUILD_RDP
176 rdpConnectionAction->deleteLater();
177 #endif
179 QAction *zeroconfAction = actionCollection()->addAction("zeroconf_page");
180 zeroconfAction->setText(i18n("Browse Remote Desktop Services on Local Network..."));
181 zeroconfAction->setIcon(KIcon("network-connect"));
182 connect(zeroconfAction, SIGNAL(triggered()), SLOT(createZeroconfPage()));
183 #ifndef BUILD_ZEROCONF
184 zeroconfAction->deleteLater();
185 #endif
187 QAction *screenshotAction = actionCollection()->addAction("take_screenshot");
188 screenshotAction->setText(i18n("Copy Screenshot to Clipboard"));
189 screenshotAction->setIcon(KIcon("ksnapshot"));
190 connect(screenshotAction, SIGNAL(triggered()), SLOT(takeScreenshot()));
192 QAction *fullscreenAction = actionCollection()->addAction("switch_fullscreen");
193 fullscreenAction->setText(i18n("Switch to Fullscreen Mode"));
194 fullscreenAction->setIcon(KIcon("view-fullscreen"));
195 connect(fullscreenAction, SIGNAL(triggered()), SLOT(switchFullscreen()));
197 QAction *viewOnlyAction = actionCollection()->addAction("view_only");
198 viewOnlyAction->setCheckable(true);
199 viewOnlyAction->setText(i18n("View Only"));
200 viewOnlyAction->setIcon(KIcon("document-preview"));
201 connect(viewOnlyAction, SIGNAL(triggered(bool)), SLOT(viewOnly(bool)));
203 QAction *disconnectAction = actionCollection()->addAction("disconnect");
204 disconnectAction->setText(i18n("Disconnect"));
205 disconnectAction->setIcon(KIcon("system-log-out"));
206 connect(disconnectAction, SIGNAL(triggered()), SLOT(disconnect()));
208 QAction *showLocalCursorAction = actionCollection()->addAction("show_local_cursor");
209 showLocalCursorAction->setCheckable(true);
210 showLocalCursorAction->setIcon(KIcon("input-mouse"));
211 showLocalCursorAction->setText(i18n("Show Local Cursor"));
212 connect(showLocalCursorAction, SIGNAL(triggered(bool)), SLOT(showLocalCursor(bool)));
214 QAction *grabAllKeysAction = actionCollection()->addAction("grab_all_keys");
215 grabAllKeysAction->setCheckable(true);
216 grabAllKeysAction->setIcon(KIcon("configure-shortcuts"));
217 grabAllKeysAction->setText(i18n("Grab all possible keys"));
218 connect(grabAllKeysAction, SIGNAL(triggered(bool)), SLOT(grabAllKeys(bool)));
220 QAction *scaleAction = actionCollection()->addAction("scale");
221 scaleAction->setCheckable(true);
222 scaleAction->setIcon(KIcon("zoom-fit-best"));
223 scaleAction->setText(i18n("Scale remote screen to fit window size"));
224 connect(scaleAction, SIGNAL(triggered(bool)), SLOT(scale(bool)));
226 QAction *quitAction = KStandardAction::quit(this, SLOT(quit()), actionCollection());
227 actionCollection()->addAction("quit", quitAction);
228 KStandardAction::preferences(this, SLOT(preferences()), actionCollection());
229 KStandardAction::configureToolbars(this, SLOT(configureToolbars()), actionCollection());
230 KStandardAction::keyBindings(this, SLOT(configureKeys()), actionCollection());
231 QAction *cinfigNotifyAction = KStandardAction::configureNotifications(this, SLOT(configureNotifications()), actionCollection());
232 cinfigNotifyAction->setVisible(false);
233 m_menubarAction = KStandardAction::showMenubar(this, SLOT(showMenubar()), actionCollection());
234 m_menubarAction->setChecked(!menuBar()->isHidden());
236 QString initialProtocol;
237 #ifdef BUILD_RDP
238 initialProtocol = "rdp";
239 #endif
240 #ifdef BUILD_NX
241 initialProtocol = "nx";
242 #endif
243 #ifdef BUILD_VNC
244 initialProtocol = "vnc";
245 #endif
247 m_addressNavigator = new KUrlNavigator(0, KUrl(initialProtocol + "://"), this);
248 m_addressNavigator->setCustomProtocols(QStringList()
249 #ifdef BUILD_VNC
250 << "vnc"
251 #endif
252 #ifdef BUILD_NX
253 << "nx"
254 #endif
255 #ifdef BUILD_RDP
256 << "rdp"
257 #endif
258 #ifdef BUILD_TEST
259 << "test"
260 #endif
262 m_addressNavigator->setUrlEditable(Settings::normalUrlInputLine());
263 connect(m_addressNavigator, SIGNAL(returnPressed()), SLOT(newConnection()));
265 QLabel *addressLabel = new QLabel(i18n("Remote desktop:"), this);
267 QWidget *addressWidget = new QWidget(this);
268 QHBoxLayout *addressLayout = new QHBoxLayout(addressWidget);
269 addressLayout->setMargin(0);
270 addressLayout->addWidget(addressLabel);
271 addressLayout->addWidget(m_addressNavigator, 1);
273 KAction *addressLineAction = new KAction(i18nc("Title for remote address input action", "Address"), this);
274 actionCollection()->addAction("address_line", addressLineAction);
275 addressLineAction->setDefaultWidget(addressWidget);
277 QAction *gotoAction = actionCollection()->addAction("goto_address");
278 gotoAction->setText(i18n("Goto Address"));
279 gotoAction->setIcon(KIcon("go-jump-locationbar"));
280 connect(gotoAction, SIGNAL(triggered()), SLOT(newConnection()));
282 KActionMenu *bookmarkMenu = new KActionMenu(i18n("Bookmarks"), actionCollection());
283 m_bookmarkManager = new BookmarkManager(actionCollection(), bookmarkMenu->menu(), this);
284 actionCollection()->addAction("bookmark" , bookmarkMenu);
285 connect(m_bookmarkManager, SIGNAL(openUrl(KUrl)), SLOT(newConnection(KUrl)));
288 void MainWindow::restoreOpenSessions()
290 QStringList list = Settings::openSessions();
291 QStringList::Iterator it = list.begin();
292 QStringList::Iterator end = list.end();
293 while (it != end) {
294 newConnection(*it);
295 ++it;
299 void MainWindow::newConnection(const KUrl &newUrl, bool switchFullscreenWhenConnected)
301 m_switchFullscreenWhenConnected = switchFullscreenWhenConnected;
303 KUrl url = newUrl.isEmpty() ? m_addressNavigator->uncommittedUrl() : newUrl;
305 if (!url.isValid() || (url.host().isEmpty() && url.port() < 0)
306 || !url.path().isEmpty()) {
307 KMessageBox::error(this,
308 i18n("The entered address does not have the required form."),
309 i18n("Malformed URL"));
310 return;
313 m_addressNavigator->setUrl(KUrl(url.scheme().toLower() + "://"));
315 RemoteView *view = 0;
317 if (url.scheme().compare("vnc", Qt::CaseInsensitive) == 0) {
318 #ifdef BUILD_VNC
319 view = new VncView(this, url);
320 #endif
321 } else if (url.scheme().compare("nx", Qt::CaseInsensitive) == 0) {
322 #ifdef BUILD_NX
323 view = new NxView(this, url);
324 #endif
325 } else if (url.scheme().compare("rdp", Qt::CaseInsensitive) == 0) {
326 #ifdef BUILD_RDP
327 view = new RdpView(this, url);
328 #endif
329 } else if (url.scheme().compare("test", Qt::CaseInsensitive) == 0) {
330 #ifdef BUILD_TEST
331 view = new TestView(this, url);
332 #endif
333 } else
335 KMessageBox::error(this,
336 i18n("The entered address cannot be handled."),
337 i18n("Unusable URL"));
338 return;
341 if (!view) {
342 KMessageBox::error(this, i18n("Support for %1:// has not been enabled during build.",
343 url.scheme().toLower()),
344 i18n("Unusable URL"));
345 return;
348 connect(view, SIGNAL(changeSize(int, int)), this, SLOT(resizeTabWidget(int, int)));
349 connect(view, SIGNAL(statusChanged(RemoteView::RemoteStatus)), this, SLOT(statusChanged(RemoteView::RemoteStatus)));
351 m_remoteViewList.append(view);
353 view->resize(0, 0);
355 int numNonRemoteView = 0;
356 if (m_showStartPage)
357 numNonRemoteView++;
358 if (m_zeroconfPage)
359 numNonRemoteView++;
361 QScrollArea *scrollArea = createScrollArea(m_tabWidget, m_remoteViewList.at(m_remoteViewList.count() - 1));
363 int newIndex = m_tabWidget->addTab(scrollArea, KIcon("krdc"), url.prettyUrl(KUrl::RemoveTrailingSlash));
364 m_tabWidget->setCurrentIndex(newIndex);
365 tabChanged(newIndex); // force to update m_currentRemoteView (tabChanged is not emitted when start page has been disabled)
367 view->start();
370 void MainWindow::openFromDockWidget(const QModelIndex &index)
372 QString data = index.data(Qt::UserRole).toString();
373 if (!data.isEmpty()) {
374 KUrl url(data);
375 // first check if url has already been opened; in case show the tab
376 for (int i = 0; i < m_remoteViewList.count(); i++) {
377 if (m_remoteViewList.at(i)->url() == url) {
378 int numNonRemoteView = 0;
379 if (m_showStartPage)
380 numNonRemoteView++;
381 if (m_zeroconfPage)
382 numNonRemoteView++;
383 m_tabWidget->setCurrentIndex(i + numNonRemoteView);
384 return;
387 newConnection(url);
391 void MainWindow::resizeTabWidget(int w, int h)
393 kDebug(5010) << "tabwidget resize: w: " << w << ", h: " << h;
395 if (m_topBottomBorder == 0) { // the values are not cached yet
396 QScrollArea *tmp = qobject_cast<QScrollArea *>(m_tabWidget->currentWidget());
398 m_leftRightBorder = m_tabWidget->width() - m_tabWidget->currentWidget()->width() + (2 * tmp->frameWidth());
399 m_topBottomBorder = m_tabWidget->height() - m_tabWidget->currentWidget()->height() + (2 * tmp->frameWidth());
401 kDebug(5010) << "tabwidget border: w: " << m_leftRightBorder << ", h: " << m_topBottomBorder;
404 int newTabWidth = w + m_leftRightBorder;
405 int newTabHeight = h + m_topBottomBorder;
407 QSize newWindowSize = size() - m_tabWidget->size() + QSize(newTabWidth, newTabHeight);
409 QSize desktopSize = QSize(QApplication::desktop()->availableGeometry().width(),
410 QApplication::desktop()->availableGeometry().height());
412 if ((newWindowSize.height() >= desktopSize.height()) || (newWindowSize.width() >= desktopSize.width())) {
413 kDebug(5010) << "remote desktop needs more place than available -> show window maximized";
414 setWindowState(windowState() | Qt::WindowMaximized);
415 return;
418 //WORKAROUND: QTabWidget resize problem. Let's see if there is a clean solution for this issue.
419 m_tabWidget->setMinimumSize(newTabWidth, newTabHeight);
420 m_tabWidget->adjustSize();
421 QCoreApplication::processEvents();
422 m_tabWidget->setMinimumSize(500, 400);
425 void MainWindow::statusChanged(RemoteView::RemoteStatus status)
427 kDebug(5010) << status;
429 // the remoteview is already deleted, so don't show it; otherwise it would crash
430 if (status == RemoteView::Disconnecting || status == RemoteView::Disconnected)
431 return;
433 QString host = m_remoteViewList.at(m_currentRemoteView)->host();
435 QString iconName = "krdc";
436 QString message;
438 switch (status) {
439 case RemoteView::Connecting:
440 iconName = "network-connect";
441 message = i18n("Connecting to %1", host);
442 break;
443 case RemoteView::Authenticating:
444 iconName = "dialog-password";
445 message = i18n("Authenticating at %1", host);
446 break;
447 case RemoteView::Preparing:
448 iconName = "view-history";
449 message = i18n("Preparing connection to %1", host);
450 break;
451 case RemoteView::Connected:
452 iconName = "krdc";
453 message = i18n("Connected to %1", host);
455 // when started with command line fullscreen argument
456 if (m_switchFullscreenWhenConnected) {
457 m_switchFullscreenWhenConnected = false;
458 switchFullscreen();
461 m_bookmarkManager->addHistoryBookmark();
463 break;
464 default:
465 break;
468 m_tabWidget->setTabIcon(m_tabWidget->currentIndex(), KIcon(iconName));
469 statusBar()->showMessage(message);
472 void MainWindow::takeScreenshot()
474 QPixmap snapshot = QPixmap::grabWidget(m_remoteViewList.at(m_currentRemoteView));
476 QApplication::clipboard()->setPixmap(snapshot);
479 void MainWindow::switchFullscreen()
481 kDebug(5010);
483 if (m_fullscreenWindow) {
484 show();
485 restoreGeometry(m_mainWindowGeometry);
487 m_fullscreenWindow->setWindowState(0);
488 m_fullscreenWindow->hide();
490 QScrollArea *scrollArea = createScrollArea(m_tabWidget, m_remoteViewList.at(m_currentRemoteView));
492 int currentTab = m_tabWidget->currentIndex();
493 m_tabWidget->insertTab(currentTab, scrollArea, m_tabWidget->tabIcon(currentTab), m_tabWidget->tabText(currentTab));
494 m_tabWidget->removeTab(m_tabWidget->currentIndex());
495 m_tabWidget->setCurrentIndex(currentTab);
497 resizeTabWidget(m_remoteViewList.at(m_currentRemoteView)->sizeHint().width(),
498 m_remoteViewList.at(m_currentRemoteView)->sizeHint().height());
500 if (m_toolBar) {
501 m_toolBar->hideAndDestroy();
502 m_toolBar->deleteLater();
503 m_toolBar = 0;
506 actionCollection()->action("switch_fullscreen")->setIcon(KIcon("view-fullscreen"));
507 actionCollection()->action("switch_fullscreen")->setText(i18n("Switch to Fullscreen Mode"));
509 m_fullscreenWindow->deleteLater();
511 m_fullscreenWindow = 0;
512 } else {
513 m_fullscreenWindow = new QWidget(this, Qt::Window);
514 m_fullscreenWindow->setWindowTitle(i18nc("window title when in fullscreen mode (for example displayed in tasklist)",
515 "KDE Remote Desktop Client (Fullscreen)"));
517 QScrollArea *scrollArea = createScrollArea(m_fullscreenWindow, m_remoteViewList.at(m_currentRemoteView));
518 scrollArea->setFrameShape(QFrame::NoFrame);
520 QVBoxLayout *fullscreenLayout = new QVBoxLayout(m_fullscreenWindow);
521 fullscreenLayout->setMargin(0);
522 fullscreenLayout->addWidget(scrollArea);
524 MinimizePixel *minimizePixel = new MinimizePixel(m_fullscreenWindow);
525 minimizePixel->winId(); // force it to be a native widget (prevents problem with QX11EmbedContainer)
526 connect(minimizePixel, SIGNAL(rightClicked()), m_fullscreenWindow, SLOT(showMinimized()));
528 m_fullscreenWindow->show();
530 KToggleFullScreenAction::setFullScreen(m_fullscreenWindow, true);
532 // show the toolbar after we have switched to fullscreen mode
533 // Note: there is a race condition here, if the timer fires before the window is
534 // resized, the toolbar is not shown.
535 QTimer::singleShot(500, this, SLOT(showRemoteViewToolbar()));
537 m_mainWindowGeometry = saveGeometry();
538 hide();
542 QScrollArea *MainWindow::createScrollArea(QWidget *parent, RemoteView *remoteView)
544 RemoteViewScrollArea *scrollArea = new RemoteViewScrollArea(parent);
545 scrollArea->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
547 connect(scrollArea, SIGNAL(resized(int, int)), remoteView, SLOT(scaleResize(int, int)));
549 QPalette palette = scrollArea->palette();
550 palette.setColor(QPalette::Dark, Settings::backgroundColor());
551 scrollArea->setPalette(palette);
553 scrollArea->setBackgroundRole(QPalette::Dark);
554 scrollArea->setWidget(remoteView);
556 return scrollArea;
559 void MainWindow::disconnect()
561 kDebug(5010);
563 if (m_fullscreenWindow) { // first close fullscreen view
564 switchFullscreen();
567 QWidget *tmp = m_tabWidget->currentWidget();
569 m_remoteViewList.removeAt(m_currentRemoteView);
571 m_tabWidget->removeTab(m_tabWidget->currentIndex());
573 tmp->deleteLater();
576 void MainWindow::closeTab(QWidget *widget)
578 int index = m_tabWidget->indexOf(widget);
580 kDebug(5010) << index;
582 if (m_showStartPage && index == 0) {
583 KMessageBox::information(this, i18n("The start page cannot be closed. "
584 "If you want to disable it, you can do so in the settings."));
585 return;
588 #ifdef BUILD_ZEROCONF
589 if (widget == m_zeroconfPage) {
590 closeZeroconfPage();
591 return;
593 #endif
595 int numNonRemoteView = 0;
596 if (m_showStartPage)
597 numNonRemoteView++;
598 if (m_zeroconfPage)
599 numNonRemoteView++;
601 if (index - numNonRemoteView >= 0)
602 m_remoteViewList.removeAt(index - numNonRemoteView);
604 m_tabWidget->removeTab(index);
606 widget->deleteLater();
609 void MainWindow::showLocalCursor(bool showLocalCursor)
611 kDebug(5010) << showLocalCursor;
613 m_remoteViewList.at(m_currentRemoteView)->showDotCursor(showLocalCursor ? RemoteView::CursorOn : RemoteView::CursorOff);
616 void MainWindow::viewOnly(bool viewOnly)
618 kDebug(5010) << viewOnly;
620 m_remoteViewList.at(m_currentRemoteView)->setViewOnly(viewOnly);
623 void MainWindow::grabAllKeys(bool grabAllKeys)
625 kDebug(5010);
627 m_remoteViewList.at(m_currentRemoteView)->setGrabAllKeys(grabAllKeys);
630 void MainWindow::scale(bool scale)
632 kDebug(5010);
634 m_remoteViewList.at(m_currentRemoteView)->enableScaling(scale);
637 void MainWindow::showRemoteViewToolbar()
639 kDebug(5010);
641 if (!m_toolBar) {
642 actionCollection()->action("switch_fullscreen")->setIcon(KIcon("view-restore"));
643 actionCollection()->action("switch_fullscreen")->setText(i18n("Switch to Window Mode"));
645 m_toolBar = new FloatingToolBar(m_fullscreenWindow, m_fullscreenWindow);
646 m_toolBar->winId(); // force it to be a native widget (prevents problem with QX11EmbedContainer)
647 m_toolBar->setSide(FloatingToolBar::Top);
649 QLabel *hostLabel = new QLabel(m_remoteViewList.at(m_currentRemoteView)->url().prettyUrl(KUrl::RemoveTrailingSlash), m_toolBar);
650 hostLabel->setMargin(4);
651 QFont font(hostLabel->font());
652 font.setBold(true);
653 hostLabel->setFont(font);
654 m_toolBar->addWidget(hostLabel);
656 #if 0 //TODO: implement functionality
657 KComboBox *sessionComboBox = new KComboBox(m_toolBar);
658 sessionComboBox->setEditable(false);
659 sessionComboBox->addItem(i18n("Switch to..."));
660 for (int i = 0; i < m_remoteViewList.count(); i++) {
661 sessionComboBox->addItem(m_remoteViewList.at(i)->url().prettyUrl(KUrl::RemoveTrailingSlash));
663 sessionComboBox->setVisible(m_remoteViewList.count() > 1); // just show it if there are sessions to switch
664 m_toolBar->addWidget(sessionComboBox);
665 #endif
667 m_toolBar->addAction(actionCollection()->action("switch_fullscreen"));
669 QAction *minimizeAction = new QAction(m_toolBar);
670 minimizeAction->setIcon(KIcon("window-suppressed"));
671 minimizeAction->setText(i18n("Minimize Fullscreen Window"));
672 connect(minimizeAction, SIGNAL(triggered()), m_fullscreenWindow, SLOT(showMinimized()));
673 m_toolBar->addAction(minimizeAction);
675 m_toolBar->addAction(actionCollection()->action("take_screenshot"));
676 m_toolBar->addAction(actionCollection()->action("view_only"));
677 m_toolBar->addAction(actionCollection()->action("show_local_cursor"));
678 m_toolBar->addAction(actionCollection()->action("grab_all_keys"));
679 m_toolBar->addAction(actionCollection()->action("scale"));
680 m_toolBar->addAction(actionCollection()->action("disconnect"));
682 QAction *stickToolBarAction = new QAction(m_toolBar);
683 stickToolBarAction->setCheckable(true);
684 stickToolBarAction->setIcon(KIcon("object-locked"));
685 stickToolBarAction->setText(i18n("Stick Toolbar"));
686 connect(stickToolBarAction, SIGNAL(triggered(bool)), m_toolBar, SLOT(setSticky(bool)));
687 m_toolBar->addAction(stickToolBarAction);
690 m_toolBar->showAndAnimate();
693 void MainWindow::updateActionStatus()
695 kDebug(5010) << m_tabWidget->currentIndex();
697 bool enabled;
699 if ((m_showStartPage && (m_tabWidget->currentIndex() == 0)) ||
700 #ifdef BUILD_ZEROCONF
701 (m_zeroconfPage && (m_tabWidget->currentIndex() == m_tabWidget->indexOf(m_zeroconfPage))) ||
702 #endif
703 (!m_showStartPage && (m_tabWidget->currentIndex() < 0)))
704 enabled = false;
705 else
706 enabled = true;
708 actionCollection()->action("switch_fullscreen")->setEnabled(enabled);
709 actionCollection()->action("take_screenshot")->setEnabled(enabled);
710 actionCollection()->action("view_only")->setEnabled(enabled);
711 actionCollection()->action("grab_all_keys")->setEnabled(enabled);
712 actionCollection()->action("scale")->setEnabled(enabled);
713 actionCollection()->action("disconnect")->setEnabled(enabled);
715 bool viewOnlyChecked = false;
716 if (m_currentRemoteView >= 0)
717 viewOnlyChecked = enabled && m_remoteViewList.at(m_currentRemoteView)->viewOnly();
718 actionCollection()->action("view_only")->setChecked(viewOnlyChecked);
720 bool showLocalCursorChecked = false;
721 if (m_currentRemoteView >= 0)
722 showLocalCursorChecked = enabled && m_remoteViewList.at(m_currentRemoteView)->dotCursorState() == RemoteView::CursorOn;
723 actionCollection()->action("show_local_cursor")->setChecked(showLocalCursorChecked);
725 bool showLocalCursorVisible = false;
726 if (m_currentRemoteView >= 0)
727 showLocalCursorVisible = enabled && m_remoteViewList.at(m_currentRemoteView)->supportsLocalCursor();
728 actionCollection()->action("show_local_cursor")->setVisible(showLocalCursorVisible);
730 bool scaleVisible = false;
731 if (m_currentRemoteView >= 0)
732 scaleVisible = enabled && m_remoteViewList.at(m_currentRemoteView)->supportsScaling();
733 actionCollection()->action("scale")->setVisible(scaleVisible);
736 void MainWindow::preferences()
738 // An instance of your dialog could be already created and could be
739 // cached, in which case you want to display the cached dialog
740 // instead of creating another one
741 if (PreferencesDialog::showDialog("preferences"))
742 return;
744 // KConfigDialog didn't find an instance of this dialog, so lets
745 // create it:
746 PreferencesDialog *dialog = new PreferencesDialog(this, Settings::self());
748 // User edited the configuration - update your local copies of the
749 // configuration data
750 connect(dialog, SIGNAL(settingsChanged(const QString&)),
751 this, SLOT(updateConfiguration()));
753 dialog->show();
756 void MainWindow::updateConfiguration()
758 m_addressNavigator->setUrlEditable(Settings::normalUrlInputLine());
760 if (Settings::systemTrayIcon() && !m_systemTrayIcon) {
761 m_systemTrayIcon = new SystemTrayIcon(this);
762 m_systemTrayIcon->setVisible(true);
763 } else if (m_systemTrayIcon) {
764 delete m_systemTrayIcon;
765 m_systemTrayIcon = 0;
768 if (Settings::showStartPage() && !m_showStartPage)
769 createStartPage();
770 else if (!Settings::showStartPage() && m_showStartPage) {
771 m_tabWidget->removeTab(0);
772 m_showStartPage = false;
774 updateActionStatus();
776 // update the scroll areas background color
777 int numNonRemoteView = 0;
778 if (m_showStartPage)
779 numNonRemoteView++;
780 if (m_zeroconfPage)
781 numNonRemoteView++;
782 for (int i = numNonRemoteView; i < m_tabWidget->count(); i++) {
783 QPalette palette = m_tabWidget->widget(i)->palette();
784 palette.setColor(QPalette::Dark, Settings::backgroundColor());
785 m_tabWidget->widget(i)->setPalette(palette);
788 // Send update configuration message to all views
789 for (int i = 0; i < m_remoteViewList.count(); i++) {
790 m_remoteViewList.at(i)->updateConfiguration();
795 void MainWindow::quit()
797 bool haveRemoteConnections = m_remoteViewList.count();
798 if (!haveRemoteConnections || KMessageBox::warningContinueCancel(this,
799 i18n("Are you sure you want to quit the KDE Remote Desktop Client?"),
800 i18n("Confirm Quit"),
801 KStandardGuiItem::quit(), KStandardGuiItem::cancel(),
802 "DoNotAskBeforeExit") == KMessageBox::Continue) {
804 if (Settings::rememberSessions()) { // remember open remote views for next startup
805 QStringList list;
806 for (int i = 0; i < m_remoteViewList.count(); i++) {
807 kDebug(5010) << m_remoteViewList.at(i)->url();
808 list.append(m_remoteViewList.at(i)->url().prettyUrl(KUrl::RemoveTrailingSlash));
810 Settings::setOpenSessions(list);
813 Settings::self()->writeConfig();
815 qApp->quit();
819 void MainWindow::configureNotifications()
821 KNotifyConfigWidget::configure(this);
824 void MainWindow::configureKeys()
826 KShortcutsDialog::configure(actionCollection());
829 void MainWindow::configureToolbars()
831 KEditToolBar edit(actionCollection());
832 connect(&edit, SIGNAL(newToolbarConfig()), this, SLOT(newToolbarConfig()));
833 edit.exec();
836 void MainWindow::showMenubar()
838 if (m_menubarAction->isChecked())
839 menuBar()->show();
840 else
841 menuBar()->hide();
844 void MainWindow::closeEvent(QCloseEvent *event)
846 event->ignore();
848 if (Settings::systemTrayIcon()) {
849 hide(); // just hide the mainwindow, keep it in systemtray
850 } else {
851 quit();
855 void MainWindow::tabChanged(int index)
857 kDebug(5010) << index;
859 int numNonRemoteView = 0;
860 if (m_showStartPage)
861 numNonRemoteView++;
862 if (m_zeroconfPage)
863 numNonRemoteView++;
865 m_currentRemoteView = index - numNonRemoteView;
867 QString tabTitle = m_tabWidget->tabText(index).remove('&');
869 setCaption(tabTitle == i18n("Start Page") ? QString() : tabTitle);
871 updateActionStatus();
874 void MainWindow::createStartPage()
876 m_showStartPage = true;
878 QWidget *startWidget = new QWidget(this);
879 startWidget->setStyleSheet("QWidget { background-color: palette(base) }");
881 QVBoxLayout *startLayout = new QVBoxLayout(startWidget);
883 QLabel *headerLabel = new QLabel(this);
884 headerLabel->setText(i18n("<h1>KDE Remote Desktop Client</h1><br /><br />What would you like to do?<br />"));
886 QLabel *headerIconLabel = new QLabel(this);
887 headerIconLabel->setPixmap(KIcon("krdc").pixmap(128));
889 QHBoxLayout *headerLayout = new QHBoxLayout;
890 headerLayout->setMargin(20);
891 headerLayout->addWidget(headerLabel, 1, Qt::AlignTop);
892 headerLayout->addWidget(headerIconLabel);
894 KPushButton *vncConnectButton = new KPushButton(this);
895 vncConnectButton->setStyleSheet("KPushButton { padding: 12px; margin: 10px; }");
896 vncConnectButton->setIcon(KIcon(actionCollection()->action("new_vnc_connection")->icon()));
897 vncConnectButton->setText(i18n("Connect to a VNC Remote Desktop"));
898 connect(vncConnectButton, SIGNAL(clicked()), SLOT(newVncConnection()));
899 #ifndef BUILD_VNC
900 vncConnectButton->setVisible(false);
901 #endif
903 KPushButton *nxConnectButton = new KPushButton(this);
904 nxConnectButton->setStyleSheet("KPushButton { padding: 12px; margin: 10px; }");
905 nxConnectButton->setIcon(KIcon(actionCollection()->action("new_nx_connection")->icon()));
906 nxConnectButton->setText(i18n("Connect to a NX Remote Desktop"));
907 connect(nxConnectButton, SIGNAL(clicked()), SLOT(newNxConnection()));
908 #ifndef BUILD_NX
909 nxConnectButton->setVisible(false);
910 #endif
912 rdpConnectButton = new KPushButton(this);
913 rdpConnectButton->setStyleSheet("KPushButton { padding: 12px; margin: 10px; }");
914 rdpConnectButton->setIcon(KIcon(actionCollection()->action("new_rdp_connection")->icon()));
915 rdpConnectButton->setText(i18n("Connect to a Windows Remote Desktop (RDP)"));
916 connect(rdpConnectButton, SIGNAL(clicked()), SLOT(newRdpConnection()));
917 QMetaObject::invokeMethod(this, "checkRdektopAvailability");
918 #ifndef BUILD_RDP
919 rdpConnectButton->setVisible(false);
920 #endif
922 KPushButton *zeroconfButton = new KPushButton(this);
923 zeroconfButton->setStyleSheet("KPushButton { padding: 12px; margin: 10px; }");
924 zeroconfButton->setIcon(KIcon(actionCollection()->action("zeroconf_page")->icon()));
925 zeroconfButton->setText(i18n("Browse Remote Desktop Services on Local Network"));
926 connect(zeroconfButton, SIGNAL(clicked()), SLOT(createZeroconfPage()));
927 #ifndef BUILD_ZEROCONF
928 zeroconfButton->setVisible(false);
929 #endif
931 startLayout->addLayout(headerLayout);
932 startLayout->addWidget(vncConnectButton);
933 startLayout->addWidget(nxConnectButton);
934 startLayout->addWidget(rdpConnectButton);
935 startLayout->addWidget(zeroconfButton);
936 startLayout->addStretch();
938 m_tabWidget->insertTab(0, startWidget, KIcon("krdc"), i18n("Start Page"));
941 void MainWindow::newVncConnection()
943 m_addressNavigator->setUrl(KUrl("vnc://"));
944 m_addressNavigator->setFocus();
946 QToolTip::showText(m_addressNavigator->pos() + pos() + QPoint(m_addressNavigator->width(),
947 m_addressNavigator->height() + 20),
948 i18n("<html>Enter the address here.<br />"
949 "<i>Example: vncserver:1 (host:port / screen)</i></html>"), this);
952 void MainWindow::newNxConnection()
954 m_addressNavigator->setUrl(KUrl("nx://"));
955 m_addressNavigator->setFocus();
957 QToolTip::showText(m_addressNavigator->pos() + pos() + QPoint(m_addressNavigator->width(),
958 m_addressNavigator->height() + 20),
959 i18n("<html>Enter the address here.<br />"
960 "<i>Example: nxserver (host)</i></html>"), this);
963 void MainWindow::newRdpConnection()
965 m_addressNavigator->setUrl(KUrl("rdp://"));
966 m_addressNavigator->setFocus();
968 QToolTip::showText(m_addressNavigator->pos() + pos() + QPoint(m_addressNavigator->width(),
969 m_addressNavigator->height() + 20),
970 i18n("<html>Enter the address here. Port is optional.<br />"
971 "<i>Example: rdpserver:3389 (host:port)</i></html>"), this);
974 void MainWindow::createZeroconfPage()
976 #ifdef BUILD_ZEROCONF
977 if (m_zeroconfPage)
978 return;
980 m_zeroconfPage = new ZeroconfPage(this);
981 connect(m_zeroconfPage, SIGNAL(newConnection(const KUrl, bool)), this, SLOT(newConnection(const KUrl, bool)));
982 connect(m_zeroconfPage, SIGNAL(closeZeroconfPage()), this, SLOT(closeZeroconfPage()));
983 int zeroconfTabIndex = m_tabWidget->insertTab(m_showStartPage ? 1 : 0, m_zeroconfPage, KIcon("krdc"), i18n("Browse Local Network"));
984 m_tabWidget->setCurrentIndex(zeroconfTabIndex);
985 #endif
988 void MainWindow::closeZeroconfPage()
990 #ifdef BUILD_ZEROCONF
991 int index = m_tabWidget->indexOf(m_zeroconfPage);
992 m_tabWidget->removeTab(index);
993 m_zeroconfPage->deleteLater();
994 m_zeroconfPage = 0;
995 tabChanged(index); // force update again because m_zeroconfPage was not null before
996 #endif
999 void MainWindow::checkRdektopAvailability()
1001 if (KProcess::execute("rdesktop") < 0) { //-2 if the process could not be started, -1 if it crashed, otherwise its exit code
1002 rdpConnectButton->setEnabled(false);
1003 rdpConnectButton->setText(rdpConnectButton->text() + '\n' +
1004 i18n("\"rdesktop\" cannot be found on your system; make sure it is properly installed."));
1008 QList<RemoteView *> MainWindow::remoteViewList() const
1010 return m_remoteViewList;
1013 int MainWindow::currentRemoteView() const
1015 return m_currentRemoteView;
1018 #include "mainwindow.moc"