]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphinmainwindow.cpp
* respect the --select startup option
[dolphin.git] / src / dolphinmainwindow.cpp
1 /***************************************************************************
2 * Copyright (C) 2006 by Peter Penz <peter.penz@gmx.at> *
3 * Copyright (C) 2006 by Stefan Monov <logixoul@gmail.com> *
4 * Copyright (C) 2006 by Cvetoslav Ludmiloff <ludmiloff@gmail.com> *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20 ***************************************************************************/
21
22 #include "dolphinmainwindow.h"
23 #include "dolphinviewactionhandler.h"
24 #include "dolphinremoteencoding.h"
25
26 #include <config-nepomuk.h>
27 #ifdef HAVE_NEPOMUK
28 #include "search/dolphinsearchoptionsconfigurator.h"
29 #endif
30
31 #include "dolphinapplication.h"
32 #include "dolphinnewmenu.h"
33 #include "search/dolphinsearchbox.h"
34 #include "search/dolphinsearchoptionsconfigurator.h"
35 #include "settings/dolphinsettings.h"
36 #include "settings/dolphinsettingsdialog.h"
37 #include "dolphinviewcontainer.h"
38 #include "panels/folders/folderspanel.h"
39 #include "panels/places/placespanel.h"
40 #include "panels/information/informationpanel.h"
41 #include "mainwindowadaptor.h"
42 #include "statusbar/dolphinstatusbar.h"
43 #include "viewproperties.h"
44
45 #ifndef Q_OS_WIN
46 #include "panels/terminal/terminalpanel.h"
47 #endif
48
49 #include "dolphin_generalsettings.h"
50 #include "dolphin_iconsmodesettings.h"
51 #include "draganddrophelper.h"
52
53 #include <kaction.h>
54 #include <kactioncollection.h>
55 #include <kconfig.h>
56 #include <kdesktopfile.h>
57 #include <kdeversion.h>
58 #include <kfiledialog.h>
59 #include <kfileplacesmodel.h>
60 #include <kglobal.h>
61 #include <klineedit.h>
62 #include <ktoolbar.h>
63 #include <kicon.h>
64 #include <kiconloader.h>
65 #include <kio/netaccess.h>
66 #include <kinputdialog.h>
67 #include <klocale.h>
68 #include <kprotocolmanager.h>
69 #include <kmenu.h>
70 #include <kmenubar.h>
71 #include <kmessagebox.h>
72 #include <kfileitemlistproperties.h>
73 #include <konqmimedata.h>
74 #include <kprotocolinfo.h>
75 #include <krun.h>
76 #include <kshell.h>
77 #include <kstandarddirs.h>
78 #include <kstatusbar.h>
79 #include <kstandardaction.h>
80 #include <ktabbar.h>
81 #include <ktoggleaction.h>
82 #include <kurlnavigator.h>
83 #include <kurl.h>
84 #include <kurlcombobox.h>
85 #include <ktoolinvocation.h>
86
87 #include <QDBusMessage>
88 #include <QKeyEvent>
89 #include <QClipboard>
90 #include <QSplitter>
91 #include <QDockWidget>
92 #include <kacceleratormanager.h>
93
94 /*
95 * Remembers the tab configuration if a tab has been closed.
96 * Each closed tab can be restored by the menu
97 * "Go -> Recently Closed Tabs".
98 */
99 struct ClosedTab
100 {
101 KUrl primaryUrl;
102 KUrl secondaryUrl;
103 bool isSplit;
104 };
105 Q_DECLARE_METATYPE(ClosedTab)
106
107 DolphinMainWindow::DolphinMainWindow(int id) :
108 KXmlGuiWindow(0),
109 m_newMenu(0),
110 m_showMenuBar(0),
111 m_tabBar(0),
112 m_activeViewContainer(0),
113 m_centralWidgetLayout(0),
114 m_searchBox(0),
115 #ifdef HAVE_NEPOMUK
116 m_searchOptionsConfigurator(0),
117 #endif
118 m_id(id),
119 m_tabIndex(0),
120 m_viewTab(),
121 m_actionHandler(0),
122 m_remoteEncoding(0),
123 m_settingsDialog(0)
124 {
125 setObjectName("Dolphin#");
126
127 m_viewTab.append(ViewTab());
128
129 new MainWindowAdaptor(this);
130 QDBusConnection::sessionBus().registerObject(QString("/dolphin/MainWindow%1").arg(m_id), this);
131
132 KIO::FileUndoManager* undoManager = KIO::FileUndoManager::self();
133 undoManager->setUiInterface(new UndoUiInterface());
134
135 connect(undoManager, SIGNAL(undoAvailable(bool)),
136 this, SLOT(slotUndoAvailable(bool)));
137 connect(undoManager, SIGNAL(undoTextChanged(const QString&)),
138 this, SLOT(slotUndoTextChanged(const QString&)));
139 connect(undoManager, SIGNAL(jobRecordingStarted(CommandType)),
140 this, SLOT(clearStatusBar()));
141 connect(undoManager, SIGNAL(jobRecordingFinished(CommandType)),
142 this, SLOT(showCommand(CommandType)));
143 connect(DolphinSettings::instance().placesModel(), SIGNAL(errorMessage(const QString&)),
144 this, SLOT(showErrorMessage(const QString&)));
145 connect(&DragAndDropHelper::instance(), SIGNAL(errorMessage(const QString&)),
146 this, SLOT(showErrorMessage(const QString&)));
147 }
148
149 DolphinMainWindow::~DolphinMainWindow()
150 {
151 DolphinApplication::app()->removeMainWindow(this);
152 }
153
154 void DolphinMainWindow::openDirectories(const QList<KUrl>& dirs)
155 {
156 if (dirs.isEmpty()) {
157 return;
158 }
159
160 const int oldOpenTabsCount = m_viewTab.count();
161
162 const GeneralSettings* generalSettings = DolphinSettings::instance().generalSettings();
163 const bool hasSplitView = generalSettings->splitView();
164
165 // Open each directory inside a new tab. If the "split view" option has been enabled,
166 // always show two directories within one tab.
167 QList<KUrl>::const_iterator it = dirs.begin();
168 while (it != dirs.end()) {
169 openNewTab(*it);
170 ++it;
171
172 if (hasSplitView && (it != dirs.end())) {
173 const int tabIndex = m_viewTab.count() - 1;
174 m_viewTab[tabIndex].secondaryView->setUrl(*it);
175 ++it;
176 }
177 }
178
179 // remove the previously opened tabs
180 for (int i = 0; i < oldOpenTabsCount; ++i) {
181 closeTab(0);
182 }
183 }
184
185 void DolphinMainWindow::openFiles(const QList<KUrl>& files)
186 {
187 // Get all distinct directories from 'files' and open a tab
188 // for each directory. If the "split view" option is enabled, two
189 // directories are shown inside one tab (see openDirectories()).
190 QList<KUrl> dirs;
191 foreach (const KUrl& url, files) {
192 const KUrl dir(url.directory());
193 if (!dirs.contains(dir)) {
194 dirs.append(dir);
195 }
196 }
197
198 openDirectories(dirs);
199
200 // Select the files. Although the files can be split between several
201 // tabs, there is no need to split 'files' accordingly, as
202 // the DolphinView will just ignore invalid selections.
203 const int tabCount = m_viewTab.count();
204 for (int i = 0; i < tabCount; ++i) {
205 m_viewTab[i].primaryView->view()->markUrlsAsSelected(files);
206 if (m_viewTab[i].secondaryView != 0) {
207 m_viewTab[i].secondaryView->view()->markUrlsAsSelected(files);
208 }
209 }
210 }
211
212 void DolphinMainWindow::toggleViews()
213 {
214 if (m_viewTab[m_tabIndex].primaryView == 0) {
215 return;
216 }
217
218 // move secondary view from the last position of the splitter
219 // to the first position
220 m_viewTab[m_tabIndex].splitter->insertWidget(0, m_viewTab[m_tabIndex].secondaryView);
221
222 DolphinViewContainer* container = m_viewTab[m_tabIndex].primaryView;
223 m_viewTab[m_tabIndex].primaryView = m_viewTab[m_tabIndex].secondaryView;
224 m_viewTab[m_tabIndex].secondaryView = container;
225 }
226
227 void DolphinMainWindow::showCommand(CommandType command)
228 {
229 DolphinStatusBar* statusBar = m_activeViewContainer->statusBar();
230 switch (command) {
231 case KIO::FileUndoManager::Copy:
232 statusBar->setMessage(i18nc("@info:status", "Successfully copied."),
233 DolphinStatusBar::OperationCompleted);
234 break;
235 case KIO::FileUndoManager::Move:
236 statusBar->setMessage(i18nc("@info:status", "Successfully moved."),
237 DolphinStatusBar::OperationCompleted);
238 break;
239 case KIO::FileUndoManager::Link:
240 statusBar->setMessage(i18nc("@info:status", "Successfully linked."),
241 DolphinStatusBar::OperationCompleted);
242 break;
243 case KIO::FileUndoManager::Trash:
244 statusBar->setMessage(i18nc("@info:status", "Successfully moved to trash."),
245 DolphinStatusBar::OperationCompleted);
246 break;
247 case KIO::FileUndoManager::Rename:
248 statusBar->setMessage(i18nc("@info:status", "Successfully renamed."),
249 DolphinStatusBar::OperationCompleted);
250 break;
251
252 case KIO::FileUndoManager::Mkdir:
253 statusBar->setMessage(i18nc("@info:status", "Created folder."),
254 DolphinStatusBar::OperationCompleted);
255 break;
256
257 default:
258 break;
259 }
260 }
261
262 void DolphinMainWindow::refreshViews()
263 {
264 Q_ASSERT(m_viewTab[m_tabIndex].primaryView != 0);
265
266 // remember the current active view, as because of
267 // the refreshing the active view might change to
268 // the secondary view
269 DolphinViewContainer* activeViewContainer = m_activeViewContainer;
270
271 const int tabCount = m_viewTab.count();
272 for (int i = 0; i < tabCount; ++i) {
273 m_viewTab[i].primaryView->refresh();
274 if (m_viewTab[i].secondaryView != 0) {
275 m_viewTab[i].secondaryView->refresh();
276 }
277 }
278
279 setActiveViewContainer(activeViewContainer);
280 }
281
282 void DolphinMainWindow::pasteIntoFolder()
283 {
284 m_activeViewContainer->view()->pasteIntoFolder();
285 }
286
287 void DolphinMainWindow::changeUrl(const KUrl& url)
288 {
289 if (!KProtocolManager::supportsListing(url)) {
290 // The URL navigator only checks for validity, not
291 // if the URL can be listed. An error message is
292 // shown due to DolphinViewContainer::restoreView().
293 return;
294 }
295
296 DolphinViewContainer* view = activeViewContainer();
297 if (view != 0) {
298 view->setUrl(url);
299 updateEditActions();
300 updateViewActions();
301 updateGoActions();
302 setUrlAsCaption(url);
303 if (m_viewTab.count() > 1) {
304 m_tabBar->setTabText(m_tabIndex, squeezedText(tabName(m_activeViewContainer->url())));
305 }
306 const QString iconName = KMimeType::iconNameForUrl(url);
307 m_tabBar->setTabIcon(m_tabIndex, KIcon(iconName));
308 emit urlChanged(url);
309 }
310 }
311
312 void DolphinMainWindow::slotEditableStateChanged(bool editable)
313 {
314 KToggleAction* editableLocationAction =
315 static_cast<KToggleAction*>(actionCollection()->action("editable_location"));
316 editableLocationAction->setChecked(editable);
317 }
318
319 void DolphinMainWindow::slotSelectionChanged(const KFileItemList& selection)
320 {
321 updateEditActions();
322
323 Q_ASSERT(m_viewTab[m_tabIndex].primaryView != 0);
324 int selectedUrlsCount = m_viewTab[m_tabIndex].primaryView->view()->selectedItemsCount();
325 if (m_viewTab[m_tabIndex].secondaryView != 0) {
326 selectedUrlsCount += m_viewTab[m_tabIndex].secondaryView->view()->selectedItemsCount();
327 }
328
329 QAction* compareFilesAction = actionCollection()->action("compare_files");
330 if (selectedUrlsCount == 2) {
331 compareFilesAction->setEnabled(isKompareInstalled());
332 } else {
333 compareFilesAction->setEnabled(false);
334 }
335
336 emit selectionChanged(selection);
337 }
338
339 void DolphinMainWindow::slotWheelMoved(int wheelDelta)
340 {
341 if (wheelDelta > 0) {
342 activatePrevTab();
343 } else {
344 activateNextTab();
345 }
346 }
347
348 void DolphinMainWindow::slotRequestItemInfo(const KFileItem& item)
349 {
350 emit requestItemInfo(item);
351 }
352
353 void DolphinMainWindow::updateHistory()
354 {
355 const KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator();
356 const int index = urlNavigator->historyIndex();
357
358 QAction* backAction = actionCollection()->action("go_back");
359 backAction->setToolTip(i18nc("@info", "Go back"));
360 if (backAction != 0) {
361 backAction->setEnabled(index < urlNavigator->historySize() - 1);
362 }
363
364 QAction* forwardAction = actionCollection()->action("go_forward");
365 forwardAction->setToolTip(i18nc("@info", "Go forward"));
366 if (forwardAction != 0) {
367 forwardAction->setEnabled(index > 0);
368 }
369 }
370
371 void DolphinMainWindow::updateFilterBarAction(bool show)
372 {
373 QAction* showFilterBarAction = actionCollection()->action("show_filter_bar");
374 showFilterBarAction->setChecked(show);
375 }
376
377 void DolphinMainWindow::openNewMainWindow()
378 {
379 DolphinApplication::app()->createMainWindow()->show();
380 }
381
382 void DolphinMainWindow::openNewTab()
383 {
384 openNewTab(m_activeViewContainer->url());
385 m_tabBar->setCurrentIndex(m_viewTab.count() - 1);
386
387 KUrlNavigator* navigator = m_activeViewContainer->urlNavigator();
388 if (navigator->isUrlEditable()) {
389 // if a new tab is opened and the URL is editable, assure that
390 // the user can edit the URL without manually setting the focus
391 navigator->setFocus();
392 }
393 }
394
395 void DolphinMainWindow::openNewTab(const KUrl& url)
396 {
397 const KIcon icon = KIcon(KMimeType::iconNameForUrl(m_activeViewContainer->url()));
398 if (m_viewTab.count() == 1) {
399 // Only one view is open currently and hence no tab is shown at
400 // all. Before creating a tab for 'url', provide a tab for the current URL.
401 m_tabBar->addTab(icon, squeezedText(tabName(m_activeViewContainer->url())));
402 m_tabBar->blockSignals(false);
403 }
404
405 m_tabBar->addTab(icon, squeezedText(tabName(url)));
406
407 ViewTab viewTab;
408 viewTab.splitter = new QSplitter(this);
409 viewTab.splitter->setChildrenCollapsible(false);
410 viewTab.primaryView = new DolphinViewContainer(this, viewTab.splitter, url);
411 viewTab.primaryView->setActive(false);
412 connectViewSignals(viewTab.primaryView);
413 viewTab.primaryView->view()->reload();
414
415 m_viewTab.append(viewTab);
416
417 actionCollection()->action("close_tab")->setEnabled(true);
418
419 // provide a split view, if the startup settings are set this way
420 const GeneralSettings* generalSettings = DolphinSettings::instance().generalSettings();
421 if (generalSettings->splitView()) {
422 const int tabIndex = m_viewTab.count() - 1;
423 createSecondaryView(tabIndex);
424 m_viewTab[tabIndex].secondaryView->setActive(true);
425 m_viewTab[tabIndex].isPrimaryViewActive = false;
426 }
427 }
428
429 void DolphinMainWindow::activateNextTab()
430 {
431 if ((m_viewTab.count() == 1) || (m_tabBar->count() < 2)) {
432 return;
433 }
434
435 const int tabIndex = (m_tabBar->currentIndex() + 1) % m_tabBar->count();
436 m_tabBar->setCurrentIndex(tabIndex);
437 }
438
439 void DolphinMainWindow::activatePrevTab()
440 {
441 if ((m_viewTab.count() == 1) || (m_tabBar->count() < 2)) {
442 return;
443 }
444
445 int tabIndex = m_tabBar->currentIndex() - 1;
446 if (tabIndex == -1) {
447 tabIndex = m_tabBar->count() - 1;
448 }
449 m_tabBar->setCurrentIndex(tabIndex);
450 }
451
452 void DolphinMainWindow::openInNewTab()
453 {
454 const KFileItemList list = m_activeViewContainer->view()->selectedItems();
455 if ((list.count() == 1) && list[0].isDir()) {
456 openNewTab(m_activeViewContainer->view()->selectedUrls()[0]);
457 }
458 }
459
460 void DolphinMainWindow::openInNewWindow()
461 {
462 const KFileItemList list = m_activeViewContainer->view()->selectedItems();
463 if ((list.count() == 1) && list[0].isDir()) {
464 DolphinMainWindow* window = DolphinApplication::app()->createMainWindow();
465 window->changeUrl(m_activeViewContainer->view()->selectedUrls()[0]);
466 window->show();
467 }
468 }
469
470 void DolphinMainWindow::toggleActiveView()
471 {
472 if (m_viewTab[m_tabIndex].secondaryView == 0) {
473 // only one view is available
474 return;
475 }
476
477 Q_ASSERT(m_activeViewContainer != 0);
478 Q_ASSERT(m_viewTab[m_tabIndex].primaryView != 0);
479
480 DolphinViewContainer* left = m_viewTab[m_tabIndex].primaryView;
481 DolphinViewContainer* right = m_viewTab[m_tabIndex].secondaryView;
482 setActiveViewContainer(m_activeViewContainer == right ? left : right);
483 }
484
485 void DolphinMainWindow::closeEvent(QCloseEvent* event)
486 {
487 DolphinSettings& settings = DolphinSettings::instance();
488 GeneralSettings* generalSettings = settings.generalSettings();
489
490 // Find out if Dolphin is closed directly by the user or
491 // by the session manager because the session is closed
492 bool closedByUser = true;
493 DolphinApplication *application = qobject_cast<DolphinApplication*>(qApp);
494 if (application && application->sessionSaving()) {
495 closedByUser = false;
496 }
497
498 if ((m_viewTab.count() > 1) && generalSettings->confirmClosingMultipleTabs() && closedByUser) {
499 // Ask the user if he really wants to quit and close all tabs.
500 // Open a confirmation dialog with 3 buttons:
501 // KDialog::Yes -> Quit
502 // KDialog::No -> Close only the current tab
503 // KDialog::Cancel -> do nothing
504 KDialog *dialog = new KDialog(this, Qt::Dialog);
505 dialog->setCaption(i18nc("@title:window", "Confirmation"));
506 dialog->setButtons(KDialog::Yes | KDialog::No | KDialog::Cancel);
507 dialog->setModal(true);
508 dialog->showButtonSeparator(true);
509 dialog->setButtonGuiItem(KDialog::Yes, KStandardGuiItem::quit());
510 dialog->setButtonGuiItem(KDialog::No, KGuiItem(i18n("C&lose Current Tab"), KIcon("tab-close")));
511 dialog->setButtonGuiItem(KDialog::Cancel, KStandardGuiItem::cancel());
512 dialog->setDefaultButton(KDialog::Yes);
513
514 bool doNotAskAgainCheckboxResult = false;
515
516 const int result = KMessageBox::createKMessageBox(dialog,
517 QMessageBox::Warning,
518 i18n("You have multiple tabs open in this window, are you sure you want to quit?"),
519 QStringList(),
520 i18n("Do not ask again"),
521 &doNotAskAgainCheckboxResult,
522 KMessageBox::Notify);
523
524 if (doNotAskAgainCheckboxResult) {
525 generalSettings->setConfirmClosingMultipleTabs(false);
526 }
527
528 switch (result) {
529 case KDialog::Yes:
530 // Quit
531 break;
532 case KDialog::No:
533 // Close only the current tab
534 closeTab();
535 default:
536 event->ignore();
537 return;
538 }
539 }
540
541 generalSettings->setFirstRun(false);
542
543 settings.save();
544
545 KXmlGuiWindow::closeEvent(event);
546 }
547
548 void DolphinMainWindow::saveProperties(KConfigGroup& group)
549 {
550 const int tabCount = m_viewTab.count();
551 group.writeEntry("Tab Count", tabCount);
552 group.writeEntry("Active Tab Index", m_tabBar->currentIndex());
553
554 for (int i = 0; i < tabCount; ++i) {
555 const DolphinViewContainer* cont = m_viewTab[i].primaryView;
556 group.writeEntry(tabProperty("Primary URL", i), cont->url().url());
557 group.writeEntry(tabProperty("Primary Editable", i), cont->isUrlEditable());
558
559 cont = m_viewTab[i].secondaryView;
560 if (cont != 0) {
561 group.writeEntry(tabProperty("Secondary URL", i), cont->url().url());
562 group.writeEntry(tabProperty("Secondary Editable", i), cont->isUrlEditable());
563 }
564 }
565 }
566
567 void DolphinMainWindow::readProperties(const KConfigGroup& group)
568 {
569 const int tabCount = group.readEntry("Tab Count", 1);
570 for (int i = 0; i < tabCount; ++i) {
571 DolphinViewContainer* cont = m_viewTab[i].primaryView;
572
573 cont->setUrl(group.readEntry(tabProperty("Primary URL", i)));
574 const bool editable = group.readEntry(tabProperty("Primary Editable", i), false);
575 cont->urlNavigator()->setUrlEditable(editable);
576
577 cont = m_viewTab[i].secondaryView;
578 const QString secondaryUrl = group.readEntry(tabProperty("Secondary URL", i));
579 if (!secondaryUrl.isEmpty()) {
580 if (cont == 0) {
581 // a secondary view should be shown, but no one is available
582 // currently -> create a new view
583 toggleSplitView();
584 cont = m_viewTab[i].secondaryView;
585 Q_ASSERT(cont != 0);
586 }
587
588 cont->setUrl(secondaryUrl);
589 const bool editable = group.readEntry(tabProperty("Secondary Editable", i), false);
590 cont->urlNavigator()->setUrlEditable(editable);
591 } else if (cont != 0) {
592 // no secondary view should be shown, but the default setting shows
593 // one already -> close the view
594 toggleSplitView();
595 }
596
597 // openNewTab() needs to be called only tabCount - 1 times
598 if (i != tabCount - 1) {
599 openNewTab();
600 }
601 }
602
603 const int index = group.readEntry("Active Tab Index", 0);
604 m_tabBar->setCurrentIndex(index);
605 }
606
607 void DolphinMainWindow::updateNewMenu()
608 {
609 m_newMenu->setViewShowsHiddenFiles(activeViewContainer()->view()->showHiddenFiles());
610 m_newMenu->slotCheckUpToDate();
611 m_newMenu->setPopupFiles(activeViewContainer()->url());
612 }
613
614 void DolphinMainWindow::createDirectory()
615 {
616 m_newMenu->setViewShowsHiddenFiles(activeViewContainer()->view()->showHiddenFiles());
617 m_newMenu->setPopupFiles(activeViewContainer()->url());
618 m_newMenu->createDirectory();
619 }
620
621 void DolphinMainWindow::quit()
622 {
623 close();
624 }
625
626 void DolphinMainWindow::showErrorMessage(const QString& message)
627 {
628 if (!message.isEmpty()) {
629 DolphinStatusBar* statusBar = m_activeViewContainer->statusBar();
630 statusBar->setMessage(message, DolphinStatusBar::Error);
631 }
632 }
633
634 void DolphinMainWindow::slotUndoAvailable(bool available)
635 {
636 QAction* undoAction = actionCollection()->action(KStandardAction::name(KStandardAction::Undo));
637 if (undoAction != 0) {
638 undoAction->setEnabled(available);
639 }
640 }
641
642 void DolphinMainWindow::restoreClosedTab(QAction* action)
643 {
644 if (action->data().toBool()) {
645 // clear all actions except the "Empty Recently Closed Tabs"
646 // action and the separator
647 QList<QAction*> actions = m_recentTabsMenu->menu()->actions();
648 const int count = actions.size();
649 for (int i = 2; i < count; ++i) {
650 m_recentTabsMenu->menu()->removeAction(actions.at(i));
651 }
652 } else {
653 const ClosedTab closedTab = action->data().value<ClosedTab>();
654 openNewTab(closedTab.primaryUrl);
655 m_tabBar->setCurrentIndex(m_viewTab.count() - 1);
656
657 if (closedTab.isSplit) {
658 // create secondary view
659 toggleSplitView();
660 m_viewTab[m_tabIndex].secondaryView->setUrl(closedTab.secondaryUrl);
661 }
662
663 m_recentTabsMenu->removeAction(action);
664 }
665
666 if (m_recentTabsMenu->menu()->actions().count() == 2) {
667 m_recentTabsMenu->setEnabled(false);
668 }
669 }
670
671 void DolphinMainWindow::slotUndoTextChanged(const QString& text)
672 {
673 QAction* undoAction = actionCollection()->action(KStandardAction::name(KStandardAction::Undo));
674 if (undoAction != 0) {
675 undoAction->setText(text);
676 }
677 }
678
679 void DolphinMainWindow::undo()
680 {
681 clearStatusBar();
682 KIO::FileUndoManager::self()->uiInterface()->setParentWidget(this);
683 KIO::FileUndoManager::self()->undo();
684 }
685
686 void DolphinMainWindow::cut()
687 {
688 m_activeViewContainer->view()->cutSelectedItems();
689 }
690
691 void DolphinMainWindow::copy()
692 {
693 m_activeViewContainer->view()->copySelectedItems();
694 }
695
696 void DolphinMainWindow::paste()
697 {
698 m_activeViewContainer->view()->paste();
699 }
700
701 void DolphinMainWindow::updatePasteAction()
702 {
703 QAction* pasteAction = actionCollection()->action(KStandardAction::name(KStandardAction::Paste));
704 QPair<bool, QString> pasteInfo = m_activeViewContainer->view()->pasteInfo();
705 pasteAction->setEnabled(pasteInfo.first);
706 pasteAction->setText(pasteInfo.second);
707 }
708
709 void DolphinMainWindow::selectAll()
710 {
711 clearStatusBar();
712
713 // if the URL navigator is editable and focused, select the whole
714 // URL instead of all items of the view
715
716 KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator();
717 QLineEdit* lineEdit = urlNavigator->editor()->lineEdit(); // krazy:exclude=qclasses
718 const bool selectUrl = urlNavigator->isUrlEditable() &&
719 lineEdit->hasFocus();
720 if (selectUrl) {
721 lineEdit->selectAll();
722 } else {
723 m_activeViewContainer->view()->selectAll();
724 }
725 }
726
727 void DolphinMainWindow::invertSelection()
728 {
729 clearStatusBar();
730 m_activeViewContainer->view()->invertSelection();
731 }
732
733 void DolphinMainWindow::toggleSplitView()
734 {
735 if (m_viewTab[m_tabIndex].secondaryView == 0) {
736 createSecondaryView(m_tabIndex);
737 setActiveViewContainer(m_viewTab[m_tabIndex].secondaryView);
738 } else if (m_activeViewContainer == m_viewTab[m_tabIndex].secondaryView) {
739 // remove secondary view
740 m_viewTab[m_tabIndex].secondaryView->close();
741 m_viewTab[m_tabIndex].secondaryView->deleteLater();
742 m_viewTab[m_tabIndex].secondaryView = 0;
743
744 setActiveViewContainer(m_viewTab[m_tabIndex].primaryView);
745 } else {
746 // The primary view is active and should be closed. Hence from a users point of view
747 // the content of the secondary view should be moved to the primary view.
748 // From an implementation point of view it is more efficient to close
749 // the primary view and exchange the internal pointers afterwards.
750
751 m_viewTab[m_tabIndex].primaryView->close();
752 m_viewTab[m_tabIndex].primaryView->deleteLater();
753 m_viewTab[m_tabIndex].primaryView = m_viewTab[m_tabIndex].secondaryView;
754 m_viewTab[m_tabIndex].secondaryView = 0;
755
756 setActiveViewContainer(m_viewTab[m_tabIndex].primaryView);
757 }
758
759 updateViewActions();
760 }
761
762 void DolphinMainWindow::reloadView()
763 {
764 clearStatusBar();
765 m_activeViewContainer->view()->reload();
766 }
767
768 void DolphinMainWindow::stopLoading()
769 {
770 }
771
772 void DolphinMainWindow::toggleFilterBarVisibility(bool show)
773 {
774 m_activeViewContainer->showFilterBar(show);
775 }
776
777 void DolphinMainWindow::toggleEditLocation()
778 {
779 clearStatusBar();
780
781 QAction* action = actionCollection()->action("editable_location");
782 KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator();
783 urlNavigator->setUrlEditable(action->isChecked());
784 }
785
786 void DolphinMainWindow::replaceLocation()
787 {
788 KUrlNavigator* navigator = m_activeViewContainer->urlNavigator();
789 navigator->setUrlEditable(true);
790 navigator->setFocus();
791
792 // select the whole text of the combo box editor
793 QLineEdit* lineEdit = navigator->editor()->lineEdit(); // krazy:exclude=qclasses
794 const QString text = lineEdit->text();
795 lineEdit->setSelection(0, text.length());
796 }
797
798 void DolphinMainWindow::goBack()
799 {
800 clearStatusBar();
801 m_activeViewContainer->urlNavigator()->goBack();
802 }
803
804 void DolphinMainWindow::goForward()
805 {
806 clearStatusBar();
807 m_activeViewContainer->urlNavigator()->goForward();
808 }
809
810 void DolphinMainWindow::goUp()
811 {
812 clearStatusBar();
813 m_activeViewContainer->urlNavigator()->goUp();
814 }
815
816 void DolphinMainWindow::goBack(Qt::MouseButtons buttons)
817 {
818 // The default case (left button pressed) is handled in goBack().
819 if (buttons == Qt::MidButton) {
820 KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigator();
821 openNewTab(urlNavigator->historyUrl(urlNavigator->historyIndex() + 1));
822 }
823 }
824
825 void DolphinMainWindow::goForward(Qt::MouseButtons buttons)
826 {
827 // The default case (left button pressed) is handled in goForward().
828 if (buttons == Qt::MidButton) {
829 KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigator();
830 openNewTab(urlNavigator->historyUrl(urlNavigator->historyIndex() - 1));
831 }
832 }
833
834 void DolphinMainWindow::goUp(Qt::MouseButtons buttons)
835 {
836 // The default case (left button pressed) is handled in goUp().
837 if (buttons == Qt::MidButton) {
838 openNewTab(activeViewContainer()->url().upUrl());
839 }
840 }
841
842 void DolphinMainWindow::goHome()
843 {
844 clearStatusBar();
845 m_activeViewContainer->urlNavigator()->goHome();
846 }
847
848 void DolphinMainWindow::compareFiles()
849 {
850 // The method is only invoked if exactly 2 files have
851 // been selected. The selected files may be:
852 // - both in the primary view
853 // - both in the secondary view
854 // - one in the primary view and the other in the secondary
855 // view
856 Q_ASSERT(m_viewTab[m_tabIndex].primaryView != 0);
857
858 KUrl urlA;
859 KUrl urlB;
860 KUrl::List urls = m_viewTab[m_tabIndex].primaryView->view()->selectedUrls();
861
862 switch (urls.count()) {
863 case 0: {
864 Q_ASSERT(m_viewTab[m_tabIndex].secondaryView != 0);
865 urls = m_viewTab[m_tabIndex].secondaryView->view()->selectedUrls();
866 Q_ASSERT(urls.count() == 2);
867 urlA = urls[0];
868 urlB = urls[1];
869 break;
870 }
871
872 case 1: {
873 urlA = urls[0];
874 Q_ASSERT(m_viewTab[m_tabIndex].secondaryView != 0);
875 urls = m_viewTab[m_tabIndex].secondaryView->view()->selectedUrls();
876 Q_ASSERT(urls.count() == 1);
877 urlB = urls[0];
878 break;
879 }
880
881 case 2: {
882 urlA = urls[0];
883 urlB = urls[1];
884 break;
885 }
886
887 default: {
888 // may not happen: compareFiles may only get invoked if 2
889 // files are selected
890 Q_ASSERT(false);
891 }
892 }
893
894 QString command("kompare -c \"");
895 command.append(urlA.pathOrUrl());
896 command.append("\" \"");
897 command.append(urlB.pathOrUrl());
898 command.append('\"');
899 KRun::runCommand(command, "Kompare", "kompare", this);
900 }
901
902 void DolphinMainWindow::toggleShowMenuBar()
903 {
904 const bool visible = menuBar()->isVisible();
905 menuBar()->setVisible(!visible);
906 }
907
908 void DolphinMainWindow::openTerminal()
909 {
910 QString dir(QDir::homePath());
911
912 // If the given directory is not local, it can still be the URL of an
913 // ioslave using UDS_LOCAL_PATH which to be converted first.
914 KUrl url = KIO::NetAccess::mostLocalUrl(m_activeViewContainer->url(), this);
915
916 //If the URL is local after the above conversion, set the directory.
917 if (url.isLocalFile()) {
918 dir = url.toLocalFile();
919 }
920
921 KToolInvocation::invokeTerminal(QString(), dir);
922 }
923
924 void DolphinMainWindow::editSettings()
925 {
926 if (m_settingsDialog == 0) {
927 const KUrl& url = activeViewContainer()->url();
928 m_settingsDialog = new DolphinSettingsDialog(url, this);
929 m_settingsDialog->setAttribute(Qt::WA_DeleteOnClose);
930 m_settingsDialog->show();
931 } else {
932 m_settingsDialog->raise();
933 }
934 }
935
936 void DolphinMainWindow::setActiveTab(int index)
937 {
938 Q_ASSERT(index >= 0);
939 Q_ASSERT(index < m_viewTab.count());
940 if (index == m_tabIndex) {
941 return;
942 }
943
944 // hide current tab content
945 ViewTab& hiddenTab = m_viewTab[m_tabIndex];
946 hiddenTab.isPrimaryViewActive = hiddenTab.primaryView->isActive();
947 hiddenTab.primaryView->setActive(false);
948 if (hiddenTab.secondaryView != 0) {
949 hiddenTab.secondaryView->setActive(false);
950 }
951 QSplitter* splitter = m_viewTab[m_tabIndex].splitter;
952 splitter->hide();
953 m_centralWidgetLayout->removeWidget(splitter);
954
955 // show active tab content
956 m_tabIndex = index;
957
958 ViewTab& viewTab = m_viewTab[index];
959 m_centralWidgetLayout->addWidget(viewTab.splitter, 1);
960 viewTab.primaryView->show();
961 if (viewTab.secondaryView != 0) {
962 viewTab.secondaryView->show();
963 }
964 viewTab.splitter->show();
965
966 setActiveViewContainer(viewTab.isPrimaryViewActive ? viewTab.primaryView :
967 viewTab.secondaryView);
968 }
969
970 void DolphinMainWindow::closeTab()
971 {
972 closeTab(m_tabBar->currentIndex());
973 }
974
975 void DolphinMainWindow::closeTab(int index)
976 {
977 Q_ASSERT(index >= 0);
978 Q_ASSERT(index < m_viewTab.count());
979 if (m_viewTab.count() == 1) {
980 // the last tab may never get closed
981 return;
982 }
983
984 if (index == m_tabIndex) {
985 // The tab that should be closed is the active tab. Activate the
986 // previous tab before closing the tab.
987 m_tabBar->setCurrentIndex((index > 0) ? index - 1 : 1);
988 }
989 rememberClosedTab(index);
990
991 // delete tab
992 m_viewTab[index].primaryView->deleteLater();
993 if (m_viewTab[index].secondaryView != 0) {
994 m_viewTab[index].secondaryView->deleteLater();
995 }
996 m_viewTab[index].splitter->deleteLater();
997 m_viewTab.erase(m_viewTab.begin() + index);
998
999 m_tabBar->blockSignals(true);
1000 m_tabBar->removeTab(index);
1001
1002 if (m_tabIndex > index) {
1003 m_tabIndex--;
1004 Q_ASSERT(m_tabIndex >= 0);
1005 }
1006
1007 // if only one tab is left, also remove the tab entry so that
1008 // closing the last tab is not possible
1009 if (m_viewTab.count() == 1) {
1010 m_tabBar->removeTab(0);
1011 actionCollection()->action("close_tab")->setEnabled(false);
1012 } else {
1013 m_tabBar->blockSignals(false);
1014 }
1015 }
1016
1017 void DolphinMainWindow::openTabContextMenu(int index, const QPoint& pos)
1018 {
1019 KMenu menu(this);
1020
1021 QAction* newTabAction = menu.addAction(KIcon("tab-new"), i18nc("@action:inmenu", "New Tab"));
1022 newTabAction->setShortcut(actionCollection()->action("new_tab")->shortcut());
1023
1024 QAction* closeOtherTabsAction = menu.addAction(KIcon("tab-close-other"), i18nc("@action:inmenu", "Close Other Tabs"));
1025
1026 QAction* closeTabAction = menu.addAction(KIcon("tab-close"), i18nc("@action:inmenu", "Close Tab"));
1027 closeTabAction->setShortcut(actionCollection()->action("close_tab")->shortcut());
1028 QAction* selectedAction = menu.exec(pos);
1029 if (selectedAction == newTabAction) {
1030 const ViewTab& tab = m_viewTab[index];
1031 Q_ASSERT(tab.primaryView != 0);
1032 const KUrl url = (tab.secondaryView != 0) && tab.secondaryView->isActive() ?
1033 tab.secondaryView->url() : tab.primaryView->url();
1034 openNewTab(url);
1035 m_tabBar->setCurrentIndex(m_viewTab.count() - 1);
1036 } else if (selectedAction == closeOtherTabsAction) {
1037 const int count = m_tabBar->count();
1038 for (int i = 0; i < index; ++i) {
1039 closeTab(0);
1040 }
1041 for (int i = index + 1; i < count; ++i) {
1042 closeTab(1);
1043 }
1044 } else if (selectedAction == closeTabAction) {
1045 closeTab(index);
1046 }
1047 }
1048
1049 void DolphinMainWindow::handlePlacesClick(const KUrl& url, Qt::MouseButtons buttons)
1050 {
1051 if (buttons & Qt::MidButton) {
1052 openNewTab(url);
1053 m_tabBar->setCurrentIndex(m_viewTab.count() - 1);
1054 } else {
1055 changeUrl(url);
1056 }
1057 }
1058
1059 void DolphinMainWindow::slotTestCanDecode(const QDragMoveEvent* event, bool& canDecode)
1060 {
1061 canDecode = KUrl::List::canDecode(event->mimeData());
1062 }
1063
1064 void DolphinMainWindow::searchItems()
1065 {
1066 #ifdef HAVE_NEPOMUK
1067 const KUrl nepomukSearchUrl = m_searchOptionsConfigurator->nepomukSearchUrl();
1068 m_activeViewContainer->setUrl(nepomukSearchUrl);
1069 #endif
1070 }
1071
1072 void DolphinMainWindow::slotTabMoved(int from, int to)
1073 {
1074 m_viewTab.move(from, to);
1075 m_tabIndex = m_tabBar->currentIndex();
1076 }
1077
1078 void DolphinMainWindow::showSearchOptions()
1079 {
1080 #ifdef HAVE_NEPOMUK
1081 m_searchOptionsConfigurator->show();
1082 #endif
1083 }
1084
1085 void DolphinMainWindow::init()
1086 {
1087 DolphinSettings& settings = DolphinSettings::instance();
1088
1089 // Check whether Dolphin runs the first time. If yes then
1090 // a proper default window size is given at the end of DolphinMainWindow::init().
1091 GeneralSettings* generalSettings = settings.generalSettings();
1092 const bool firstRun = generalSettings->firstRun();
1093 if (firstRun) {
1094 generalSettings->setViewPropsTimestamp(QDateTime::currentDateTime());
1095 }
1096
1097 setAcceptDrops(true);
1098
1099 m_viewTab[m_tabIndex].splitter = new QSplitter(this);
1100 m_viewTab[m_tabIndex].splitter->setChildrenCollapsible(false);
1101
1102 setupActions();
1103
1104 const KUrl& homeUrl = generalSettings->homeUrl();
1105 setUrlAsCaption(homeUrl);
1106 m_actionHandler = new DolphinViewActionHandler(actionCollection(), this);
1107 connect(m_actionHandler, SIGNAL(actionBeingHandled()), SLOT(clearStatusBar()));
1108 connect(m_actionHandler, SIGNAL(createDirectory()), SLOT(createDirectory()));
1109 ViewProperties props(homeUrl);
1110 m_viewTab[m_tabIndex].primaryView = new DolphinViewContainer(this,
1111 m_viewTab[m_tabIndex].splitter,
1112 homeUrl);
1113
1114 m_activeViewContainer = m_viewTab[m_tabIndex].primaryView;
1115 connectViewSignals(m_activeViewContainer);
1116 DolphinView* view = m_activeViewContainer->view();
1117 view->reload();
1118 m_activeViewContainer->show();
1119 m_actionHandler->setCurrentView(view);
1120
1121 m_remoteEncoding = new DolphinRemoteEncoding(this, m_actionHandler);
1122 connect(this, SIGNAL(urlChanged(const KUrl&)),
1123 m_remoteEncoding, SLOT(slotAboutToOpenUrl()));
1124
1125 #ifdef HAVE_NEPOMUK
1126 m_searchOptionsConfigurator = new DolphinSearchOptionsConfigurator(this);
1127 m_searchOptionsConfigurator->hide();
1128 connect(m_searchOptionsConfigurator, SIGNAL(searchOptionsChanged()),
1129 this, SLOT(searchItems()));
1130 connect(this, SIGNAL(urlChanged(KUrl)), m_searchOptionsConfigurator, SLOT(setDirectory(KUrl)));
1131 #endif
1132
1133 m_tabBar = new KTabBar(this);
1134 m_tabBar->setMovable(true);
1135 m_tabBar->setTabsClosable(true);
1136 connect(m_tabBar, SIGNAL(currentChanged(int)),
1137 this, SLOT(setActiveTab(int)));
1138 connect(m_tabBar, SIGNAL(tabCloseRequested(int)),
1139 this, SLOT(closeTab(int)));
1140 connect(m_tabBar, SIGNAL(contextMenu(int, const QPoint&)),
1141 this, SLOT(openTabContextMenu(int, const QPoint&)));
1142 connect(m_tabBar, SIGNAL(newTabRequest()),
1143 this, SLOT(openNewTab()));
1144 connect(m_tabBar, SIGNAL(testCanDecode(const QDragMoveEvent*, bool&)),
1145 this, SLOT(slotTestCanDecode(const QDragMoveEvent*, bool&)));
1146 connect(m_tabBar, SIGNAL(wheelDelta(int)),
1147 this, SLOT(slotWheelMoved(int)));
1148 connect(m_tabBar, SIGNAL(mouseMiddleClick(int)),
1149 this, SLOT(closeTab(int)));
1150 connect(m_tabBar, SIGNAL(tabMoved(int, int)),
1151 this, SLOT(slotTabMoved(int, int)));
1152
1153 m_tabBar->blockSignals(true); // signals get unblocked after at least 2 tabs are open
1154
1155 QWidget* centralWidget = new QWidget(this);
1156 m_centralWidgetLayout = new QVBoxLayout(centralWidget);
1157 m_centralWidgetLayout->setSpacing(0);
1158 m_centralWidgetLayout->setMargin(0);
1159 #ifdef HAVE_NEPOMUK
1160 m_centralWidgetLayout->addWidget(m_searchOptionsConfigurator);
1161 #endif
1162 m_centralWidgetLayout->addWidget(m_tabBar);
1163 m_centralWidgetLayout->addWidget(m_viewTab[m_tabIndex].splitter, 1);
1164
1165 setCentralWidget(centralWidget);
1166 setupDockWidgets();
1167 emit urlChanged(homeUrl);
1168
1169 setupGUI(Keys | Save | Create | ToolBar);
1170
1171 m_searchBox->setParent(toolBar("searchToolBar"));
1172 m_searchBox->show();
1173 connect(m_searchBox, SIGNAL(requestSearchOptions()),
1174 this, SLOT(showSearchOptions()));
1175 #ifdef HAVE_NEPOMUK
1176 connect(m_searchBox, SIGNAL(searchTextChanged(QString)),
1177 m_searchOptionsConfigurator, SLOT(setCustomSearchQuery(QString)));
1178 #endif
1179
1180 stateChanged("new_file");
1181
1182 QClipboard* clipboard = QApplication::clipboard();
1183 connect(clipboard, SIGNAL(dataChanged()),
1184 this, SLOT(updatePasteAction()));
1185 updatePasteAction();
1186 updateGoActions();
1187
1188 if (generalSettings->splitView()) {
1189 toggleSplitView();
1190 }
1191 updateViewActions();
1192
1193 QAction* showFilterBarAction = actionCollection()->action("show_filter_bar");
1194 showFilterBarAction->setChecked(generalSettings->filterBar());
1195
1196 if (firstRun) {
1197 // assure a proper default size if Dolphin runs the first time
1198 resize(750, 500);
1199 }
1200
1201 m_showMenuBar->setChecked(!menuBar()->isHidden()); // workaround for bug #171080
1202 }
1203
1204 void DolphinMainWindow::setActiveViewContainer(DolphinViewContainer* viewContainer)
1205 {
1206 Q_ASSERT(viewContainer != 0);
1207 Q_ASSERT((viewContainer == m_viewTab[m_tabIndex].primaryView) ||
1208 (viewContainer == m_viewTab[m_tabIndex].secondaryView));
1209 if (m_activeViewContainer == viewContainer) {
1210 return;
1211 }
1212
1213 m_activeViewContainer->setActive(false);
1214 m_activeViewContainer = viewContainer;
1215
1216 // Activating the view container might trigger a recursive setActiveViewContainer() call
1217 // inside DolphinMainWindow::toggleActiveView() when having a split view. Temporary
1218 // disconnect the activated() signal in this case:
1219 disconnect(m_activeViewContainer->view(), SIGNAL(activated()), this, SLOT(toggleActiveView()));
1220 m_activeViewContainer->setActive(true);
1221 connect(m_activeViewContainer->view(), SIGNAL(activated()), this, SLOT(toggleActiveView()));
1222
1223 m_actionHandler->setCurrentView(viewContainer->view());
1224
1225 updateHistory();
1226 updateEditActions();
1227 updateViewActions();
1228 updateGoActions();
1229
1230 const KUrl& url = m_activeViewContainer->url();
1231 setUrlAsCaption(url);
1232 if (m_viewTab.count() > 1 && m_viewTab[m_tabIndex].secondaryView != 0) {
1233 m_tabBar->setTabText(m_tabIndex, tabName(url));
1234 m_tabBar->setTabIcon(m_tabIndex, KIcon(KMimeType::iconNameForUrl(url)));
1235 }
1236
1237 emit urlChanged(url);
1238 }
1239
1240 void DolphinMainWindow::setupActions()
1241 {
1242 // setup 'File' menu
1243 m_newMenu = new DolphinNewMenu(this, this);
1244 KMenu* menu = m_newMenu->menu();
1245 menu->setTitle(i18nc("@title:menu Create new folder, file, link, etc.", "Create New"));
1246 menu->setIcon(KIcon("document-new"));
1247 connect(menu, SIGNAL(aboutToShow()),
1248 this, SLOT(updateNewMenu()));
1249
1250 KAction* newWindow = actionCollection()->addAction("new_window");
1251 newWindow->setIcon(KIcon("window-new"));
1252 newWindow->setText(i18nc("@action:inmenu File", "New &Window"));
1253 newWindow->setShortcut(Qt::CTRL | Qt::Key_N);
1254 connect(newWindow, SIGNAL(triggered()), this, SLOT(openNewMainWindow()));
1255
1256 KAction* newTab = actionCollection()->addAction("new_tab");
1257 newTab->setIcon(KIcon("tab-new"));
1258 newTab->setText(i18nc("@action:inmenu File", "New Tab"));
1259 newTab->setShortcut(KShortcut(Qt::CTRL | Qt::Key_T, Qt::CTRL | Qt::SHIFT | Qt::Key_N));
1260 connect(newTab, SIGNAL(triggered()), this, SLOT(openNewTab()));
1261
1262 KAction* closeTab = actionCollection()->addAction("close_tab");
1263 closeTab->setIcon(KIcon("tab-close"));
1264 closeTab->setText(i18nc("@action:inmenu File", "Close Tab"));
1265 closeTab->setShortcut(Qt::CTRL | Qt::Key_W);
1266 closeTab->setEnabled(false);
1267 connect(closeTab, SIGNAL(triggered()), this, SLOT(closeTab()));
1268
1269 KStandardAction::quit(this, SLOT(quit()), actionCollection());
1270
1271 // setup 'Edit' menu
1272 KStandardAction::undo(this,
1273 SLOT(undo()),
1274 actionCollection());
1275
1276 // need to remove shift+del from cut action, else the shortcut for deletejob
1277 // doesn't work
1278 KAction* cut = KStandardAction::cut(this, SLOT(cut()), actionCollection());
1279 KShortcut cutShortcut = cut->shortcut();
1280 cutShortcut.remove(Qt::SHIFT + Qt::Key_Delete, KShortcut::KeepEmpty);
1281 cut->setShortcut(cutShortcut);
1282 KStandardAction::copy(this, SLOT(copy()), actionCollection());
1283 KAction* paste = KStandardAction::paste(this, SLOT(paste()), actionCollection());
1284 // The text of the paste-action is modified dynamically by Dolphin
1285 // (e. g. to "Paste One Folder"). To prevent that the size of the toolbar changes
1286 // due to the long text, the text "Paste" is used:
1287 paste->setIconText(i18nc("@action:inmenu Edit", "Paste"));
1288
1289 KAction* selectAll = actionCollection()->addAction("select_all");
1290 selectAll->setText(i18nc("@action:inmenu Edit", "Select All"));
1291 selectAll->setShortcut(Qt::CTRL + Qt::Key_A);
1292 connect(selectAll, SIGNAL(triggered()), this, SLOT(selectAll()));
1293
1294 KAction* invertSelection = actionCollection()->addAction("invert_selection");
1295 invertSelection->setText(i18nc("@action:inmenu Edit", "Invert Selection"));
1296 invertSelection->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_A);
1297 connect(invertSelection, SIGNAL(triggered()), this, SLOT(invertSelection()));
1298
1299 // setup 'View' menu
1300 // (note that most of it is set up in DolphinViewActionHandler)
1301
1302 KAction* split = actionCollection()->addAction("split_view");
1303 split->setShortcut(Qt::Key_F3);
1304 updateSplitAction();
1305 connect(split, SIGNAL(triggered()), this, SLOT(toggleSplitView()));
1306
1307 KAction* reload = actionCollection()->addAction("reload");
1308 reload->setText(i18nc("@action:inmenu View", "Reload"));
1309 reload->setShortcut(Qt::Key_F5);
1310 reload->setIcon(KIcon("view-refresh"));
1311 connect(reload, SIGNAL(triggered()), this, SLOT(reloadView()));
1312
1313 KAction* stop = actionCollection()->addAction("stop");
1314 stop->setText(i18nc("@action:inmenu View", "Stop"));
1315 stop->setToolTip(i18nc("@info", "Stop loading"));
1316 stop->setIcon(KIcon("process-stop"));
1317 connect(stop, SIGNAL(triggered()), this, SLOT(stopLoading()));
1318
1319 KToggleAction* showFullLocation = actionCollection()->add<KToggleAction>("editable_location");
1320 showFullLocation->setText(i18nc("@action:inmenu Navigation Bar", "Editable Location"));
1321 showFullLocation->setShortcut(Qt::CTRL | Qt::Key_L);
1322 connect(showFullLocation, SIGNAL(triggered()), this, SLOT(toggleEditLocation()));
1323
1324 KAction* replaceLocation = actionCollection()->addAction("replace_location");
1325 replaceLocation->setText(i18nc("@action:inmenu Navigation Bar", "Replace Location"));
1326 replaceLocation->setShortcut(Qt::Key_F6);
1327 connect(replaceLocation, SIGNAL(triggered()), this, SLOT(replaceLocation()));
1328
1329 // setup 'Go' menu
1330 KAction* backAction = KStandardAction::back(this, SLOT(goBack()), actionCollection());
1331 connect(backAction, SIGNAL(triggered(Qt::MouseButtons, Qt::KeyboardModifiers)), this, SLOT(goBack(Qt::MouseButtons)));
1332 KShortcut backShortcut = backAction->shortcut();
1333 backShortcut.setAlternate(Qt::Key_Backspace);
1334 backAction->setShortcut(backShortcut);
1335
1336 m_recentTabsMenu = new KActionMenu(i18n("Recently Closed Tabs"), this);
1337 m_recentTabsMenu->setIcon(KIcon("edit-undo"));
1338 actionCollection()->addAction("closed_tabs", m_recentTabsMenu);
1339 connect(m_recentTabsMenu->menu(), SIGNAL(triggered(QAction *)),
1340 this, SLOT(restoreClosedTab(QAction *)));
1341
1342 QAction* action = new QAction("Empty Recently Closed Tabs", m_recentTabsMenu);
1343 action->setIcon(KIcon("edit-clear-list"));
1344 action->setData(QVariant::fromValue(true));
1345 m_recentTabsMenu->addAction(action);
1346 m_recentTabsMenu->addSeparator();
1347 m_recentTabsMenu->setEnabled(false);
1348
1349 KAction* forwardAction = KStandardAction::forward(this, SLOT(goForward()), actionCollection());
1350 connect(forwardAction, SIGNAL(triggered(Qt::MouseButtons, Qt::KeyboardModifiers)), this, SLOT(goForward(Qt::MouseButtons)));
1351
1352 KAction* upAction = KStandardAction::up(this, SLOT(goUp()), actionCollection());
1353 connect(upAction, SIGNAL(triggered(Qt::MouseButtons, Qt::KeyboardModifiers)), this, SLOT(goUp(Qt::MouseButtons)));
1354
1355 KStandardAction::home(this, SLOT(goHome()), actionCollection());
1356
1357 // setup 'Tools' menu
1358 KToggleAction* showSearchBar = actionCollection()->add<KToggleAction>("show_search_bar");
1359 showSearchBar->setText(i18nc("@action:inmenu Tools", "Show Search Bar"));
1360 showSearchBar->setShortcut(Qt::CTRL | Qt::Key_S);
1361 connect(showSearchBar, SIGNAL(triggered(bool)), this, SLOT(toggleFilterBarVisibility(bool)));
1362
1363 KToggleAction* showFilterBar = actionCollection()->add<KToggleAction>("show_filter_bar");
1364 showFilterBar->setText(i18nc("@action:inmenu Tools", "Show Filter Bar"));
1365 showFilterBar->setIcon(KIcon("view-filter"));
1366 showFilterBar->setShortcut(Qt::CTRL | Qt::Key_I);
1367 connect(showFilterBar, SIGNAL(triggered(bool)), this, SLOT(toggleFilterBarVisibility(bool)));
1368
1369 KAction* compareFiles = actionCollection()->addAction("compare_files");
1370 compareFiles->setText(i18nc("@action:inmenu Tools", "Compare Files"));
1371 compareFiles->setIcon(KIcon("kompare"));
1372 compareFiles->setEnabled(false);
1373 connect(compareFiles, SIGNAL(triggered()), this, SLOT(compareFiles()));
1374
1375 KAction* openTerminal = actionCollection()->addAction("open_terminal");
1376 openTerminal->setText(i18nc("@action:inmenu Tools", "Open Terminal"));
1377 openTerminal->setIcon(KIcon("utilities-terminal"));
1378 openTerminal->setShortcut(Qt::SHIFT | Qt::Key_F4);
1379 connect(openTerminal, SIGNAL(triggered()), this, SLOT(openTerminal()));
1380
1381 // setup 'Settings' menu
1382 m_showMenuBar = KStandardAction::showMenubar(this, SLOT(toggleShowMenuBar()), actionCollection());
1383 KStandardAction::preferences(this, SLOT(editSettings()), actionCollection());
1384
1385 // not in menu actions
1386 KAction* activateNextTab = actionCollection()->addAction("activate_next_tab");
1387 activateNextTab->setText(i18nc("@action:inmenu", "Activate Next Tab"));
1388 connect(activateNextTab, SIGNAL(triggered()), SLOT(activateNextTab()));
1389 activateNextTab->setShortcuts(QApplication::isRightToLeft() ? KStandardShortcut::tabPrev() :
1390 KStandardShortcut::tabNext());
1391
1392 KAction* activatePrevTab = actionCollection()->addAction("activate_prev_tab");
1393 activatePrevTab->setText(i18nc("@action:inmenu", "Activate Previous Tab"));
1394 connect(activatePrevTab, SIGNAL(triggered()), SLOT(activatePrevTab()));
1395 activatePrevTab->setShortcuts(QApplication::isRightToLeft() ? KStandardShortcut::tabNext() :
1396 KStandardShortcut::tabPrev());
1397
1398 // for context menu
1399 KAction* openInNewTab = actionCollection()->addAction("open_in_new_tab");
1400 openInNewTab->setText(i18nc("@action:inmenu", "Open in New Tab"));
1401 openInNewTab->setIcon(KIcon("tab-new"));
1402 connect(openInNewTab, SIGNAL(triggered()), this, SLOT(openInNewTab()));
1403
1404 KAction* openInNewWindow = actionCollection()->addAction("open_in_new_window");
1405 openInNewWindow->setText(i18nc("@action:inmenu", "Open in New Window"));
1406 openInNewWindow->setIcon(KIcon("window-new"));
1407 connect(openInNewWindow, SIGNAL(triggered()), this, SLOT(openInNewWindow()));
1408
1409 // 'Search' toolbar
1410 m_searchBox = new DolphinSearchBox(this);
1411 connect(m_searchBox, SIGNAL(search(QString)), this, SLOT(searchItems()));
1412
1413 KAction* search = new KAction(this);
1414 actionCollection()->addAction("search_bar", search);
1415 search->setText(i18nc("@action:inmenu", "Search Bar"));
1416 search->setDefaultWidget(m_searchBox);
1417 search->setShortcutConfigurable(false);
1418 }
1419
1420 void DolphinMainWindow::setupDockWidgets()
1421 {
1422 // setup "Information"
1423 QDockWidget* infoDock = new QDockWidget(i18nc("@title:window", "Information"));
1424 infoDock->setObjectName("infoDock");
1425 infoDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
1426 Panel* infoPanel = new InformationPanel(infoDock);
1427 connect(infoPanel, SIGNAL(urlActivated(KUrl)), this, SLOT(handleUrl(KUrl)));
1428 infoDock->setWidget(infoPanel);
1429
1430 QAction* infoAction = infoDock->toggleViewAction();
1431 infoAction->setText(i18nc("@title:window", "Information"));
1432 infoAction->setShortcut(Qt::Key_F11);
1433 infoAction->setIcon(KIcon("dialog-information"));
1434 actionCollection()->addAction("show_info_panel", infoDock->toggleViewAction());
1435
1436 addDockWidget(Qt::RightDockWidgetArea, infoDock);
1437 connect(this, SIGNAL(urlChanged(KUrl)),
1438 infoPanel, SLOT(setUrl(KUrl)));
1439 connect(this, SIGNAL(selectionChanged(KFileItemList)),
1440 infoPanel, SLOT(setSelection(KFileItemList)));
1441 connect(this, SIGNAL(requestItemInfo(KFileItem)),
1442 infoPanel, SLOT(requestDelayedItemInfo(KFileItem)));
1443
1444 // setup "Folders"
1445 QDockWidget* foldersDock = new QDockWidget(i18nc("@title:window", "Folders"));
1446 foldersDock->setObjectName("foldersDock");
1447 foldersDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
1448 FoldersPanel* foldersPanel = new FoldersPanel(foldersDock);
1449 foldersDock->setWidget(foldersPanel);
1450
1451 QAction* foldersAction = foldersDock->toggleViewAction();
1452 foldersAction->setText(i18nc("@title:window", "Folders"));
1453 foldersAction->setShortcut(Qt::Key_F7);
1454 foldersAction->setIcon(KIcon("folder"));
1455 actionCollection()->addAction("show_folders_panel", foldersDock->toggleViewAction());
1456
1457 addDockWidget(Qt::LeftDockWidgetArea, foldersDock);
1458 connect(this, SIGNAL(urlChanged(KUrl)),
1459 foldersPanel, SLOT(setUrl(KUrl)));
1460 connect(foldersPanel, SIGNAL(changeUrl(KUrl, Qt::MouseButtons)),
1461 this, SLOT(handlePlacesClick(KUrl, Qt::MouseButtons)));
1462
1463 // setup "Terminal"
1464 #ifndef Q_OS_WIN
1465 QDockWidget* terminalDock = new QDockWidget(i18nc("@title:window Shell terminal", "Terminal"));
1466 terminalDock->setObjectName("terminalDock");
1467 terminalDock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
1468 Panel* terminalPanel = new TerminalPanel(terminalDock);
1469 terminalDock->setWidget(terminalPanel);
1470
1471 connect(terminalPanel, SIGNAL(hideTerminalPanel()), terminalDock, SLOT(hide()));
1472
1473 QAction* terminalAction = terminalDock->toggleViewAction();
1474 terminalAction->setText(i18nc("@title:window Shell terminal", "Terminal"));
1475 terminalAction->setShortcut(Qt::Key_F4);
1476 terminalAction->setIcon(KIcon("utilities-terminal"));
1477 actionCollection()->addAction("show_terminal_panel", terminalDock->toggleViewAction());
1478
1479 addDockWidget(Qt::BottomDockWidgetArea, terminalDock);
1480 connect(this, SIGNAL(urlChanged(KUrl)),
1481 terminalPanel, SLOT(setUrl(KUrl)));
1482 #endif
1483
1484 const bool firstRun = DolphinSettings::instance().generalSettings()->firstRun();
1485 if (firstRun) {
1486 foldersDock->hide();
1487 #ifndef Q_OS_WIN
1488 terminalDock->hide();
1489 #endif
1490 }
1491
1492 QDockWidget* placesDock = new QDockWidget(i18nc("@title:window", "Places"));
1493 placesDock->setObjectName("placesDock");
1494 placesDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
1495
1496 PlacesPanel* placesPanel = new PlacesPanel(placesDock);
1497 placesDock->setWidget(placesPanel);
1498 placesPanel->setModel(DolphinSettings::instance().placesModel());
1499 placesPanel->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1500
1501 QAction* placesAction = placesDock->toggleViewAction();
1502 placesAction->setText(i18nc("@title:window", "Places"));
1503 placesAction->setShortcut(Qt::Key_F9);
1504 placesAction->setIcon(KIcon("bookmarks"));
1505 actionCollection()->addAction("show_places_panel", placesDock->toggleViewAction());
1506
1507 addDockWidget(Qt::LeftDockWidgetArea, placesDock);
1508 connect(placesPanel, SIGNAL(urlChanged(KUrl, Qt::MouseButtons)),
1509 this, SLOT(handlePlacesClick(KUrl, Qt::MouseButtons)));
1510 connect(this, SIGNAL(urlChanged(KUrl)),
1511 placesPanel, SLOT(setUrl(KUrl)));
1512 }
1513
1514 void DolphinMainWindow::updateEditActions()
1515 {
1516 const KFileItemList list = m_activeViewContainer->view()->selectedItems();
1517 if (list.isEmpty()) {
1518 stateChanged("has_no_selection");
1519 } else {
1520 stateChanged("has_selection");
1521
1522 KActionCollection* col = actionCollection();
1523 QAction* renameAction = col->action("rename");
1524 QAction* moveToTrashAction = col->action("move_to_trash");
1525 QAction* deleteAction = col->action("delete");
1526 QAction* cutAction = col->action(KStandardAction::name(KStandardAction::Cut));
1527 QAction* deleteWithTrashShortcut = col->action("delete_shortcut"); // see DolphinViewActionHandler
1528
1529 KFileItemListProperties capabilities(list);
1530 const bool enableMoveToTrash = capabilities.isLocal() && capabilities.supportsMoving();
1531
1532 renameAction->setEnabled(capabilities.supportsMoving());
1533 moveToTrashAction->setEnabled(enableMoveToTrash);
1534 deleteAction->setEnabled(capabilities.supportsDeleting());
1535 deleteWithTrashShortcut->setEnabled(capabilities.supportsDeleting() && !enableMoveToTrash);
1536 cutAction->setEnabled(capabilities.supportsMoving());
1537 }
1538 updatePasteAction();
1539 }
1540
1541 void DolphinMainWindow::updateViewActions()
1542 {
1543 m_actionHandler->updateViewActions();
1544
1545 QAction* showFilterBarAction = actionCollection()->action("show_filter_bar");
1546 showFilterBarAction->setChecked(m_activeViewContainer->isFilterBarVisible());
1547
1548 updateSplitAction();
1549
1550 QAction* editableLocactionAction = actionCollection()->action("editable_location");
1551 const KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator();
1552 editableLocactionAction->setChecked(urlNavigator->isUrlEditable());
1553 }
1554
1555 void DolphinMainWindow::updateGoActions()
1556 {
1557 QAction* goUpAction = actionCollection()->action(KStandardAction::name(KStandardAction::Up));
1558 const KUrl& currentUrl = m_activeViewContainer->url();
1559 goUpAction->setEnabled(currentUrl.upUrl() != currentUrl);
1560 }
1561
1562 void DolphinMainWindow::rememberClosedTab(int index)
1563 {
1564 KMenu* tabsMenu = m_recentTabsMenu->menu();
1565
1566 const QString primaryPath = m_viewTab[index].primaryView->url().path();
1567 const QString iconName = KMimeType::iconNameForUrl(primaryPath);
1568
1569 QAction* action = new QAction(squeezedText(primaryPath), tabsMenu);
1570
1571 ClosedTab closedTab;
1572 closedTab.primaryUrl = m_viewTab[index].primaryView->url();
1573
1574 if (m_viewTab[index].secondaryView != 0) {
1575 closedTab.secondaryUrl = m_viewTab[index].secondaryView->url();
1576 closedTab.isSplit = true;
1577 } else {
1578 closedTab.isSplit = false;
1579 }
1580
1581 action->setData(QVariant::fromValue(closedTab));
1582 action->setIcon(KIcon(iconName));
1583
1584 // add the closed tab menu entry after the separator and
1585 // "Empty Recently Closed Tabs" entry
1586 if (tabsMenu->actions().size() == 2) {
1587 tabsMenu->addAction(action);
1588 } else {
1589 tabsMenu->insertAction(tabsMenu->actions().at(2), action);
1590 }
1591
1592 // assure that only up to 8 closed tabs are shown in the menu
1593 if (tabsMenu->actions().size() > 8) {
1594 tabsMenu->removeAction(tabsMenu->actions().last());
1595 }
1596 actionCollection()->action("closed_tabs")->setEnabled(true);
1597 KAcceleratorManager::manage(tabsMenu);
1598 }
1599
1600 void DolphinMainWindow::clearStatusBar()
1601 {
1602 m_activeViewContainer->statusBar()->clear();
1603 }
1604
1605 void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container)
1606 {
1607 connect(container, SIGNAL(showFilterBarChanged(bool)),
1608 this, SLOT(updateFilterBarAction(bool)));
1609
1610 DolphinView* view = container->view();
1611 connect(view, SIGNAL(selectionChanged(KFileItemList)),
1612 this, SLOT(slotSelectionChanged(KFileItemList)));
1613 connect(view, SIGNAL(requestItemInfo(KFileItem)),
1614 this, SLOT(slotRequestItemInfo(KFileItem)));
1615 connect(view, SIGNAL(activated()),
1616 this, SLOT(toggleActiveView()));
1617 connect(view, SIGNAL(tabRequested(const KUrl&)),
1618 this, SLOT(openNewTab(const KUrl&)));
1619
1620 const KUrlNavigator* navigator = container->urlNavigator();
1621 connect(navigator, SIGNAL(urlChanged(const KUrl&)),
1622 this, SLOT(changeUrl(const KUrl&)));
1623 connect(navigator, SIGNAL(historyChanged()),
1624 this, SLOT(updateHistory()));
1625 connect(navigator, SIGNAL(editableStateChanged(bool)),
1626 this, SLOT(slotEditableStateChanged(bool)));
1627 }
1628
1629 void DolphinMainWindow::updateSplitAction()
1630 {
1631 QAction* splitAction = actionCollection()->action("split_view");
1632 if (m_viewTab[m_tabIndex].secondaryView != 0) {
1633 if (m_activeViewContainer == m_viewTab[m_tabIndex].secondaryView) {
1634 splitAction->setText(i18nc("@action:intoolbar Close right view", "Close"));
1635 splitAction->setToolTip(i18nc("@info", "Close right view"));
1636 splitAction->setIcon(KIcon("view-right-close"));
1637 } else {
1638 splitAction->setText(i18nc("@action:intoolbar Close left view", "Close"));
1639 splitAction->setToolTip(i18nc("@info", "Close left view"));
1640 splitAction->setIcon(KIcon("view-left-close"));
1641 }
1642 } else {
1643 splitAction->setText(i18nc("@action:intoolbar Split view", "Split"));
1644 splitAction->setToolTip(i18nc("@info", "Split view"));
1645 splitAction->setIcon(KIcon("view-right-new"));
1646 }
1647 }
1648
1649 QString DolphinMainWindow::tabName(const KUrl& url) const
1650 {
1651 QString name;
1652 if (url.equals(KUrl("file:///"))) {
1653 name = '/';
1654 } else {
1655 name = url.fileName();
1656 if (name.isEmpty()) {
1657 name = url.protocol();
1658 } else {
1659 // Make sure that a '&' inside the directory name is displayed correctly
1660 // and not misinterpreted as a keyboard shortcut in QTabBar::setTabText()
1661 name.replace('&', "&&");
1662 }
1663 }
1664 return name;
1665 }
1666
1667 bool DolphinMainWindow::isKompareInstalled() const
1668 {
1669 static bool initialized = false;
1670 static bool installed = false;
1671 if (!initialized) {
1672 // TODO: maybe replace this approach later by using a menu
1673 // plugin like kdiff3plugin.cpp
1674 installed = !KGlobal::dirs()->findExe("kompare").isEmpty();
1675 initialized = true;
1676 }
1677 return installed;
1678 }
1679
1680 void DolphinMainWindow::createSecondaryView(int tabIndex)
1681 {
1682 QSplitter* splitter = m_viewTab[tabIndex].splitter;
1683 const int newWidth = (m_viewTab[tabIndex].primaryView->width() - splitter->handleWidth()) / 2;
1684
1685 const DolphinView* view = m_viewTab[tabIndex].primaryView->view();
1686 m_viewTab[tabIndex].secondaryView = new DolphinViewContainer(this, 0, view->rootUrl());
1687 splitter->addWidget(m_viewTab[tabIndex].secondaryView);
1688 splitter->setSizes(QList<int>() << newWidth << newWidth);
1689 connectViewSignals(m_viewTab[tabIndex].secondaryView);
1690 m_viewTab[tabIndex].secondaryView->view()->reload();
1691 m_viewTab[tabIndex].secondaryView->setActive(false);
1692 m_viewTab[tabIndex].secondaryView->show();
1693 }
1694
1695 QString DolphinMainWindow::tabProperty(const QString& property, int tabIndex) const
1696 {
1697 return "Tab " + QString::number(tabIndex) + ' ' + property;
1698 }
1699
1700 void DolphinMainWindow::setUrlAsCaption(const KUrl& url)
1701 {
1702 QString caption;
1703 if (url.equals(KUrl("file:///"))) {
1704 caption = '/';
1705 } else {
1706 caption = url.fileName();
1707 if (caption.isEmpty()) {
1708 caption = url.protocol();
1709 }
1710 }
1711
1712 setCaption(caption);
1713 }
1714
1715 void DolphinMainWindow::handleUrl(const KUrl& url)
1716 {
1717 if (KProtocolManager::supportsListing(url)) {
1718 activeViewContainer()->setUrl(url);
1719 }
1720 else {
1721 new KRun(url, this);
1722 }
1723 }
1724
1725 QString DolphinMainWindow::squeezedText(const QString& text) const
1726 {
1727 const QFontMetrics fm = fontMetrics();
1728 return fm.elidedText(text, Qt::ElideMiddle, fm.maxWidth() * 10);
1729 }
1730
1731 DolphinMainWindow::UndoUiInterface::UndoUiInterface() :
1732 KIO::FileUndoManager::UiInterface()
1733 {
1734 }
1735
1736 DolphinMainWindow::UndoUiInterface::~UndoUiInterface()
1737 {
1738 }
1739
1740 void DolphinMainWindow::UndoUiInterface::jobError(KIO::Job* job)
1741 {
1742 DolphinMainWindow* mainWin= qobject_cast<DolphinMainWindow *>(parentWidget());
1743 if (mainWin) {
1744 DolphinStatusBar* statusBar = mainWin->activeViewContainer()->statusBar();
1745 statusBar->setMessage(job->errorString(), DolphinStatusBar::Error);
1746 } else {
1747 KIO::FileUndoManager::UiInterface::jobError(job);
1748 }
1749 }
1750
1751 #include "dolphinmainwindow.moc"