1 /****************************************************************************
3 ** Copyright (C) 2007 - 2008 Urs Wolfer <uwolfer @ kde.org>
5 ** This file is part of KDE.
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"
28 #include "config/preferencesdialog.h"
29 #include "floatingtoolbar.h"
30 #include "bookmarkmanager.h"
31 #include "remotedesktopsmodel.h"
32 #include "systemtrayicon.h"
43 #include "zeroconfpage.h"
50 #include <KActionCollection>
51 #include <KActionMenu>
52 #include <KApplication>
54 #include <KEditToolBar>
58 #include <KMessageBox>
59 #include <KNotifyConfigWidget>
61 #include <KPushButton>
63 #include <KShortcutsDialog>
66 #include <KToggleAction>
67 #include <KToggleFullScreenAction>
68 #include <KUrlNavigator>
71 #include <QCloseEvent>
72 #include <QDesktopWidget>
73 #include <QDockWidget>
74 #include <QFontMetrics>
75 #include <QHeaderView>
78 #include <QScrollArea>
80 #include <QToolButton>
84 MainWindow::MainWindow(QWidget
*parent
)
85 : KXmlGuiWindow(parent
),
86 m_fullscreenWindow(0),
90 m_currentRemoteView(-1),
91 m_showStartPage(false),
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())
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()));
160 vncConnectionAction
->deleteLater();
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()));
168 nxConnectionAction
->deleteLater();
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()));
176 rdpConnectionAction
->deleteLater();
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();
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
;
238 initialProtocol
= "rdp";
241 initialProtocol
= "nx";
244 initialProtocol
= "vnc";
247 m_addressNavigator
= new KUrlNavigator(0, KUrl(initialProtocol
+ "://"), this);
248 m_addressNavigator
->setCustomProtocols(QStringList()
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();
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"));
313 m_addressNavigator
->setUrl(KUrl(url
.scheme().toLower() + "://"));
315 RemoteView
*view
= 0;
317 if (url
.scheme().compare("vnc", Qt::CaseInsensitive
) == 0) {
319 view
= new VncView(this, url
);
321 } else if (url
.scheme().compare("nx", Qt::CaseInsensitive
) == 0) {
323 view
= new NxView(this, url
);
325 } else if (url
.scheme().compare("rdp", Qt::CaseInsensitive
) == 0) {
327 view
= new RdpView(this, url
);
329 } else if (url
.scheme().compare("test", Qt::CaseInsensitive
) == 0) {
331 view
= new TestView(this, url
);
335 KMessageBox::error(this,
336 i18n("The entered address cannot be handled."),
337 i18n("Unusable URL"));
342 KMessageBox::error(this, i18n("Support for %1:// has not been enabled during build.",
343 url
.scheme().toLower()),
344 i18n("Unusable URL"));
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
);
355 int numNonRemoteView
= 0;
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)
370 void MainWindow::openFromDockWidget(const QModelIndex
&index
)
372 QString data
= index
.data(Qt::UserRole
).toString();
373 if (!data
.isEmpty()) {
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;
383 m_tabWidget
->setCurrentIndex(i
+ numNonRemoteView
);
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
);
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
)
433 QString host
= m_remoteViewList
.at(m_currentRemoteView
)->host();
435 QString iconName
= "krdc";
439 case RemoteView::Connecting
:
440 iconName
= "network-connect";
441 message
= i18n("Connecting to %1", host
);
443 case RemoteView::Authenticating
:
444 iconName
= "dialog-password";
445 message
= i18n("Authenticating at %1", host
);
447 case RemoteView::Preparing
:
448 iconName
= "view-history";
449 message
= i18n("Preparing connection to %1", host
);
451 case RemoteView::Connected
:
453 message
= i18n("Connected to %1", host
);
455 // when started with command line fullscreen argument
456 if (m_switchFullscreenWhenConnected
) {
457 m_switchFullscreenWhenConnected
= false;
461 m_bookmarkManager
->addHistoryBookmark();
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()
483 if (m_fullscreenWindow
) {
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());
501 m_toolBar
->hideAndDestroy();
502 m_toolBar
->deleteLater();
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;
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();
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
);
559 void MainWindow::disconnect()
563 if (m_fullscreenWindow
) { // first close fullscreen view
567 QWidget
*tmp
= m_tabWidget
->currentWidget();
569 m_remoteViewList
.removeAt(m_currentRemoteView
);
571 m_tabWidget
->removeTab(m_tabWidget
->currentIndex());
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."));
588 #ifdef BUILD_ZEROCONF
589 if (widget
== m_zeroconfPage
) {
595 int numNonRemoteView
= 0;
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
)
627 m_remoteViewList
.at(m_currentRemoteView
)->setGrabAllKeys(grabAllKeys
);
630 void MainWindow::scale(bool scale
)
634 m_remoteViewList
.at(m_currentRemoteView
)->enableScaling(scale
);
637 void MainWindow::showRemoteViewToolbar()
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());
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
);
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();
699 if ((m_showStartPage
&& (m_tabWidget
->currentIndex() == 0)) ||
700 #ifdef BUILD_ZEROCONF
701 (m_zeroconfPage
&& (m_tabWidget
->currentIndex() == m_tabWidget
->indexOf(m_zeroconfPage
))) ||
703 (!m_showStartPage
&& (m_tabWidget
->currentIndex() < 0)))
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"))
744 // KConfigDialog didn't find an instance of this dialog, so lets
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()));
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
)
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;
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
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();
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()));
836 void MainWindow::showMenubar()
838 if (m_menubarAction
->isChecked())
844 void MainWindow::closeEvent(QCloseEvent
*event
)
848 if (Settings::systemTrayIcon()) {
849 hide(); // just hide the mainwindow, keep it in systemtray
855 void MainWindow::tabChanged(int index
)
857 kDebug(5010) << index
;
859 int numNonRemoteView
= 0;
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()));
900 vncConnectButton
->setVisible(false);
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()));
909 nxConnectButton
->setVisible(false);
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");
919 rdpConnectButton
->setVisible(false);
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);
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
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
);
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();
995 tabChanged(index
); // force update again because m_zeroconfPage was not null before
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"