1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2007 - 2013 Urs Wolfer <uwolfer @ kde.org> |
4 | ** Copyright (C) 2009 - 2010 Tony Murray <murraytony @ gmail.com> |
5 | ** |
6 | ** This file is part of KDE. |
7 | ** |
8 | ** This program is free software; you can redistribute it and/or modify |
9 | ** it under the terms of the GNU General Public License as published by |
10 | ** the Free Software Foundation; either version 2 of the License, or |
11 | ** (at your option) any later version. |
12 | ** |
13 | ** This program is distributed in the hope that it will be useful, |
14 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | ** GNU General Public License for more details. |
17 | ** |
18 | ** You should have received a copy of the GNU General Public License |
19 | ** along with this program; see the file COPYING. If not, write to |
20 | ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
21 | ** Boston, MA 02110-1301, USA. |
22 | ** |
23 | ****************************************************************************/ |
24 | |
25 | #include "mainwindow.h" |
26 | |
27 | #include "remoteview.h" |
28 | #include "settings.h" |
29 | #include "config/preferencesdialog.h" |
30 | #include "floatingtoolbar.h" |
31 | #include "bookmarkmanager.h" |
32 | #include "connectiondelegate.h" |
33 | #include "remotedesktopsmodel.h" |
34 | #include "systemtrayicon.h" |
35 | #include "tabbedviewwidget.h" |
36 | #include "hostpreferences.h" |
37 | |
38 | #ifdef TELEPATHY_SUPPORT |
39 | #include "tubesmanager.h" |
40 | #endif |
41 | |
42 | #include <KAction> |
43 | #include <KActionCollection> |
44 | #include <KActionMenu> |
45 | #include <KComboBox> |
46 | #include <KIcon> |
47 | #include <KInputDialog> |
48 | #include <KLineEdit> |
49 | #include <KLocale> |
50 | #include <KMenu> |
51 | #include <KMenuBar> |
52 | #include <KMessageBox> |
53 | #include <KNotifyConfigWidget> |
54 | #include <KPluginInfo> |
55 | #include <KPushButton> |
56 | #include <KStatusBar> |
57 | #include <KToggleAction> |
58 | #include <KToggleFullScreenAction> |
59 | #include <KServiceTypeTrader> |
60 | |
61 | #include <QClipboard> |
62 | #include <QDockWidget> |
63 | #include <QFontMetrics> |
64 | #include <QGroupBox> |
65 | #include <QHBoxLayout> |
66 | #include <QHeaderView> |
67 | #include <QLabel> |
68 | #include <QLayout> |
69 | #include <QScrollArea> |
70 | #include <QSortFilterProxyModel> |
71 | #include <QTableView> |
72 | #include <QTimer> |
73 | #include <QToolBar> |
74 | #include <QVBoxLayout> |
75 | |
76 | MainWindow::MainWindow(QWidget *parent) |
77 | : KXmlGuiWindow(parent), |
78 | m_fullscreenWindow(0), |
79 | m_protocolInput(0), |
80 | m_addressInput(0), |
81 | m_toolBar(0), |
82 | m_currentRemoteView(-1), |
83 | m_systemTrayIcon(0), |
84 | m_dockWidgetTableView(0), |
85 | m_newConnectionTableView(0), |
86 | #ifdef TELEPATHY_SUPPORT |
87 | m_tubesManager(0), |
88 | #endif |
89 | m_newConnectionWidget(0) |
90 | { |
91 | loadAllPlugins(); |
92 | |
93 | setupActions(); |
94 | |
95 | setStandardToolBarMenuEnabled(true); |
96 | |
97 | m_tabWidget = new TabbedViewWidget(this); |
98 | m_tabWidget->setMovable(true); |
99 | m_tabWidget->setTabPosition((KTabWidget::TabPosition) Settings::tabPosition()); |
100 | |
101 | #if QT_VERSION >= 0x040500 |
102 | m_tabWidget->setTabsClosable(Settings::tabCloseButton()); |
103 | #else |
104 | m_tabWidget->setCloseButtonEnabled(Settings::tabCloseButton()); |
105 | #endif |
106 | |
107 | connect(m_tabWidget, SIGNAL(closeRequest(QWidget*)), SLOT(closeTab(QWidget*))); |
108 | |
109 | if (Settings::tabMiddleClick()) |
110 | connect(m_tabWidget, SIGNAL(mouseMiddleClick(QWidget*)), SLOT(closeTab(QWidget*))); |
111 | |
112 | connect(m_tabWidget, SIGNAL(mouseDoubleClick(QWidget*)), SLOT(openTabSettings(QWidget*))); |
113 | connect(m_tabWidget, SIGNAL(mouseDoubleClick()), SLOT(newConnectionPage())); |
114 | connect(m_tabWidget, SIGNAL(contextMenu(QWidget*,QPoint)), SLOT(tabContextMenu(QWidget*,QPoint))); |
115 | |
116 | m_tabWidget->setMinimumSize(600, 400); |
117 | setCentralWidget(m_tabWidget); |
118 | |
119 | createDockWidget(); |
120 | |
121 | setupGUI(ToolBar | Keys | Save | Create); |
122 | |
123 | if (Settings::systemTrayIcon()) { |
124 | m_systemTrayIcon = new SystemTrayIcon(this); |
125 | if(m_fullscreenWindow) m_systemTrayIcon->setAssociatedWidget(m_fullscreenWindow); |
126 | } |
127 | |
128 | connect(m_tabWidget, SIGNAL(currentChanged(int)), SLOT(tabChanged(int))); |
129 | |
130 | if (Settings::showStatusBar()) |
131 | statusBar()->showMessage(i18n("KDE Remote Desktop Client started" )); |
132 | |
133 | updateActionStatus(); // disable remote view actions |
134 | |
135 | if (Settings::openSessions().count() == 0) // just create a new connection tab if there are no open sessions |
136 | m_tabWidget->addTab(newConnectionWidget(), i18n("New Connection" )); |
137 | |
138 | if (Settings::rememberSessions()) // give some time to create and show the window first |
139 | QTimer::singleShot(100, this, SLOT(restoreOpenSessions())); |
140 | } |
141 | |
142 | MainWindow::~MainWindow() |
143 | { |
144 | } |
145 | |
146 | void MainWindow::setupActions() |
147 | { |
148 | QAction *connectionAction = actionCollection()->addAction("new_connection" ); |
149 | connectionAction->setText(i18n("New Connection" )); |
150 | connectionAction->setIcon(KIcon("network-connect" )); |
151 | connect(connectionAction, SIGNAL(triggered()), SLOT(newConnectionPage())); |
152 | |
153 | QAction *screenshotAction = actionCollection()->addAction("take_screenshot" ); |
154 | screenshotAction->setText(i18n("Copy Screenshot to Clipboard" )); |
155 | screenshotAction->setIconText(i18n("Screenshot" )); |
156 | screenshotAction->setIcon(KIcon("ksnapshot" )); |
157 | connect(screenshotAction, SIGNAL(triggered()), SLOT(takeScreenshot())); |
158 | |
159 | KAction *fullscreenAction = actionCollection()->addAction("switch_fullscreen" ); // note: please do not switch to KStandardShortcut unless you know what you are doing (see history of this file) |
160 | fullscreenAction->setText(i18n("Switch to Full Screen Mode" )); |
161 | fullscreenAction->setIconText(i18n("Full Screen" )); |
162 | fullscreenAction->setIcon(KIcon("view-fullscreen" )); |
163 | fullscreenAction->setShortcut(KStandardShortcut::fullScreen()); |
164 | connect(fullscreenAction, SIGNAL(triggered()), SLOT(switchFullscreen())); |
165 | |
166 | QAction *viewOnlyAction = actionCollection()->addAction("view_only" ); |
167 | viewOnlyAction->setCheckable(true); |
168 | viewOnlyAction->setText(i18n("View Only" )); |
169 | viewOnlyAction->setIcon(KIcon("document-preview" )); |
170 | connect(viewOnlyAction, SIGNAL(triggered(bool)), SLOT(viewOnly(bool))); |
171 | |
172 | KAction *disconnectAction = actionCollection()->addAction("disconnect" ); |
173 | disconnectAction->setText(i18n("Disconnect" )); |
174 | disconnectAction->setIcon(KIcon("network-disconnect" )); |
175 | disconnectAction->setShortcut(QKeySequence::Close); |
176 | connect(disconnectAction, SIGNAL(triggered()), SLOT(disconnectHost())); |
177 | |
178 | QAction *showLocalCursorAction = actionCollection()->addAction("show_local_cursor" ); |
179 | showLocalCursorAction->setCheckable(true); |
180 | showLocalCursorAction->setIcon(KIcon("input-mouse" )); |
181 | showLocalCursorAction->setText(i18n("Show Local Cursor" )); |
182 | showLocalCursorAction->setIconText(i18n("Local Cursor" )); |
183 | connect(showLocalCursorAction, SIGNAL(triggered(bool)), SLOT(showLocalCursor(bool))); |
184 | |
185 | QAction *grabAllKeysAction = actionCollection()->addAction("grab_all_keys" ); |
186 | grabAllKeysAction->setCheckable(true); |
187 | grabAllKeysAction->setIcon(KIcon("configure-shortcuts" )); |
188 | grabAllKeysAction->setText(i18n("Grab All Possible Keys" )); |
189 | grabAllKeysAction->setIconText(i18n("Grab Keys" )); |
190 | connect(grabAllKeysAction, SIGNAL(triggered(bool)), SLOT(grabAllKeys(bool))); |
191 | |
192 | QAction *scaleAction = actionCollection()->addAction("scale" ); |
193 | scaleAction->setCheckable(true); |
194 | scaleAction->setIcon(KIcon("zoom-fit-best" )); |
195 | scaleAction->setText(i18n("Scale Remote Screen to Fit Window Size" )); |
196 | scaleAction->setIconText(i18n("Scale" )); |
197 | connect(scaleAction, SIGNAL(triggered(bool)), SLOT(scale(bool))); |
198 | |
199 | KStandardAction::quit(this, SLOT(quit()), actionCollection()); |
200 | KStandardAction::preferences(this, SLOT(preferences()), actionCollection()); |
201 | QAction *configNotifyAction = KStandardAction::configureNotifications(this, SLOT(configureNotifications()), actionCollection()); |
202 | configNotifyAction->setVisible(false); |
203 | m_menubarAction = KStandardAction::showMenubar(this, SLOT(showMenubar()), actionCollection()); |
204 | m_menubarAction->setChecked(!menuBar()->isHidden()); |
205 | |
206 | KActionMenu * = new KActionMenu(i18n("Bookmarks" ), actionCollection()); |
207 | m_bookmarkManager = new BookmarkManager(actionCollection(), bookmarkMenu->menu(), this); |
208 | actionCollection()->addAction("bookmark" , bookmarkMenu); |
209 | connect(m_bookmarkManager, SIGNAL(openUrl(KUrl)), SLOT(newConnection(KUrl))); |
210 | } |
211 | |
212 | void MainWindow::loadAllPlugins() |
213 | { |
214 | const KService::List offers = KServiceTypeTrader::self()->query("KRDC/Plugin" ); |
215 | |
216 | KConfigGroup conf(KGlobal::config(), "Plugins" ); |
217 | |
218 | for (int i = 0; i < offers.size(); i++) { |
219 | KService::Ptr offer = offers[i]; |
220 | |
221 | RemoteViewFactory *remoteView; |
222 | |
223 | KPluginInfo description(offer); |
224 | description.load(conf); |
225 | |
226 | const bool selected = description.isPluginEnabled(); |
227 | |
228 | if (selected) { |
229 | if ((remoteView = createPluginFromService(offer)) != 0) { |
230 | kDebug(5010) << "### Plugin " + description.name() + " found ###" ; |
231 | kDebug(5010) << "# Version:" << description.version(); |
232 | kDebug(5010) << "# Description:" << description.comment(); |
233 | kDebug(5010) << "# Author:" << description.author(); |
234 | const int sorting = offer->property("X-KDE-KRDC-Sorting" ).toInt(); |
235 | kDebug(5010) << "# Sorting:" << sorting; |
236 | |
237 | m_remoteViewFactories.insert(sorting, remoteView); |
238 | } else { |
239 | kDebug(5010) << "Error loading KRDC plugin (" << (offers[i])->library() << ')'; |
240 | } |
241 | } else { |
242 | kDebug(5010) << "# Plugin " + description.name() + " found, however it's not activated, skipping..." ; |
243 | continue; |
244 | } |
245 | } |
246 | |
247 | #ifdef TELEPATHY_SUPPORT |
248 | /* Start tube handler */ |
249 | m_tubesManager = new TubesManager(this); |
250 | connect(m_tubesManager, SIGNAL(newConnection(KUrl)), SLOT(newConnection(KUrl))); |
251 | #endif |
252 | } |
253 | |
254 | RemoteViewFactory *MainWindow::createPluginFromService(const KService::Ptr &service) |
255 | { |
256 | //try to load the specified library |
257 | KPluginFactory *factory = KPluginLoader(service->library()).factory(); |
258 | |
259 | if (!factory) { |
260 | kError(5010) << "KPluginFactory could not load the plugin:" << service->library(); |
261 | return 0; |
262 | } |
263 | |
264 | RemoteViewFactory *plugin = factory->create<RemoteViewFactory>(); |
265 | |
266 | return plugin; |
267 | } |
268 | |
269 | void MainWindow::restoreOpenSessions() |
270 | { |
271 | const QStringList list = Settings::openSessions(); |
272 | QStringList::ConstIterator it = list.begin(); |
273 | QStringList::ConstIterator end = list.end(); |
274 | while (it != end) { |
275 | newConnection(*it); |
276 | ++it; |
277 | } |
278 | } |
279 | |
280 | KUrl MainWindow::getInputUrl() |
281 | { |
282 | return KUrl(m_protocolInput->currentText() + "://" + m_addressInput->text()); |
283 | } |
284 | |
285 | void MainWindow::newConnection(const KUrl &newUrl, bool switchFullscreenWhenConnected, const QString &tabName) |
286 | { |
287 | m_switchFullscreenWhenConnected = switchFullscreenWhenConnected; |
288 | |
289 | const KUrl url = newUrl.isEmpty() ? getInputUrl() : newUrl; |
290 | |
291 | if (!url.isValid() || (url.host().isEmpty() && url.port() < 0) |
292 | || (!url.path().isEmpty() && url.path() != QLatin1String("/" ))) { |
293 | KMessageBox::error(this, |
294 | i18n("The entered address does not have the required form.\n Syntax: [username@]host[:port]" ), |
295 | i18n("Malformed URL" )); |
296 | return; |
297 | } |
298 | |
299 | if (m_protocolInput && m_addressInput) { |
300 | int index = m_protocolInput->findText(url.protocol()); |
301 | if (index>=0) m_protocolInput->setCurrentIndex(index); |
302 | m_addressInput->setText(url.authority()); |
303 | } |
304 | |
305 | RemoteView *view = 0; |
306 | KConfigGroup configGroup = Settings::self()->config()->group("hostpreferences" ).group(url.prettyUrl(KUrl::RemoveTrailingSlash)); |
307 | |
308 | foreach(RemoteViewFactory *factory, m_remoteViewFactories) { |
309 | if (factory->supportsUrl(url)) { |
310 | view = factory->createView(this, url, configGroup); |
311 | kDebug(5010) << "Found plugin to handle url (" + url.url() + "): " + view->metaObject()->className(); |
312 | break; |
313 | } |
314 | } |
315 | |
316 | if (!view) { |
317 | KMessageBox::error(this, |
318 | i18n("The entered address cannot be handled." ), |
319 | i18n("Unusable URL" )); |
320 | return; |
321 | } |
322 | |
323 | // Configure the view |
324 | HostPreferences* prefs = view->hostPreferences(); |
325 | if (! prefs->showDialogIfNeeded(this)) { |
326 | delete view; |
327 | return; |
328 | } |
329 | |
330 | view->showDotCursor(prefs->showLocalCursor() ? RemoteView::CursorOn : RemoteView::CursorOff); |
331 | view->setViewOnly(prefs->viewOnly()); |
332 | if (! switchFullscreenWhenConnected) view->enableScaling(prefs->windowedScale()); |
333 | |
334 | connect(view, SIGNAL(framebufferSizeChanged(int,int)), this, SLOT(resizeTabWidget(int,int))); |
335 | connect(view, SIGNAL(statusChanged(RemoteView::RemoteStatus)), this, SLOT(statusChanged(RemoteView::RemoteStatus))); |
336 | connect(view, SIGNAL(disconnected()), this, SLOT(disconnectHost())); |
337 | |
338 | view->winId(); // native widget workaround for bug 253365 |
339 | QScrollArea *scrollArea = createScrollArea(m_tabWidget, view); |
340 | |
341 | const int indexOfNewConnectionWidget = m_tabWidget->indexOf(m_newConnectionWidget); |
342 | if (indexOfNewConnectionWidget >= 0) |
343 | m_tabWidget->removeTab(indexOfNewConnectionWidget); |
344 | |
345 | const int newIndex = m_tabWidget->addTab(scrollArea, KIcon("krdc" ), tabName.isEmpty() ? url.prettyUrl(KUrl::RemoveTrailingSlash) : tabName); |
346 | m_tabWidget->setCurrentIndex(newIndex); |
347 | m_remoteViewMap.insert(m_tabWidget->widget(newIndex), view); |
348 | tabChanged(newIndex); // force to update m_currentRemoteView (tabChanged is not emitted when start page has been disabled) |
349 | |
350 | view->start(); |
351 | } |
352 | |
353 | void MainWindow::openFromRemoteDesktopsModel(const QModelIndex &index) |
354 | { |
355 | const QString urlString = index.data(10001).toString(); |
356 | const QString nameString = index.data(10003).toString(); |
357 | if (!urlString.isEmpty()) { |
358 | const KUrl url(urlString); |
359 | // first check if url has already been opened; in case show the tab |
360 | foreach (QWidget *widget, m_remoteViewMap.keys()) { |
361 | if (m_remoteViewMap.value(widget)->url() == url) { |
362 | m_tabWidget->setCurrentWidget(widget); |
363 | return; |
364 | } |
365 | } |
366 | |
367 | newConnection(url, false, nameString); |
368 | } |
369 | } |
370 | |
371 | void MainWindow::resizeTabWidget(int w, int h) |
372 | { |
373 | kDebug(5010) << "tabwidget resize, view size: w: " << w << ", h: " << h; |
374 | if (m_fullscreenWindow) { |
375 | kDebug(5010) << "in fullscreen mode, refusing to resize" ; |
376 | return; |
377 | } |
378 | |
379 | const QSize viewSize = QSize(w,h); |
380 | QDesktopWidget *desktop = QApplication::desktop(); |
381 | |
382 | if (Settings::fullscreenOnConnect()) { |
383 | int currentScreen = desktop->screenNumber(this); |
384 | const QSize screenSize = desktop->screenGeometry(currentScreen).size(); |
385 | |
386 | if (screenSize == viewSize) { |
387 | kDebug(5010) << "screen size equal to target view size -> switch to fullscreen mode" ; |
388 | switchFullscreen(); |
389 | return; |
390 | } |
391 | } |
392 | |
393 | if (Settings::resizeOnConnect()) { |
394 | QWidget* currentWidget = m_tabWidget->currentWidget(); |
395 | const QSize newWindowSize = size() - currentWidget->frameSize() + viewSize; |
396 | |
397 | const QSize desktopSize = desktop->availableGeometry().size(); |
398 | kDebug(5010) << "new window size: " << newWindowSize << " available space:" << desktopSize; |
399 | |
400 | if ((newWindowSize.width() >= desktopSize.width()) || (newWindowSize.height() >= desktopSize.height())) { |
401 | kDebug(5010) << "remote desktop needs more space than available -> show window maximized" ; |
402 | setWindowState(windowState() | Qt::WindowMaximized); |
403 | return; |
404 | } |
405 | |
406 | resize(newWindowSize); |
407 | } |
408 | } |
409 | |
410 | void MainWindow::statusChanged(RemoteView::RemoteStatus status) |
411 | { |
412 | kDebug(5010) << status; |
413 | |
414 | // the remoteview is already deleted, so don't show it; otherwise it would crash |
415 | if (status == RemoteView::Disconnecting || status == RemoteView::Disconnected) |
416 | return; |
417 | |
418 | RemoteView *view = qobject_cast<RemoteView*>(QObject::sender()); |
419 | const QString host = view->host(); |
420 | |
421 | QString iconName = "krdc" ; |
422 | QString message; |
423 | |
424 | switch (status) { |
425 | case RemoteView::Connecting: |
426 | iconName = "network-connect" ; |
427 | message = i18n("Connecting to %1" , host); |
428 | break; |
429 | case RemoteView::Authenticating: |
430 | iconName = "dialog-password" ; |
431 | message = i18n("Authenticating at %1" , host); |
432 | break; |
433 | case RemoteView::Preparing: |
434 | iconName = "view-history" ; |
435 | message = i18n("Preparing connection to %1" , host); |
436 | break; |
437 | case RemoteView::Connected: |
438 | iconName = "krdc" ; |
439 | message = i18n("Connected to %1" , host); |
440 | |
441 | if (view->grabAllKeys() != view->hostPreferences()->grabAllKeys()) { |
442 | view->setGrabAllKeys(view->hostPreferences()->grabAllKeys()); |
443 | updateActionStatus(); |
444 | } |
445 | |
446 | // when started with command line fullscreen argument |
447 | if (m_switchFullscreenWhenConnected) { |
448 | m_switchFullscreenWhenConnected = false; |
449 | switchFullscreen(); |
450 | } |
451 | |
452 | if (Settings::rememberHistory()) { |
453 | m_bookmarkManager->addHistoryBookmark(view); |
454 | } |
455 | |
456 | break; |
457 | default: |
458 | break; |
459 | } |
460 | |
461 | m_tabWidget->setTabIcon(m_tabWidget->indexOf(view), KIcon(iconName)); |
462 | if (Settings::showStatusBar()) |
463 | statusBar()->showMessage(message); |
464 | } |
465 | |
466 | void MainWindow::takeScreenshot() |
467 | { |
468 | const QPixmap snapshot = currentRemoteView()->takeScreenshot(); |
469 | |
470 | QApplication::clipboard()->setPixmap(snapshot); |
471 | } |
472 | |
473 | void MainWindow::switchFullscreen() |
474 | { |
475 | kDebug(5010); |
476 | |
477 | if (m_fullscreenWindow) { |
478 | // Leaving full screen mode |
479 | m_fullscreenWindow->setWindowState(0); |
480 | m_fullscreenWindow->hide(); |
481 | |
482 | m_tabWidget->setTabBarHidden(m_tabWidget->count() <= 1 && !Settings::showTabBar()); |
483 | m_tabWidget->setDocumentMode(false); |
484 | setCentralWidget(m_tabWidget); |
485 | |
486 | show(); |
487 | restoreGeometry(m_mainWindowGeometry); |
488 | if (m_systemTrayIcon) m_systemTrayIcon->setAssociatedWidget(this); |
489 | |
490 | foreach (RemoteView * view, m_remoteViewMap.values()) { |
491 | view->enableScaling(view->hostPreferences()->windowedScale()); |
492 | } |
493 | |
494 | if (m_toolBar) { |
495 | m_toolBar->hideAndDestroy(); |
496 | m_toolBar->deleteLater(); |
497 | m_toolBar = 0; |
498 | } |
499 | |
500 | actionCollection()->action("switch_fullscreen" )->setIcon(KIcon("view-fullscreen" )); |
501 | actionCollection()->action("switch_fullscreen" )->setText(i18n("Switch to Full Screen Mode" )); |
502 | actionCollection()->action("switch_fullscreen" )->setIconText(i18n("Full Screen" )); |
503 | |
504 | m_fullscreenWindow->deleteLater(); |
505 | m_fullscreenWindow = 0; |
506 | } else { |
507 | // Entering full screen mode |
508 | m_fullscreenWindow = new QWidget(this, Qt::Window); |
509 | m_fullscreenWindow->setWindowTitle(i18nc("window title when in full screen mode (for example displayed in tasklist)" , |
510 | "KDE Remote Desktop Client (Full Screen)" )); |
511 | |
512 | m_mainWindowGeometry = saveGeometry(); |
513 | |
514 | m_tabWidget->setTabBarHidden(true); |
515 | m_tabWidget->setDocumentMode(true); |
516 | |
517 | foreach(RemoteView *currentView, m_remoteViewMap) { |
518 | currentView->enableScaling(currentView->hostPreferences()->fullscreenScale()); |
519 | } |
520 | |
521 | QVBoxLayout *fullscreenLayout = new QVBoxLayout(m_fullscreenWindow); |
522 | fullscreenLayout->setContentsMargins(QMargins(0, 0, 0, 0)); |
523 | fullscreenLayout->addWidget(m_tabWidget); |
524 | |
525 | KToggleFullScreenAction::setFullScreen(m_fullscreenWindow, true); |
526 | |
527 | MinimizePixel *minimizePixel = new MinimizePixel(m_fullscreenWindow); |
528 | minimizePixel->winId(); // force it to be a native widget (prevents problem with QX11EmbedContainer) |
529 | connect(minimizePixel, SIGNAL(rightClicked()), m_fullscreenWindow, SLOT(showMinimized())); |
530 | m_fullscreenWindow->installEventFilter(this); |
531 | |
532 | m_fullscreenWindow->show(); |
533 | hide(); // hide after showing the new window so it stays on the same screen |
534 | |
535 | if (m_systemTrayIcon) m_systemTrayIcon->setAssociatedWidget(m_fullscreenWindow); |
536 | |
537 | actionCollection()->action("switch_fullscreen" )->setIcon(KIcon("view-restore" )); |
538 | actionCollection()->action("switch_fullscreen" )->setText(i18n("Switch to Window Mode" )); |
539 | actionCollection()->action("switch_fullscreen" )->setIconText(i18n("Window Mode" )); |
540 | showRemoteViewToolbar(); |
541 | } |
542 | if (m_tabWidget->currentWidget() == m_newConnectionWidget) { |
543 | m_addressInput->setFocus(); |
544 | } |
545 | } |
546 | |
547 | QScrollArea *MainWindow::createScrollArea(QWidget *parent, RemoteView *remoteView) |
548 | { |
549 | RemoteViewScrollArea *scrollArea = new RemoteViewScrollArea(parent); |
550 | scrollArea->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); |
551 | |
552 | connect(scrollArea, SIGNAL(resized(int,int)), remoteView, SLOT(scaleResize(int,int))); |
553 | |
554 | QPalette palette = scrollArea->palette(); |
555 | palette.setColor(QPalette::Dark, Settings::backgroundColor()); |
556 | scrollArea->setPalette(palette); |
557 | |
558 | scrollArea->setBackgroundRole(QPalette::Dark); |
559 | scrollArea->setFrameStyle(QFrame::NoFrame); |
560 | |
561 | scrollArea->setWidget(remoteView); |
562 | |
563 | return scrollArea; |
564 | } |
565 | |
566 | void MainWindow::disconnectHost() |
567 | { |
568 | kDebug(5010); |
569 | |
570 | RemoteView *view = qobject_cast<RemoteView*>(QObject::sender()); |
571 | |
572 | QWidget *widgetToDelete; |
573 | if (view) { |
574 | widgetToDelete = (QWidget*) view->parent()->parent(); |
575 | m_remoteViewMap.remove(m_remoteViewMap.key(view)); |
576 | } else { |
577 | widgetToDelete = m_tabWidget->currentWidget(); |
578 | view = currentRemoteView(); |
579 | m_remoteViewMap.remove(m_remoteViewMap.key(view)); |
580 | } |
581 | |
582 | saveHostPrefs(view); |
583 | view->startQuitting(); // some deconstructors can't properly quit, so quit early |
584 | m_tabWidget->removePage(widgetToDelete); |
585 | widgetToDelete->deleteLater(); |
586 | #ifdef TELEPATHY_SUPPORT |
587 | m_tubesManager->closeTube(view->url()); |
588 | #endif |
589 | |
590 | // if closing the last connection, create new connection tab |
591 | if (m_tabWidget->count() == 0) { |
592 | newConnectionPage(false); |
593 | } |
594 | |
595 | // if the newConnectionWidget is the only tab and we are fullscreen, switch to window mode |
596 | if (m_fullscreenWindow && m_tabWidget->count() == 1 && m_tabWidget->currentWidget() == m_newConnectionWidget) { |
597 | switchFullscreen(); |
598 | } |
599 | } |
600 | |
601 | void MainWindow::closeTab(QWidget *widget) |
602 | { |
603 | bool isNewConnectionPage = widget == m_newConnectionWidget; |
604 | |
605 | if (!isNewConnectionPage) { |
606 | RemoteView *view = m_remoteViewMap.value(widget); |
607 | m_remoteViewMap.remove(m_remoteViewMap.key(view)); |
608 | view->startQuitting(); |
609 | #ifdef TELEPATHY_SUPPORT |
610 | m_tubesManager->closeTube(view->url()); |
611 | #endif |
612 | widget->deleteLater(); |
613 | } |
614 | |
615 | m_tabWidget->removePage(widget); |
616 | |
617 | // if closing the last connection, create new connection tab |
618 | if (m_tabWidget->count() == 0) { |
619 | newConnectionPage(false); |
620 | } |
621 | |
622 | // if the newConnectionWidget is the only tab and we are fullscreen, switch to window mode |
623 | if (m_fullscreenWindow && m_tabWidget->count() == 1 && m_tabWidget->currentWidget() == m_newConnectionWidget) { |
624 | switchFullscreen(); |
625 | } |
626 | } |
627 | |
628 | void MainWindow::openTabSettings(QWidget *widget) |
629 | { |
630 | RemoteViewScrollArea *scrollArea = qobject_cast<RemoteViewScrollArea*>(widget); |
631 | if (!scrollArea) return; |
632 | RemoteView *view = qobject_cast<RemoteView*>(scrollArea->widget()); |
633 | if (!view) return; |
634 | |
635 | const QString url = view->url().url(); |
636 | kDebug(5010) << url; |
637 | |
638 | showSettingsDialog(url); |
639 | } |
640 | |
641 | void MainWindow::showSettingsDialog(const QString &url) |
642 | { |
643 | HostPreferences *prefs = 0; |
644 | |
645 | foreach(RemoteViewFactory *factory, remoteViewFactoriesList()) { |
646 | if (factory->supportsUrl(url)) { |
647 | prefs = factory->createHostPreferences(Settings::self()->config()->group("hostpreferences" ).group(url), this); |
648 | if (prefs) { |
649 | kDebug(5010) << "Found plugin to handle url (" + url + "): " + prefs->metaObject()->className(); |
650 | } else { |
651 | kDebug(5010) << "Found plugin to handle url (" + url + "), but plugin does not provide preferences" ; |
652 | } |
653 | } |
654 | } |
655 | |
656 | if (prefs) { |
657 | prefs->setShownWhileConnected(true); |
658 | prefs->showDialog(this); |
659 | } else { |
660 | KMessageBox::error(this, |
661 | i18n("The selected host cannot be handled." ), |
662 | i18n("Unusable URL" )); |
663 | } |
664 | } |
665 | |
666 | void MainWindow::showConnectionContextMenu(const QPoint &pos) |
667 | { |
668 | // QTableView does not take headers into account when it does mapToGlobal(), so calculate the offset |
669 | QPoint offset = QPoint(m_newConnectionTableView->verticalHeader()->size().width(), |
670 | m_newConnectionTableView->horizontalHeader()->size().height()); |
671 | QModelIndex index = m_newConnectionTableView->indexAt(pos); |
672 | |
673 | if (!index.isValid()) |
674 | return; |
675 | |
676 | const QString url = index.data(10001).toString(); |
677 | const QString title = index.model()->index(index.row(), RemoteDesktopsModel::Title).data(Qt::DisplayRole).toString(); |
678 | const QString source = index.model()->index(index.row(), RemoteDesktopsModel::Source).data(Qt::DisplayRole).toString(); |
679 | |
680 | KMenu * = new KMenu(m_newConnectionTableView); |
681 | menu->addTitle(url); |
682 | |
683 | QAction *connectAction = menu->addAction(KIcon("network-connect" ), i18n("Connect" )); |
684 | QAction *renameAction = menu->addAction(KIcon("edit-rename" ), i18n("Rename" )); |
685 | QAction *settingsAction = menu->addAction(KIcon("configure" ), i18n("Settings" )); |
686 | QAction *deleteAction = menu->addAction(KIcon("edit-delete" ), i18n("Delete" )); |
687 | |
688 | // not very clean, but it works, |
689 | if (!(source == i18nc("Where each displayed link comes from" , "Bookmarks" ) || |
690 | source == i18nc("Where each displayed link comes from" , "History" ))) { |
691 | renameAction->setEnabled(false); |
692 | deleteAction->setEnabled(false); |
693 | } |
694 | |
695 | QAction *selectedAction = menu->exec(m_newConnectionTableView->mapToGlobal(pos + offset)); |
696 | |
697 | if (selectedAction == connectAction) { |
698 | openFromRemoteDesktopsModel(index); |
699 | } else if (selectedAction == renameAction) { |
700 | //TODO: use inline editor if possible |
701 | bool ok = false; |
702 | const QString newTitle = KInputDialog::getText(i18n("Rename %1" , title), i18n("Rename %1 to" , title), title, &ok, this); |
703 | if (ok && !newTitle.isEmpty()) { |
704 | BookmarkManager::updateTitle(m_bookmarkManager->getManager(), url, newTitle); |
705 | } |
706 | } else if (selectedAction == settingsAction) { |
707 | showSettingsDialog(url); |
708 | } else if (selectedAction == deleteAction) { |
709 | |
710 | if (KMessageBox::warningContinueCancel(this, i18n("Are you sure you want to delete %1?" , url), i18n("Delete %1" , title), |
711 | KStandardGuiItem::del()) == KMessageBox::Continue) { |
712 | BookmarkManager::removeByUrl(m_bookmarkManager->getManager(), url); |
713 | } |
714 | } |
715 | |
716 | menu->deleteLater(); |
717 | } |
718 | |
719 | void MainWindow::tabContextMenu(QWidget *widget, const QPoint &point) |
720 | { |
721 | RemoteViewScrollArea *scrollArea = qobject_cast<RemoteViewScrollArea*>(widget); |
722 | if (!scrollArea) return; |
723 | RemoteView *view = qobject_cast<RemoteView*>(scrollArea->widget()); |
724 | if (!view) return; |
725 | |
726 | const QString url = view->url().prettyUrl(KUrl::RemoveTrailingSlash); |
727 | kDebug(5010) << url; |
728 | |
729 | KMenu * = new KMenu(this); |
730 | menu->addTitle(url); |
731 | QAction *bookmarkAction = menu->addAction(KIcon("bookmark-new" ), i18n("Add Bookmark" )); |
732 | QAction *closeAction = menu->addAction(KIcon("tab-close" ), i18n("Close Tab" )); |
733 | QAction *selectedAction = menu->exec(point); |
734 | if (selectedAction) { |
735 | if (selectedAction == closeAction) { |
736 | closeTab(widget); |
737 | } else if (selectedAction == bookmarkAction) { |
738 | m_bookmarkManager->addManualBookmark(url, url); |
739 | } |
740 | } |
741 | menu->deleteLater(); |
742 | } |
743 | |
744 | void MainWindow::showLocalCursor(bool showLocalCursor) |
745 | { |
746 | kDebug(5010) << showLocalCursor; |
747 | |
748 | RemoteView* view = currentRemoteView(); |
749 | view->showDotCursor(showLocalCursor ? RemoteView::CursorOn : RemoteView::CursorOff); |
750 | view->hostPreferences()->setShowLocalCursor(showLocalCursor); |
751 | saveHostPrefs(view); |
752 | } |
753 | |
754 | void MainWindow::viewOnly(bool viewOnly) |
755 | { |
756 | kDebug(5010) << viewOnly; |
757 | |
758 | RemoteView* view = currentRemoteView(); |
759 | view->setViewOnly(viewOnly); |
760 | view->hostPreferences()->setViewOnly(viewOnly); |
761 | saveHostPrefs(view); |
762 | } |
763 | |
764 | void MainWindow::grabAllKeys(bool grabAllKeys) |
765 | { |
766 | kDebug(5010); |
767 | |
768 | RemoteView* view = currentRemoteView(); |
769 | view->setGrabAllKeys(grabAllKeys); |
770 | view->hostPreferences()->setGrabAllKeys(grabAllKeys); |
771 | saveHostPrefs(view); |
772 | } |
773 | |
774 | void MainWindow::scale(bool scale) |
775 | { |
776 | kDebug(5010); |
777 | |
778 | RemoteView* view = currentRemoteView(); |
779 | view->enableScaling(scale); |
780 | if (m_fullscreenWindow) |
781 | view->hostPreferences()->setFullscreenScale(scale); |
782 | else |
783 | view->hostPreferences()->setWindowedScale(scale); |
784 | |
785 | saveHostPrefs(view); |
786 | } |
787 | |
788 | void MainWindow::showRemoteViewToolbar() |
789 | { |
790 | kDebug(5010); |
791 | |
792 | if (!m_toolBar) { |
793 | m_toolBar = new FloatingToolBar(m_fullscreenWindow, m_fullscreenWindow); |
794 | m_toolBar->winId(); // force it to be a native widget (prevents problem with QX11EmbedContainer) |
795 | m_toolBar->setSide(FloatingToolBar::Top); |
796 | |
797 | KComboBox *sessionComboBox = new KComboBox(m_toolBar); |
798 | sessionComboBox->setStyleSheet("QComboBox:!editable{background:transparent;}" ); |
799 | sessionComboBox->setModel(m_tabWidget->getModel()); |
800 | sessionComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); |
801 | sessionComboBox->setCurrentIndex(m_tabWidget->currentIndex()); |
802 | connect(sessionComboBox, SIGNAL(activated(int)), m_tabWidget, SLOT(setCurrentIndex(int))); |
803 | connect(m_tabWidget, SIGNAL(currentChanged(int)), sessionComboBox, SLOT(setCurrentIndex(int))); |
804 | m_toolBar->addWidget(sessionComboBox); |
805 | |
806 | QToolBar *buttonBox = new QToolBar(m_toolBar); |
807 | |
808 | buttonBox->addAction(actionCollection()->action("new_connection" )); |
809 | buttonBox->addAction(actionCollection()->action("switch_fullscreen" )); |
810 | |
811 | QAction *minimizeAction = new QAction(m_toolBar); |
812 | minimizeAction->setIcon(KIcon("go-down" )); |
813 | minimizeAction->setText(i18n("Minimize Full Screen Window" )); |
814 | connect(minimizeAction, SIGNAL(triggered()), m_fullscreenWindow, SLOT(showMinimized())); |
815 | buttonBox->addAction(minimizeAction); |
816 | |
817 | buttonBox->addAction(actionCollection()->action("take_screenshot" )); |
818 | buttonBox->addAction(actionCollection()->action("view_only" )); |
819 | buttonBox->addAction(actionCollection()->action("show_local_cursor" )); |
820 | buttonBox->addAction(actionCollection()->action("grab_all_keys" )); |
821 | buttonBox->addAction(actionCollection()->action("scale" )); |
822 | buttonBox->addAction(actionCollection()->action("disconnect" )); |
823 | buttonBox->addAction(actionCollection()->action("file_quit" )); |
824 | |
825 | QAction *stickToolBarAction = new QAction(m_toolBar); |
826 | stickToolBarAction->setCheckable(true); |
827 | stickToolBarAction->setIcon(KIcon("object-locked" )); |
828 | stickToolBarAction->setText(i18n("Stick Toolbar" )); |
829 | connect(stickToolBarAction, SIGNAL(triggered(bool)), m_toolBar, SLOT(setSticky(bool))); |
830 | buttonBox->addAction(stickToolBarAction); |
831 | |
832 | m_toolBar->addWidget(buttonBox); |
833 | } |
834 | } |
835 | |
836 | void setActionStatus(QAction* action, bool enabled, bool visible, bool checked) |
837 | { |
838 | action->setEnabled(enabled); |
839 | action->setVisible(visible); |
840 | action->setChecked(checked); |
841 | } |
842 | |
843 | void MainWindow::updateActionStatus() |
844 | { |
845 | kDebug(5010) << m_tabWidget->currentIndex(); |
846 | |
847 | bool enabled = true; |
848 | |
849 | if (m_tabWidget->currentWidget() == m_newConnectionWidget) |
850 | enabled = false; |
851 | |
852 | RemoteView* view = (m_currentRemoteView >= 0 && enabled) ? currentRemoteView() : 0; |
853 | |
854 | actionCollection()->action("take_screenshot" )->setEnabled(enabled); |
855 | actionCollection()->action("disconnect" )->setEnabled(enabled); |
856 | |
857 | setActionStatus(actionCollection()->action("view_only" ), |
858 | enabled, |
859 | true, |
860 | view ? view->viewOnly() : false); |
861 | |
862 | setActionStatus(actionCollection()->action("show_local_cursor" ), |
863 | enabled, |
864 | view ? view->supportsLocalCursor() : false, |
865 | view ? view->dotCursorState() == RemoteView::CursorOn : false); |
866 | |
867 | setActionStatus(actionCollection()->action("scale" ), |
868 | enabled, |
869 | view ? view->supportsScaling() : false, |
870 | view ? view->scaling() : false); |
871 | |
872 | setActionStatus(actionCollection()->action("grab_all_keys" ), |
873 | enabled, |
874 | enabled, |
875 | view ? view->grabAllKeys() : false); |
876 | } |
877 | |
878 | void MainWindow::preferences() |
879 | { |
880 | // An instance of your dialog could be already created and could be |
881 | // cached, in which case you want to display the cached dialog |
882 | // instead of creating another one |
883 | if (PreferencesDialog::showDialog("preferences" )) |
884 | return; |
885 | |
886 | // KConfigDialog didn't find an instance of this dialog, so lets |
887 | // create it: |
888 | PreferencesDialog *dialog = new PreferencesDialog(this, Settings::self()); |
889 | |
890 | // User edited the configuration - update your local copies of the |
891 | // configuration data |
892 | connect(dialog, SIGNAL(settingsChanged(QString)), |
893 | this, SLOT(updateConfiguration())); |
894 | |
895 | dialog->show(); |
896 | } |
897 | |
898 | void MainWindow::updateConfiguration() |
899 | { |
900 | if (!Settings::showStatusBar()) |
901 | statusBar()->deleteLater(); |
902 | else |
903 | statusBar()->showMessage("" ); // force creation of statusbar |
904 | |
905 | m_tabWidget->setTabBarHidden((m_tabWidget->count() <= 1 && !Settings::showTabBar()) || m_fullscreenWindow); |
906 | m_tabWidget->setTabPosition((KTabWidget::TabPosition) Settings::tabPosition()); |
907 | #if QT_VERSION >= 0x040500 |
908 | m_tabWidget->setTabsClosable(Settings::tabCloseButton()); |
909 | #else |
910 | m_tabWidget->setCloseButtonEnabled(Settings::tabCloseButton()); |
911 | #endif |
912 | disconnect(m_tabWidget, SIGNAL(mouseMiddleClick(QWidget*)), this, SLOT(closeTab(QWidget*))); // just be sure it is not connected twice |
913 | if (Settings::tabMiddleClick()) |
914 | connect(m_tabWidget, SIGNAL(mouseMiddleClick(QWidget*)), SLOT(closeTab(QWidget*))); |
915 | |
916 | if (Settings::systemTrayIcon() && !m_systemTrayIcon) { |
917 | m_systemTrayIcon = new SystemTrayIcon(this); |
918 | if(m_fullscreenWindow) m_systemTrayIcon->setAssociatedWidget(m_fullscreenWindow); |
919 | } else if (m_systemTrayIcon) { |
920 | delete m_systemTrayIcon; |
921 | m_systemTrayIcon = 0; |
922 | } |
923 | |
924 | // update the scroll areas background color |
925 | for (int i = 0; i < m_tabWidget->count(); ++i) { |
926 | QPalette palette = m_tabWidget->widget(i)->palette(); |
927 | palette.setColor(QPalette::Dark, Settings::backgroundColor()); |
928 | m_tabWidget->widget(i)->setPalette(palette); |
929 | } |
930 | |
931 | // Send update configuration message to all views |
932 | foreach (RemoteView *view, m_remoteViewMap.values()) { |
933 | view->updateConfiguration(); |
934 | } |
935 | |
936 | } |
937 | |
938 | void MainWindow::quit(bool systemEvent) |
939 | { |
940 | const bool haveRemoteConnections = !m_remoteViewMap.isEmpty(); |
941 | if (systemEvent || !haveRemoteConnections || KMessageBox::warningContinueCancel(this, |
942 | i18n("Are you sure you want to quit the KDE Remote Desktop Client?" ), |
943 | i18n("Confirm Quit" ), |
944 | KStandardGuiItem::quit(), KStandardGuiItem::cancel(), |
945 | "DoNotAskBeforeExit" ) == KMessageBox::Continue) { |
946 | |
947 | if (Settings::rememberSessions()) { // remember open remote views for next startup |
948 | QStringList list; |
949 | foreach (RemoteView *view, m_remoteViewMap.values()) { |
950 | kDebug(5010) << view->url(); |
951 | list.append(view->url().prettyUrl(KUrl::RemoveTrailingSlash)); |
952 | } |
953 | Settings::setOpenSessions(list); |
954 | } |
955 | |
956 | saveHostPrefs(); |
957 | |
958 | foreach (RemoteView *view, m_remoteViewMap.values()) { |
959 | view->startQuitting(); |
960 | } |
961 | |
962 | Settings::self()->writeConfig(); |
963 | |
964 | qApp->quit(); |
965 | } |
966 | } |
967 | |
968 | void MainWindow::configureNotifications() |
969 | { |
970 | KNotifyConfigWidget::configure(this); |
971 | } |
972 | |
973 | void MainWindow::showMenubar() |
974 | { |
975 | if (m_menubarAction->isChecked()) |
976 | menuBar()->show(); |
977 | else |
978 | menuBar()->hide(); |
979 | } |
980 | |
981 | bool MainWindow::eventFilter(QObject *obj, QEvent *event) |
982 | { |
983 | // check for close events from the fullscreen window. |
984 | if (obj == m_fullscreenWindow && event->type() == QEvent::Close) { |
985 | quit(true); |
986 | } |
987 | // allow other events to pass through. |
988 | return QObject::eventFilter(obj, event); |
989 | } |
990 | |
991 | void MainWindow::closeEvent(QCloseEvent *event) |
992 | { |
993 | if (event->spontaneous()) { // Returns true if the event originated outside the application (a system event); otherwise returns false. |
994 | event->ignore(); |
995 | if (Settings::systemTrayIcon()) { |
996 | hide(); // just hide the mainwindow, keep it in systemtray |
997 | } else { |
998 | quit(); |
999 | } |
1000 | } else { |
1001 | quit(true); |
1002 | } |
1003 | } |
1004 | |
1005 | void MainWindow::saveProperties(KConfigGroup &group) |
1006 | { |
1007 | kDebug(5010); |
1008 | KMainWindow::saveProperties(group); |
1009 | saveHostPrefs(); |
1010 | } |
1011 | |
1012 | |
1013 | void MainWindow::saveHostPrefs() |
1014 | { |
1015 | foreach (RemoteView *view, m_remoteViewMap.values()) { |
1016 | saveHostPrefs(view); |
1017 | view->startQuitting(); |
1018 | } |
1019 | } |
1020 | |
1021 | void MainWindow::saveHostPrefs(RemoteView* view) |
1022 | { |
1023 | // should saving this be a user option? |
1024 | if (view && view->scaling()) { |
1025 | QSize viewSize = m_tabWidget->currentWidget()->size(); |
1026 | kDebug(5010) << "saving window size:" << viewSize; |
1027 | view->hostPreferences()->setWidth(viewSize.width()); |
1028 | view->hostPreferences()->setHeight(viewSize.height()); |
1029 | } |
1030 | |
1031 | Settings::self()->config()->sync(); |
1032 | } |
1033 | |
1034 | void MainWindow::tabChanged(int index) |
1035 | { |
1036 | kDebug(5010) << index; |
1037 | |
1038 | m_tabWidget->setTabBarHidden((m_tabWidget->count() <= 1 && !Settings::showTabBar()) || m_fullscreenWindow); |
1039 | |
1040 | m_currentRemoteView = index; |
1041 | |
1042 | if (m_tabWidget->currentWidget() == m_newConnectionWidget) { |
1043 | m_currentRemoteView = -1; |
1044 | if(m_addressInput) m_addressInput->setFocus(); |
1045 | } |
1046 | |
1047 | const QString tabTitle = m_tabWidget->tabText(index).remove('&'); |
1048 | setCaption(tabTitle == i18n("New Connection" ) ? QString() : tabTitle); |
1049 | |
1050 | updateActionStatus(); |
1051 | } |
1052 | |
1053 | QWidget* MainWindow::newConnectionWidget() |
1054 | { |
1055 | if (m_newConnectionWidget) |
1056 | return m_newConnectionWidget; |
1057 | |
1058 | m_newConnectionWidget = new QWidget(this); |
1059 | |
1060 | QVBoxLayout *startLayout = new QVBoxLayout(m_newConnectionWidget); |
1061 | startLayout->setContentsMargins(QMargins(8, 12, 8, 4)); |
1062 | |
1063 | QLabel * = new QLabel(m_newConnectionWidget); |
1064 | headerLabel->setText(i18n("<h1>KDE Remote Desktop Client</h1><br />Enter or select the address of the desktop you would like to connect to." )); |
1065 | |
1066 | QLabel * = new QLabel(m_newConnectionWidget); |
1067 | headerIconLabel->setPixmap(KIcon("krdc" ).pixmap(80)); |
1068 | |
1069 | QHBoxLayout * = new QHBoxLayout; |
1070 | headerLayout->addWidget(headerLabel, 1, Qt::AlignTop); |
1071 | headerLayout->addWidget(headerIconLabel); |
1072 | startLayout->addLayout(headerLayout); |
1073 | |
1074 | QSortFilterProxyModel *remoteDesktopsModelProxy = new QSortFilterProxyModel(this); |
1075 | remoteDesktopsModelProxy->setSourceModel(m_remoteDesktopsModel); |
1076 | remoteDesktopsModelProxy->setFilterCaseSensitivity(Qt::CaseInsensitive); |
1077 | remoteDesktopsModelProxy->setFilterRole(10002); |
1078 | |
1079 | { |
1080 | QHBoxLayout *connectLayout = new QHBoxLayout; |
1081 | |
1082 | QLabel *addressLabel = new QLabel(i18n("Connect to:" ), m_newConnectionWidget); |
1083 | m_protocolInput = new KComboBox(m_newConnectionWidget); |
1084 | m_addressInput = new KLineEdit(m_newConnectionWidget); |
1085 | m_addressInput->setClearButtonShown(true); |
1086 | m_addressInput->setClickMessage(i18n("Type here to connect to an address and filter the list." )); |
1087 | connect(m_addressInput, SIGNAL(textChanged(QString)), remoteDesktopsModelProxy, SLOT(setFilterFixedString(QString))); |
1088 | |
1089 | foreach(RemoteViewFactory *factory, m_remoteViewFactories) { |
1090 | m_protocolInput->addItem(factory->scheme()); |
1091 | } |
1092 | |
1093 | connect(m_addressInput, SIGNAL(returnPressed()), SLOT(newConnection())); |
1094 | m_addressInput->setToolTip(i18n("Type an IP or DNS Name here. Clear the line to get a list of connection methods." )); |
1095 | |
1096 | KPushButton *connectButton = new KPushButton(m_newConnectionWidget); |
1097 | connectButton->setToolTip(i18n("Goto Address" )); |
1098 | connectButton->setIcon(KIcon("go-jump-locationbar" )); |
1099 | connect(connectButton, SIGNAL(clicked()), SLOT(newConnection())); |
1100 | |
1101 | connectLayout->addWidget(addressLabel); |
1102 | connectLayout->addWidget(m_protocolInput); |
1103 | connectLayout->addWidget(m_addressInput, 1); |
1104 | connectLayout->addWidget(connectButton); |
1105 | connectLayout->setContentsMargins(QMargins(0, 6, 0, 10)); |
1106 | startLayout->addLayout(connectLayout); |
1107 | } |
1108 | |
1109 | { |
1110 | m_newConnectionTableView = new QTableView(m_newConnectionWidget); |
1111 | m_newConnectionTableView->setModel(remoteDesktopsModelProxy); |
1112 | |
1113 | // set up the view so it looks nice |
1114 | m_newConnectionTableView->setItemDelegate(new ConnectionDelegate(m_newConnectionTableView)); |
1115 | m_newConnectionTableView->setShowGrid(false); |
1116 | m_newConnectionTableView->setSelectionMode(QAbstractItemView::NoSelection); |
1117 | m_newConnectionTableView->verticalHeader()->hide(); |
1118 | m_newConnectionTableView->verticalHeader()->setDefaultSectionSize( |
1119 | m_newConnectionTableView->fontMetrics().height() + 3); |
1120 | m_newConnectionTableView->horizontalHeader()->setStretchLastSection(true); |
1121 | m_newConnectionTableView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents); |
1122 | m_newConnectionTableView->setAlternatingRowColors(true); |
1123 | // set up sorting and actions (double click open, right click custom menu) |
1124 | m_newConnectionTableView->setSortingEnabled(true); |
1125 | m_newConnectionTableView->sortByColumn(Settings::connectionListSortColumn(), Qt::SortOrder(Settings::connectionListSortOrder())); |
1126 | connect(m_newConnectionTableView->horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), |
1127 | SLOT(saveConnectionListSort(int,Qt::SortOrder))); |
1128 | connect(m_newConnectionTableView, SIGNAL(doubleClicked(QModelIndex)), |
1129 | SLOT(openFromRemoteDesktopsModel(QModelIndex))); |
1130 | m_newConnectionTableView->setContextMenuPolicy(Qt::CustomContextMenu); |
1131 | connect(m_newConnectionTableView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(showConnectionContextMenu(QPoint))); |
1132 | |
1133 | startLayout->addWidget(m_newConnectionTableView); |
1134 | } |
1135 | |
1136 | return m_newConnectionWidget; |
1137 | } |
1138 | |
1139 | void MainWindow::saveConnectionListSort(const int logicalindex, const Qt::SortOrder order) |
1140 | { |
1141 | Settings::setConnectionListSortColumn(logicalindex); |
1142 | Settings::setConnectionListSortOrder(order); |
1143 | Settings::self()->writeConfig(); |
1144 | } |
1145 | |
1146 | void MainWindow::newConnectionPage(bool clearInput) |
1147 | { |
1148 | const int indexOfNewConnectionWidget = m_tabWidget->indexOf(m_newConnectionWidget); |
1149 | if (indexOfNewConnectionWidget >= 0) |
1150 | m_tabWidget->setCurrentIndex(indexOfNewConnectionWidget); |
1151 | else { |
1152 | const int index = m_tabWidget->addTab(newConnectionWidget(), i18n("New Connection" )); |
1153 | m_tabWidget->setCurrentIndex(index); |
1154 | } |
1155 | if(clearInput) { |
1156 | m_addressInput->clear(); |
1157 | } else { |
1158 | m_addressInput->selectAll(); |
1159 | } |
1160 | m_addressInput->setFocus(); |
1161 | } |
1162 | |
1163 | QMap<QWidget *, RemoteView *> MainWindow::remoteViewList() const |
1164 | { |
1165 | return m_remoteViewMap; |
1166 | } |
1167 | |
1168 | QList<RemoteViewFactory *> MainWindow::remoteViewFactoriesList() const |
1169 | { |
1170 | return m_remoteViewFactories.values(); |
1171 | } |
1172 | |
1173 | RemoteView* MainWindow::currentRemoteView() const |
1174 | { |
1175 | if (m_currentRemoteView >= 0) { |
1176 | return m_remoteViewMap.value(m_tabWidget->widget(m_currentRemoteView)); |
1177 | } else { |
1178 | return 0; |
1179 | } |
1180 | } |
1181 | |
1182 | void MainWindow::createDockWidget() |
1183 | { |
1184 | QDockWidget *remoteDesktopsDockWidget = new QDockWidget(this); |
1185 | QWidget *remoteDesktopsDockLayoutWidget = new QWidget(remoteDesktopsDockWidget); |
1186 | QVBoxLayout *remoteDesktopsDockLayout = new QVBoxLayout(remoteDesktopsDockLayoutWidget); |
1187 | remoteDesktopsDockWidget->setObjectName("remoteDesktopsDockWidget" ); // required for saving position / state |
1188 | remoteDesktopsDockWidget->setWindowTitle(i18n("Remote Desktops" )); |
1189 | QFontMetrics fontMetrics(remoteDesktopsDockWidget->font()); |
1190 | remoteDesktopsDockWidget->setMinimumWidth(fontMetrics.width("vnc://192.168.100.100:6000" )); |
1191 | actionCollection()->addAction("remote_desktop_dockwidget" , |
1192 | remoteDesktopsDockWidget->toggleViewAction()); |
1193 | |
1194 | m_dockWidgetTableView = new QTableView(remoteDesktopsDockLayoutWidget); |
1195 | m_remoteDesktopsModel = new RemoteDesktopsModel(this); |
1196 | QSortFilterProxyModel *remoteDesktopsModelProxy = new QSortFilterProxyModel(this); |
1197 | remoteDesktopsModelProxy->setSourceModel(m_remoteDesktopsModel); |
1198 | remoteDesktopsModelProxy->setFilterCaseSensitivity(Qt::CaseInsensitive); |
1199 | remoteDesktopsModelProxy->setFilterRole(10002); |
1200 | m_dockWidgetTableView->setModel(remoteDesktopsModelProxy); |
1201 | |
1202 | m_dockWidgetTableView->setShowGrid(false); |
1203 | m_dockWidgetTableView->verticalHeader()->hide(); |
1204 | m_dockWidgetTableView->verticalHeader()->setDefaultSectionSize( |
1205 | m_dockWidgetTableView->fontMetrics().height() + 2); |
1206 | m_dockWidgetTableView->horizontalHeader()->hide(); |
1207 | m_dockWidgetTableView->horizontalHeader()->setStretchLastSection(true); |
1208 | // hide all columns, then show the one we want |
1209 | for (int i=0; i < remoteDesktopsModelProxy->columnCount(); i++) { |
1210 | m_dockWidgetTableView->hideColumn(i); |
1211 | } |
1212 | m_dockWidgetTableView->showColumn(RemoteDesktopsModel::Title); |
1213 | m_dockWidgetTableView->sortByColumn(RemoteDesktopsModel::Title, Qt::AscendingOrder); |
1214 | |
1215 | connect(m_dockWidgetTableView, SIGNAL(doubleClicked(QModelIndex)), |
1216 | SLOT(openFromRemoteDesktopsModel(QModelIndex))); |
1217 | |
1218 | KLineEdit *filterLineEdit = new KLineEdit(remoteDesktopsDockLayoutWidget); |
1219 | filterLineEdit->setClickMessage(i18n("Filter" )); |
1220 | filterLineEdit->setClearButtonShown(true); |
1221 | connect(filterLineEdit, SIGNAL(textChanged(QString)), remoteDesktopsModelProxy, SLOT(setFilterFixedString(QString))); |
1222 | remoteDesktopsDockLayout->addWidget(filterLineEdit); |
1223 | remoteDesktopsDockLayout->addWidget(m_dockWidgetTableView); |
1224 | remoteDesktopsDockWidget->setWidget(remoteDesktopsDockLayoutWidget); |
1225 | addDockWidget(Qt::LeftDockWidgetArea, remoteDesktopsDockWidget); |
1226 | } |
1227 | |
1228 | #include "mainwindow.moc" |
1229 | |