* major layout fixes (size, stacked widget, ...)
[kdenetwork.git] / krdc / mainwindow.cpp
blob4dd87fbfd8c7a60b8c0616975768db8dfabe60e5
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->setCloseButtonEnabled(true);
96 connect(m_tabWidget, SIGNAL(closeRequest(QWidget *)), SLOT(closeTab(QWidget *)));
98 m_tabWidget->setMinimumSize(600, 400);
99 setCentralWidget(m_tabWidget);
101 QDockWidget *remoteDesktopsDockWidget = new QDockWidget(this);
102 remoteDesktopsDockWidget->setObjectName("remoteDesktopsDockWidget"); // required for saving position / state
103 remoteDesktopsDockWidget->setWindowTitle(i18n("Remote desktops"));
104 actionCollection()->addAction("remote_desktop_dockwidget",
105 remoteDesktopsDockWidget->toggleViewAction());
106 QTreeView *remoteDesktopsTreeView = new QTreeView(remoteDesktopsDockWidget);
107 RemoteDesktopsModel *remoteDesktopsModel = new RemoteDesktopsModel(this);
108 connect(remoteDesktopsModel, SIGNAL(modelReset()), remoteDesktopsTreeView, SLOT(expandAll()));
109 remoteDesktopsTreeView->setModel(remoteDesktopsModel);
110 remoteDesktopsTreeView->header()->hide();
111 remoteDesktopsTreeView->expandAll();
112 connect(remoteDesktopsTreeView, SIGNAL(doubleClicked(const QModelIndex &)),
113 SLOT(openFromDockWidget(const QModelIndex &)));
115 remoteDesktopsDockWidget->setWidget(remoteDesktopsTreeView);
116 addDockWidget(Qt::LeftDockWidgetArea, remoteDesktopsDockWidget);
118 createGUI("krdcui.rc");
120 if (Settings::systemTrayIcon()) {
121 m_systemTrayIcon = new SystemTrayIcon(this);
122 m_systemTrayIcon->setVisible(true);
125 connect(m_tabWidget, SIGNAL(currentChanged(int)), SLOT(tabChanged(int)));
127 statusBar()->showMessage(i18n("KDE Remote Desktop Client started"));
129 updateActionStatus(); // disable remote view actions
131 if (Settings::showStartPage())
132 createStartPage();
134 setAutoSaveSettings(); // e.g toolbar position, mainwindow size, ...
136 if (Settings::rememberSessions()) // give some time to create and show the window first
137 QTimer::singleShot(100, this, SLOT(restoreOpenSessions()));
140 MainWindow::~MainWindow()
144 void MainWindow::setupActions()
146 QAction *vncConnectionAction = actionCollection()->addAction("new_vnc_connection");
147 vncConnectionAction->setText(i18n("New VNC Connection..."));
148 vncConnectionAction->setIcon(KIcon("network-connect"));
149 connect(vncConnectionAction, SIGNAL(triggered()), SLOT(newVncConnection()));
150 #ifndef BUILD_VNC
151 vncConnectionAction->deleteLater();
152 #endif
154 QAction *nxConnectionAction = actionCollection()->addAction("new_nx_connection");
155 nxConnectionAction->setText(i18n("New NX Connection..."));
156 nxConnectionAction->setIcon(KIcon("network-connect"));
157 connect(nxConnectionAction, SIGNAL(triggered()), SLOT(newNxConnection()));
158 #ifndef BUILD_NX
159 nxConnectionAction->deleteLater();
160 #endif
162 QAction *rdpConnectionAction = actionCollection()->addAction("new_rdp_connection");
163 rdpConnectionAction->setText(i18n("New RDP Connection..."));
164 rdpConnectionAction->setIcon(KIcon("network-connect"));
165 connect(rdpConnectionAction, SIGNAL(triggered()), SLOT(newRdpConnection()));
166 #ifndef BUILD_RDP
167 rdpConnectionAction->deleteLater();
168 #endif
170 QAction *zeroconfAction = actionCollection()->addAction("zeroconf_page");
171 zeroconfAction->setText(i18n("Browse Remote Desktop Services on Local Network..."));
172 zeroconfAction->setIcon(KIcon("network-connect"));
173 connect(zeroconfAction, SIGNAL(triggered()), SLOT(createZeroconfPage()));
174 #ifndef BUILD_ZEROCONF
175 zeroconfAction->setVisible(false);
176 #endif
178 QAction *screenshotAction = actionCollection()->addAction("take_screenshot");
179 screenshotAction->setText(i18n("Copy Screenshot to Clipboard"));
180 screenshotAction->setIcon(KIcon("ksnapshot"));
181 connect(screenshotAction, SIGNAL(triggered()), SLOT(takeScreenshot()));
183 QAction *fullscreenAction = actionCollection()->addAction("switch_fullscreen");
184 fullscreenAction->setText(i18n("Switch to Fullscreen Mode"));
185 fullscreenAction->setIcon(KIcon("view-fullscreen"));
186 connect(fullscreenAction, SIGNAL(triggered()), SLOT(switchFullscreen()));
188 QAction *viewOnlyAction = actionCollection()->addAction("view_only");
189 viewOnlyAction->setCheckable(true);
190 viewOnlyAction->setText(i18n("View Only"));
191 viewOnlyAction->setIcon(KIcon("document-preview"));
192 connect(viewOnlyAction, SIGNAL(triggered(bool)), SLOT(viewOnly(bool)));
194 QAction *logoutAction = actionCollection()->addAction("logout");
195 logoutAction->setText(i18n("Log Out"));
196 logoutAction->setIcon(KIcon("system-log-out"));
197 connect(logoutAction, SIGNAL(triggered()), SLOT(logout()));
199 QAction *showLocalCursorAction = actionCollection()->addAction("show_local_cursor");
200 showLocalCursorAction->setCheckable(true);
201 showLocalCursorAction->setIcon(KIcon("input-mouse"));
202 showLocalCursorAction->setText(i18n("Show Local Cursor"));
203 connect(showLocalCursorAction, SIGNAL(triggered(bool)), SLOT(showLocalCursor(bool)));
205 QAction *grabAllKeysAction = actionCollection()->addAction("grab_all_keys");
206 grabAllKeysAction->setCheckable(true);
207 grabAllKeysAction->setIcon(KIcon("configure-shortcuts"));
208 grabAllKeysAction->setText(i18n("Grab all possible keys"));
209 connect(grabAllKeysAction, SIGNAL(triggered(bool)), SLOT(grabAllKeys(bool)));
211 QAction *scaleAction = actionCollection()->addAction("scale");
212 scaleAction->setCheckable(true);
213 scaleAction->setIcon(KIcon("zoom-fit-best"));
214 scaleAction->setText(i18n("Scale remote screen to fit window size"));
215 connect(scaleAction, SIGNAL(triggered(bool)), SLOT(scale(bool)));
217 QAction *quitAction = KStandardAction::quit(this, SLOT(quit()), actionCollection());
218 actionCollection()->addAction("quit", quitAction);
219 QAction *preferencesAction = KStandardAction::preferences(this, SLOT(preferences()), actionCollection());
220 actionCollection()->addAction("preferences", preferencesAction);
221 QAction *configToolbarAction = KStandardAction::configureToolbars(this, SLOT(configureToolbars()), actionCollection());
222 actionCollection()->addAction("configure_toolbars", configToolbarAction);
223 QAction *keyBindingsAction = KStandardAction::keyBindings(this, SLOT(configureKeys()), actionCollection());
224 actionCollection()->addAction("configure_keys", keyBindingsAction);
225 QAction *cinfigNotifyAction = KStandardAction::configureNotifications(this, SLOT(configureNotifications()), actionCollection());
226 cinfigNotifyAction->setVisible(false);
227 actionCollection()->addAction("configure_notifications", cinfigNotifyAction);
228 m_menubarAction = KStandardAction::showMenubar(this, SLOT(showMenubar()), actionCollection());
229 m_menubarAction->setChecked(!menuBar()->isHidden());
230 actionCollection()->addAction("settings_showmenubar", m_menubarAction);
232 QString initialProtocol;
233 #ifdef BUILD_RDP
234 initialProtocol = "rdp";
235 #endif
236 #ifdef BUILD_NX
237 initialProtocol = "nx";
238 #endif
239 #ifdef BUILD_VNC
240 initialProtocol = "vnc";
241 #endif
243 m_addressNavigator = new KUrlNavigator(0, KUrl(initialProtocol + "://"), this);
244 m_addressNavigator->setCustomProtocols(QStringList()
245 #ifdef BUILD_VNC
246 << "vnc"
247 #endif
248 #ifdef BUILD_NX
249 << "nx"
250 #endif
251 #ifdef BUILD_RDP
252 << "rdp"
253 #endif
255 m_addressNavigator->setUrlEditable(Settings::normalUrlInputLine());
256 connect(m_addressNavigator, SIGNAL(returnPressed()), SLOT(newConnection()));
258 QLabel *addressLabel = new QLabel(i18n("Remote desktop:"), this);
260 QWidget *addressWidget = new QWidget(this);
261 QHBoxLayout *addressLayout = new QHBoxLayout(addressWidget);
262 addressLayout->setMargin(0);
263 addressLayout->addWidget(addressLabel);
264 addressLayout->addWidget(m_addressNavigator, 1);
266 KAction *addressLineAction = new KAction(i18nc("Title for remote address input action", "Address"), this);
267 actionCollection()->addAction("address_line", addressLineAction);
268 addressLineAction->setDefaultWidget(addressWidget);
270 QAction *gotoAction = actionCollection()->addAction("goto_address");
271 gotoAction->setText(i18n("Goto Address"));
272 gotoAction->setIcon(KIcon("go-jump-locationbar"));
273 connect(gotoAction, SIGNAL(triggered()), SLOT(newConnection()));
275 KActionMenu *bookmarkMenu = new KActionMenu(i18n("Bookmarks"), actionCollection());
276 m_bookmarkManager = new BookmarkManager(actionCollection(), bookmarkMenu->menu(), this);
277 actionCollection()->addAction("bookmark" , bookmarkMenu);
278 connect(m_bookmarkManager, SIGNAL(openUrl(KUrl)), SLOT(newConnection(KUrl)));
281 void MainWindow::restoreOpenSessions()
283 QStringList list = Settings::openSessions();
284 QStringList::Iterator it = list.begin();
285 QStringList::Iterator end = list.end();
286 while (it != end) {
287 newConnection(*it);
288 ++it;
292 void MainWindow::newConnection(const KUrl &newUrl, bool switchFullscreenWhenConnected)
294 m_switchFullscreenWhenConnected = switchFullscreenWhenConnected;
296 KUrl url = newUrl.isEmpty() ? m_addressNavigator->uncommittedUrl() : newUrl;
298 if (!url.isValid() || (url.host().isEmpty() && url.port() < 0)
299 || !url.path().isEmpty()) {
300 KMessageBox::error(this,
301 i18n("The entered address does not have the required form."),
302 i18n("Malformed URL"));
303 return;
306 m_addressNavigator->setUrl(KUrl(url.scheme().toLower() + "://"));
308 RemoteView *view = 0;
310 if (url.scheme().toLower() == "vnc") {
311 #ifdef BUILD_VNC
312 view = new VncView(this, url);
313 #endif
314 } else if (url.scheme().toLower() == "nx") {
315 #ifdef BUILD_NX
316 view = new NxView(this, url);
317 #endif
318 } else if (url.scheme().toLower() == "rdp") {
319 #ifdef BUILD_RDP
320 view = new RdpView(this, url);
321 #endif
322 } else
324 KMessageBox::error(this,
325 i18n("The entered address cannot be handled."),
326 i18n("Unusable URL"));
327 return;
330 if (!view) {
331 KMessageBox::error(this, i18n("Support for %1:// has not been enabled during build.",
332 url.scheme().toLower()),
333 i18n("Unusable URL"));
334 return;
337 connect(view, SIGNAL(changeSize(int, int)), this, SLOT(resizeTabWidget(int, int)));
338 connect(view, SIGNAL(statusChanged(RemoteView::RemoteStatus)), this, SLOT(statusChanged(RemoteView::RemoteStatus)));
340 m_remoteViewList.append(view);
342 view->resize(0, 0);
344 int numNonRemoteView = 0;
345 if (m_showStartPage)
346 numNonRemoteView++;
347 if (m_zeroconfPage)
348 numNonRemoteView++;
350 QScrollArea *scrollArea = createScrollArea(m_tabWidget, m_remoteViewList.at(m_remoteViewList.count() - 1));
352 int newIndex = m_tabWidget->addTab(scrollArea, KIcon("krdc"), url.prettyUrl(KUrl::RemoveTrailingSlash));
353 m_tabWidget->setCurrentIndex(newIndex);
354 tabChanged(newIndex); // force to update m_currentRemoteView (tabChanged is not emitted when start page has been disabled)
356 view->start();
359 void MainWindow::openFromDockWidget(const QModelIndex &index)
361 if (index.data(Qt::UserRole).toBool()) {
362 KUrl url(index.data().toString());
363 // first check if url has already been opened; in case show the tab
364 for (int i = 0; i < m_remoteViewList.count(); i++) {
365 if (m_remoteViewList.at(i)->url() == url) {
366 int numNonRemoteView = 0;
367 if (m_showStartPage)
368 numNonRemoteView++;
369 if (m_zeroconfPage)
370 numNonRemoteView++;
371 m_tabWidget->setCurrentIndex(i + numNonRemoteView);
372 return;
375 newConnection(url);
379 void MainWindow::resizeTabWidget(int w, int h)
381 kDebug(5010) << "tabwidget resize: w: " << w << ", h: " << h;
383 if (m_topBottomBorder == 0) { // the values are not cached yet
384 QScrollArea *tmp = qobject_cast<QScrollArea *>(m_tabWidget->currentWidget());
386 m_leftRightBorder = m_tabWidget->width() - m_tabWidget->currentWidget()->width() + (2 * tmp->frameWidth());
387 m_topBottomBorder = m_tabWidget->height() - m_tabWidget->currentWidget()->height() + (2 * tmp->frameWidth());
389 kDebug(5010) << "tabwidget border: w: " << m_leftRightBorder << ", h: " << m_topBottomBorder;
392 int newTabWidth = w + m_leftRightBorder;
393 int newTabHeight = h + m_topBottomBorder;
395 QSize newWindowSize = size() - m_tabWidget->size() + QSize(newTabWidth, newTabHeight);
397 QSize desktopSize = QSize(QApplication::desktop()->availableGeometry().width(),
398 QApplication::desktop()->availableGeometry().height());
400 if ((newWindowSize.height() >= desktopSize.height()) || (newWindowSize.width() >= desktopSize.width())) {
401 kDebug(5010) << "remote desktop needs more place than available -> show window maximized";
402 setWindowState(windowState() | Qt::WindowMaximized);
403 return;
406 //WORKAROUND: QTabWidget resize problem. Let's see if there is a clean solution for this issue.
407 m_tabWidget->setMinimumSize(newTabWidth, newTabHeight);
408 m_tabWidget->adjustSize();
409 QCoreApplication::processEvents();
410 m_tabWidget->setMinimumSize(500, 400);
413 void MainWindow::statusChanged(RemoteView::RemoteStatus status)
415 kDebug(5010) << status;
417 // the remoteview is already deleted, so don't show it; otherwise it would crash
418 if (status == RemoteView::Disconnecting || status == RemoteView::Disconnected)
419 return;
421 QString host = m_remoteViewList.at(m_currentRemoteView)->host();
423 QString iconName = "krdc";
424 QString message;
426 switch (status) {
427 case RemoteView::Connecting:
428 iconName = "network-connect";
429 message = i18n("Connecting to %1", host);
430 break;
431 case RemoteView::Authenticating:
432 iconName = "dialog-password";
433 message = i18n("Authenticating at %1", host);
434 break;
435 case RemoteView::Preparing:
436 iconName = "view-history";
437 message = i18n("Preparing connection to %1", host);
438 break;
439 case RemoteView::Connected:
440 iconName = "krdc";
441 message = i18n("Connected to %1", host);
443 // when started with command line fullscreen argument
444 if (m_switchFullscreenWhenConnected) {
445 m_switchFullscreenWhenConnected = false;
446 switchFullscreen();
449 m_bookmarkManager->addHistoryBookmark();
451 break;
452 default:
453 iconName = "krdc";
454 message = QString();
457 m_tabWidget->setTabIcon(m_tabWidget->currentIndex(), KIcon(iconName));
458 statusBar()->showMessage(message);
461 void MainWindow::takeScreenshot()
463 QPixmap snapshot = QPixmap::grabWidget(m_remoteViewList.at(m_currentRemoteView));
465 QApplication::clipboard()->setPixmap(snapshot);
468 void MainWindow::switchFullscreen()
470 kDebug(5010);
472 if (m_fullscreenWindow) {
473 show();
474 restoreGeometry(m_mainWindowGeometry);
476 m_fullscreenWindow->setWindowState(0);
477 m_fullscreenWindow->hide();
479 QScrollArea *scrollArea = createScrollArea(m_tabWidget, m_remoteViewList.at(m_currentRemoteView));
481 int currentTab = m_tabWidget->currentIndex();
482 m_tabWidget->insertTab(currentTab, scrollArea, m_tabWidget->tabIcon(currentTab), m_tabWidget->tabText(currentTab));
483 m_tabWidget->removeTab(m_tabWidget->currentIndex());
484 m_tabWidget->setCurrentIndex(currentTab);
486 resizeTabWidget(m_remoteViewList.at(m_currentRemoteView)->sizeHint().width(),
487 m_remoteViewList.at(m_currentRemoteView)->sizeHint().height());
489 if (m_toolBar) {
490 m_toolBar->hideAndDestroy();
491 m_toolBar->deleteLater();
492 m_toolBar = 0;
495 actionCollection()->action("switch_fullscreen")->setIcon(KIcon("view-fullscreen"));
496 actionCollection()->action("switch_fullscreen")->setText(i18n("Switch to Fullscreen Mode"));
498 m_fullscreenWindow->deleteLater();
500 m_fullscreenWindow = 0;
501 } else {
502 m_fullscreenWindow = new QWidget(this, Qt::Window);
503 m_fullscreenWindow->setWindowTitle(i18nc("window title when in fullscreen mode (for example displayed in tasklist)",
504 "KDE Remote Desktop Client (Fullscreen)"));
506 QScrollArea *scrollArea = createScrollArea(m_fullscreenWindow, m_remoteViewList.at(m_currentRemoteView));
507 scrollArea->setFrameShape(QFrame::NoFrame);
509 QVBoxLayout *fullscreenLayout = new QVBoxLayout(m_fullscreenWindow);
510 fullscreenLayout->setMargin(0);
511 fullscreenLayout->addWidget(scrollArea);
513 MinimizePixel *minimizePixel = new MinimizePixel(m_fullscreenWindow);
514 minimizePixel->winId(); // force it to be a native widget (prevents problem with QX11EmbedContainer)
515 connect(minimizePixel, SIGNAL(rightClicked()), m_fullscreenWindow, SLOT(showMinimized()));
517 m_fullscreenWindow->show();
519 KToggleFullScreenAction::setFullScreen(m_fullscreenWindow, true);
521 // show the toolbar after we have switched to fullscreen mode
522 QTimer::singleShot(100, this, SLOT(showRemoteViewToolbar()));
524 m_mainWindowGeometry = saveGeometry();
525 hide();
529 QScrollArea *MainWindow::createScrollArea(QWidget *parent, RemoteView *remoteView)
531 RemoteViewScrollArea *scrollArea = new RemoteViewScrollArea(parent);
532 scrollArea->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
534 connect(scrollArea, SIGNAL(resized(int, int)), remoteView, SLOT(scaleResize(int, int)));
536 QPalette palette = scrollArea->palette();
537 palette.setColor(QPalette::Dark, Settings::backgroundColor());
538 scrollArea->setPalette(palette);
540 scrollArea->setBackgroundRole(QPalette::Dark);
541 scrollArea->setWidget(remoteView);
543 return scrollArea;
546 void MainWindow::logout()
548 kDebug(5010);
550 if (m_fullscreenWindow) { // first close fullscreen view
551 switchFullscreen();
554 QWidget *tmp = m_tabWidget->currentWidget();
556 m_remoteViewList.removeAt(m_currentRemoteView);
558 m_tabWidget->removeTab(m_tabWidget->currentIndex());
560 tmp->deleteLater();
563 void MainWindow::closeTab(QWidget *widget)
565 kDebug(5010);
567 int index = m_tabWidget->indexOf(widget);
569 if (m_showStartPage && index == 0) {
570 KMessageBox::information(this, i18n("The start page cannot be closed. "
571 "If you want to disable it, you can do so in the settings."));
572 return;
575 #ifdef BUILD_ZEROCONF
576 if (widget == m_zeroconfPage) {
577 closeZeroconfPage();
578 return;
580 #endif
582 int numNonRemoteView = 0;
583 if (m_showStartPage)
584 numNonRemoteView++;
585 if (m_zeroconfPage)
586 numNonRemoteView++;
588 if (index - numNonRemoteView >= 0)
589 m_remoteViewList.removeAt(index - numNonRemoteView);
591 m_tabWidget->removeTab(index);
593 widget->deleteLater();
594 widget = 0;
596 tabChanged(index);
599 void MainWindow::showLocalCursor(bool showLocalCursor)
601 kDebug(5010) << showLocalCursor;
603 m_remoteViewList.at(m_currentRemoteView)->showDotCursor(showLocalCursor ? RemoteView::CursorOn : RemoteView::CursorOff);
606 void MainWindow::viewOnly(bool viewOnly)
608 kDebug(5010) << viewOnly;
610 m_remoteViewList.at(m_currentRemoteView)->setViewOnly(viewOnly);
613 void MainWindow::grabAllKeys(bool grabAllKeys)
615 kDebug(5010);
617 m_remoteViewList.at(m_currentRemoteView)->setGrabAllKeys(grabAllKeys);
620 void MainWindow::scale(bool scale)
622 kDebug(5010);
624 m_remoteViewList.at(m_currentRemoteView)->enableScaling(scale);
627 void MainWindow::showRemoteViewToolbar()
629 kDebug(5010);
631 if (!m_toolBar) {
632 actionCollection()->action("switch_fullscreen")->setIcon(KIcon("view-restore"));
633 actionCollection()->action("switch_fullscreen")->setText(i18n("Switch to Window Mode"));
635 m_toolBar = new FloatingToolBar(m_fullscreenWindow, m_fullscreenWindow);
636 m_toolBar->winId(); // force it to be a native widget (prevents problem with QX11EmbedContainer)
637 m_toolBar->setSide(FloatingToolBar::Top);
639 QLabel *hostLabel = new QLabel(m_remoteViewList.at(m_currentRemoteView)->url().prettyUrl(KUrl::RemoveTrailingSlash), m_toolBar);
640 hostLabel->setMargin(4);
641 QFont font(hostLabel->font());
642 font.setBold(true);
643 hostLabel->setFont(font);
644 m_toolBar->addWidget(hostLabel);
646 #if 0 //TODO: implement functionality
647 KComboBox *sessionComboBox = new KComboBox(m_toolBar);
648 sessionComboBox->setEditable(false);
649 sessionComboBox->addItem(i18n("Switch to..."));
650 for (int i = 0; i < m_remoteViewList.count(); i++) {
651 sessionComboBox->addItem(m_remoteViewList.at(i)->url().prettyUrl(KUrl::RemoveTrailingSlash));
653 sessionComboBox->setVisible(m_remoteViewList.count() > 1); // just show it if there are sessions to switch
654 m_toolBar->addWidget(sessionComboBox);
655 #endif
657 m_toolBar->addAction(actionCollection()->action("switch_fullscreen"));
659 QAction *minimizeAction = new QAction(m_toolBar);
660 minimizeAction->setIcon(KIcon("window-suppressed"));
661 minimizeAction->setText(i18n("Minimize Fullscreen Window"));
662 connect(minimizeAction, SIGNAL(triggered()), m_fullscreenWindow, SLOT(showMinimized()));
663 m_toolBar->addAction(minimizeAction);
665 m_toolBar->addAction(actionCollection()->action("take_screenshot"));
666 m_toolBar->addAction(actionCollection()->action("view_only"));
667 m_toolBar->addAction(actionCollection()->action("show_local_cursor"));
668 m_toolBar->addAction(actionCollection()->action("grab_all_keys"));
669 m_toolBar->addAction(actionCollection()->action("scale"));
670 m_toolBar->addAction(actionCollection()->action("logout"));
672 QAction *stickToolBarAction = new QAction(m_toolBar);
673 stickToolBarAction->setCheckable(true);
674 stickToolBarAction->setIcon(KIcon("object-locked"));
675 stickToolBarAction->setText(i18n("Stick Toolbar"));
676 connect(stickToolBarAction, SIGNAL(triggered(bool)), m_toolBar, SLOT(setSticky(bool)));
677 m_toolBar->addAction(stickToolBarAction);
680 m_toolBar->showAndAnimate();
683 void MainWindow::updateActionStatus()
685 kDebug(5010) << m_tabWidget->currentIndex();
687 bool enabled;
689 if ((m_showStartPage && (m_tabWidget->currentIndex() == 0)) ||
690 #ifdef BUILD_ZEROCONF
691 (m_zeroconfPage && (m_tabWidget->currentIndex() == m_tabWidget->indexOf(m_zeroconfPage))) ||
692 #endif
693 (!m_showStartPage && (m_tabWidget->currentIndex() < 0)))
694 enabled = false;
695 else
696 enabled = true;
698 actionCollection()->action("switch_fullscreen")->setEnabled(enabled);
699 actionCollection()->action("take_screenshot")->setEnabled(enabled);
700 actionCollection()->action("view_only")->setEnabled(enabled);
701 actionCollection()->action("grab_all_keys")->setEnabled(enabled);
702 actionCollection()->action("scale")->setEnabled(enabled);
703 actionCollection()->action("logout")->setEnabled(enabled);
705 bool viewOnlyChecked = false;
706 if (m_currentRemoteView >= 0)
707 viewOnlyChecked = enabled && m_remoteViewList.at(m_currentRemoteView)->viewOnly();
708 actionCollection()->action("view_only")->setChecked(viewOnlyChecked);
710 bool showLocalCursorChecked = false;
711 if (m_currentRemoteView >= 0)
712 showLocalCursorChecked = enabled && m_remoteViewList.at(m_currentRemoteView)->dotCursorState() == RemoteView::CursorOn;
713 actionCollection()->action("show_local_cursor")->setChecked(showLocalCursorChecked);
715 bool showLocalCursorVisible = false;
716 if (m_currentRemoteView >= 0)
717 showLocalCursorVisible = enabled && m_remoteViewList.at(m_currentRemoteView)->supportsLocalCursor();
718 actionCollection()->action("show_local_cursor")->setVisible(showLocalCursorVisible);
720 bool scaleVisible = false;
721 if (m_currentRemoteView >= 0)
722 scaleVisible = enabled && m_remoteViewList.at(m_currentRemoteView)->supportsScaling();
723 actionCollection()->action("scale")->setVisible(scaleVisible);
726 void MainWindow::preferences()
728 // An instance of your dialog could be already created and could be
729 // cached, in which case you want to display the cached dialog
730 // instead of creating another one
731 if (PreferencesDialog::showDialog("preferences"))
732 return;
734 // KConfigDialog didn't find an instance of this dialog, so lets
735 // create it:
736 PreferencesDialog *dialog = new PreferencesDialog(this, Settings::self());
738 // User edited the configuration - update your local copies of the
739 // configuration data
740 connect(dialog, SIGNAL(settingsChanged(const QString&)),
741 this, SLOT(updateConfiguration()));
743 dialog->show();
746 void MainWindow::updateConfiguration()
748 m_addressNavigator->setUrlEditable(Settings::normalUrlInputLine());
750 if (Settings::systemTrayIcon() && !m_systemTrayIcon) {
751 m_systemTrayIcon = new SystemTrayIcon(this);
752 m_systemTrayIcon->setVisible(true);
753 } else if (m_systemTrayIcon) {
754 delete m_systemTrayIcon;
755 m_systemTrayIcon = 0;
758 if (Settings::showStartPage() && !m_showStartPage)
759 createStartPage();
760 else if (!Settings::showStartPage() && m_showStartPage) {
761 m_tabWidget->removeTab(0);
762 m_showStartPage = false;
764 updateActionStatus();
766 // update the scroll areas background color
767 int numNonRemoteView = 0;
768 if (m_showStartPage)
769 numNonRemoteView++;
770 if (m_zeroconfPage)
771 numNonRemoteView++;
772 for (int i = numNonRemoteView; i < m_tabWidget->count(); i++) {
773 QPalette palette = m_tabWidget->widget(i)->palette();
774 palette.setColor(QPalette::Dark, Settings::backgroundColor());
775 m_tabWidget->widget(i)->setPalette(palette);
779 void MainWindow::quit()
781 bool haveRemoteConnections = m_remoteViewList.count();
782 if (!haveRemoteConnections || KMessageBox::warningContinueCancel(this,
783 i18n("Are you sure you want to quit the KDE Remote Desktop Client?"),
784 i18n("Confirm Quit"),
785 KStandardGuiItem::quit(), KStandardGuiItem::cancel(),
786 "DoNotAskBeforeExit") == KMessageBox::Continue) {
788 if (Settings::rememberSessions()) { // remember open remote views for next startup
789 QStringList list;
790 for (int i = 0; i < m_remoteViewList.count(); i++) {
791 kDebug(5010) << m_remoteViewList.at(i)->url();
792 list.append(m_remoteViewList.at(i)->url().prettyUrl(KUrl::RemoveTrailingSlash));
794 Settings::setOpenSessions(list);
797 Settings::self()->writeConfig();
799 qApp->quit();
803 void MainWindow::configureNotifications()
805 KNotifyConfigWidget::configure(this);
808 void MainWindow::configureKeys()
810 KShortcutsDialog::configure(actionCollection());
813 void MainWindow::configureToolbars()
815 KEditToolBar edit(actionCollection());
816 connect(&edit, SIGNAL(newToolbarConfig()), this, SLOT(newToolbarConfig()));
817 edit.exec();
820 void MainWindow::showMenubar()
822 if (m_menubarAction->isChecked())
823 menuBar()->show();
824 else
825 menuBar()->hide();
828 void MainWindow::closeEvent(QCloseEvent *event)
830 event->ignore();
832 if (Settings::systemTrayIcon()) {
833 hide(); // just hide the mainwindow, keep it in systemtray
834 } else {
835 quit();
839 void MainWindow::tabChanged(int index)
841 kDebug(5010) << index;
843 int numNonRemoteView = 0;
844 if (m_showStartPage)
845 numNonRemoteView++;
846 if (m_zeroconfPage)
847 numNonRemoteView++;
849 m_currentRemoteView = index - numNonRemoteView;
851 QString tabTitle = m_tabWidget->tabText(index).remove('&');
853 setCaption(tabTitle == i18n("Start Page") ? QString() : tabTitle);
855 updateActionStatus();
858 void MainWindow::createStartPage()
860 m_showStartPage = true;
862 QWidget *startWidget = new QWidget(this);
863 startWidget->setStyleSheet("QWidget { background-color: palette(base) }");
865 QVBoxLayout *startLayout = new QVBoxLayout(startWidget);
867 QLabel *headerLabel = new QLabel(this);
868 headerLabel->setText(i18n("<h1>KDE Remote Desktop Client</h1><br /><br />What would you like to do?<br />"));
870 QLabel *headerIconLabel = new QLabel(this);
871 headerIconLabel->setPixmap(KIcon("krdc").pixmap(128));
873 QHBoxLayout *headerLayout = new QHBoxLayout;
874 headerLayout->setMargin(20);
875 headerLayout->addWidget(headerLabel, 1, Qt::AlignTop);
876 headerLayout->addWidget(headerIconLabel);
878 KPushButton *vncConnectButton = new KPushButton(this);
879 vncConnectButton->setStyleSheet("KPushButton { padding: 12px; margin: 10px; }");
880 vncConnectButton->setIcon(KIcon(actionCollection()->action("new_vnc_connection")->icon()));
881 vncConnectButton->setText(i18n("Connect to a VNC Remote Desktop"));
882 connect(vncConnectButton, SIGNAL(clicked()), SLOT(newVncConnection()));
883 #ifndef BUILD_VNC
884 vncConnectButton->setVisible(false);
885 #endif
887 KPushButton *nxConnectButton = new KPushButton(this);
888 nxConnectButton->setStyleSheet("KPushButton { padding: 12px; margin: 10px; }");
889 nxConnectButton->setIcon(KIcon(actionCollection()->action("new_nx_connection")->icon()));
890 nxConnectButton->setText(i18n("Connect to a NX Remote Desktop"));
891 connect(nxConnectButton, SIGNAL(clicked()), SLOT(newNxConnection()));
892 #ifndef BUILD_NX
893 nxConnectButton->setVisible(false);
894 #endif
896 KPushButton *rdpConnectButton = new KPushButton(this);
897 rdpConnectButton->setStyleSheet("KPushButton { padding: 12px; margin: 10px; }");
898 rdpConnectButton->setIcon(KIcon(actionCollection()->action("new_rdp_connection")->icon()));
899 rdpConnectButton->setText(i18n("Connect to a Windows Remote Desktop (RDP)"));
900 connect(rdpConnectButton, SIGNAL(clicked()), SLOT(newRdpConnection()));
901 #ifndef BUILD_RDP
902 rdpConnectButton->setVisible(false);
903 #endif
905 KPushButton *zeroconfButton = new KPushButton(this);
906 zeroconfButton->setStyleSheet("KPushButton { padding: 12px; margin: 10px; }");
907 zeroconfButton->setIcon(KIcon(actionCollection()->action("zeroconf_page")->icon()));
908 zeroconfButton->setText(i18n("Browse Remote Desktop Services on Local Network"));
909 connect(zeroconfButton, SIGNAL(clicked()), SLOT(createZeroconfPage()));
910 #ifndef BUILD_ZEROCONF
911 zeroconfButton->setVisible(false);
912 #endif
914 startLayout->addLayout(headerLayout);
915 startLayout->addWidget(vncConnectButton);
916 startLayout->addWidget(nxConnectButton);
917 startLayout->addWidget(rdpConnectButton);
918 startLayout->addWidget(zeroconfButton);
919 startLayout->addStretch();
921 m_tabWidget->insertTab(0, startWidget, KIcon("krdc"), i18n("Start Page"));
924 void MainWindow::newVncConnection()
926 m_addressNavigator->setUrl(KUrl("vnc://"));
927 m_addressNavigator->setFocus();
929 QToolTip::showText(m_addressNavigator->pos() + pos() + QPoint(m_addressNavigator->width(),
930 m_addressNavigator->height() + 20),
931 i18n("<html>Enter the address here.<br />"
932 "<i>Example: vncserver:1 (host:port / screen)</i></html>"), this);
935 void MainWindow::newNxConnection()
937 m_addressNavigator->setUrl(KUrl("nx://"));
938 m_addressNavigator->setFocus();
940 QToolTip::showText(m_addressNavigator->pos() + pos() + QPoint(m_addressNavigator->width(),
941 m_addressNavigator->height() + 20),
942 i18n("<html>Enter the address here.<br />"
943 "<i>Example: nxserver (host)</i></html>"), this);
946 void MainWindow::newRdpConnection()
948 m_addressNavigator->setUrl(KUrl("rdp://"));
949 m_addressNavigator->setFocus();
951 QToolTip::showText(m_addressNavigator->pos() + pos() + QPoint(m_addressNavigator->width(),
952 m_addressNavigator->height() + 20),
953 i18n("<html>Enter the address here. Port is optional.<br />"
954 "<i>Example: rdpserver:3389 (host:port)</i></html>"), this);
957 void MainWindow::createZeroconfPage()
959 #ifdef BUILD_ZEROCONF
960 if (m_zeroconfPage)
961 return;
963 m_zeroconfPage = new ZeroconfPage(this);
964 connect(m_zeroconfPage, SIGNAL(newConnection(const KUrl, bool)), this, SLOT(newConnection(const KUrl, bool)));
965 connect(m_zeroconfPage, SIGNAL(closeZeroconfPage()), this, SLOT(closeZeroconfPage()));
966 int zeroconfTabIndex = m_tabWidget->insertTab(m_showStartPage ? 1 : 0, m_zeroconfPage, KIcon("krdc"), i18n("Browse Local Network"));
967 m_tabWidget->setCurrentIndex(zeroconfTabIndex);
968 #endif
971 void MainWindow::closeZeroconfPage()
973 #ifdef BUILD_ZEROCONF
974 int index = m_tabWidget->indexOf(m_zeroconfPage);
975 m_tabWidget->removeTab(index);
976 m_zeroconfPage->deleteLater();
977 m_zeroconfPage = 0;
978 tabChanged(index); // force update again because m_zeroconfPage was not null before
979 #endif
982 QList<RemoteView *> MainWindow::remoteViewList() const
984 return m_remoteViewList;
987 int MainWindow::currentRemoteView() const
989 return m_currentRemoteView;
992 #include "mainwindow.moc"