1 | /*************************************************************************** |
2 | * Copyright (C) 2006 by Peter Penz <peter.penz19@gmail.com> * |
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 | |
24 | #include "dolphinapplication.h" |
25 | #include "dolphindockwidget.h" |
26 | #include "dolphincontextmenu.h" |
27 | #include "dolphinnewfilemenu.h" |
28 | #include "dolphinrecenttabsmenu.h" |
29 | #include "dolphinviewcontainer.h" |
30 | #include "dolphintabpage.h" |
31 | #include "panels/folders/folderspanel.h" |
32 | #include "panels/places/placespanel.h" |
33 | #include "panels/information/informationpanel.h" |
34 | #include "settings/dolphinsettingsdialog.h" |
35 | #include "statusbar/dolphinstatusbar.h" |
36 | #include "views/dolphinviewactionhandler.h" |
37 | #include "views/dolphinremoteencoding.h" |
38 | #include "views/draganddrophelper.h" |
39 | #include "views/viewproperties.h" |
40 | #include "views/dolphinnewfilemenuobserver.h" |
41 | |
42 | #ifndef Q_OS_WIN |
43 | #include "panels/terminal/terminalpanel.h" |
44 | #endif |
45 | |
46 | #include "dolphin_generalsettings.h" |
47 | |
48 | #include <KAcceleratorManager> |
49 | #include <KAction> |
50 | #include <KActionCollection> |
51 | #include <KActionMenu> |
52 | #include <KConfig> |
53 | #include <KDesktopFile> |
54 | #include <kdeversion.h> |
55 | #include <kdualaction.h> |
56 | #include <KFileDialog> |
57 | #include <KGlobal> |
58 | #include <KLineEdit> |
59 | #include <KToolBar> |
60 | #include <KIcon> |
61 | #include <KIconLoader> |
62 | #include <KIO/NetAccess> |
63 | #include <KIO/JobUiDelegate> |
64 | #include <KInputDialog> |
65 | #include <KLocale> |
66 | #include <KProtocolManager> |
67 | #include <KMenu> |
68 | #include <KMenuBar> |
69 | #include <KMessageBox> |
70 | #include <KFileItemListProperties> |
71 | #include <konqmimedata.h> |
72 | #include <KProtocolInfo> |
73 | #include <KRun> |
74 | #include <KShell> |
75 | #include <KStandardDirs> |
76 | #include <kstatusbar.h> |
77 | #include <KStandardAction> |
78 | #include <ktabbar.h> |
79 | #include <KToggleAction> |
80 | #include <KUrlNavigator> |
81 | #include <KUrl> |
82 | #include <KUrlComboBox> |
83 | #include <KToolInvocation> |
84 | |
85 | #include <QDesktopWidget> |
86 | #include <QDBusMessage> |
87 | #include <QKeyEvent> |
88 | #include <QClipboard> |
89 | #include <QToolButton> |
90 | |
91 | namespace { |
92 | // Used for GeneralSettings::version() to determine whether |
93 | // an updated version of Dolphin is running. |
94 | const int CurrentDolphinVersion = 200; |
95 | }; |
96 | |
97 | DolphinMainWindow::DolphinMainWindow() : |
98 | KXmlGuiWindow(0), |
99 | m_newFileMenu(0), |
100 | m_tabBar(0), |
101 | m_activeViewContainer(0), |
102 | m_centralWidgetLayout(0), |
103 | m_tabIndex(-1), |
104 | m_viewTab(), |
105 | m_actionHandler(0), |
106 | m_remoteEncoding(0), |
107 | m_settingsDialog(), |
108 | m_controlButton(0), |
109 | m_updateToolBarTimer(0), |
110 | m_lastHandleUrlStatJob(0) |
111 | { |
112 | setObjectName("Dolphin#" ); |
113 | |
114 | connect(&DolphinNewFileMenuObserver::instance(), SIGNAL(errorMessage(QString)), |
115 | this, SLOT(showErrorMessage(QString))); |
116 | |
117 | KIO::FileUndoManager* undoManager = KIO::FileUndoManager::self(); |
118 | undoManager->setUiInterface(new UndoUiInterface()); |
119 | |
120 | connect(undoManager, SIGNAL(undoAvailable(bool)), |
121 | this, SLOT(slotUndoAvailable(bool))); |
122 | connect(undoManager, SIGNAL(undoTextChanged(QString)), |
123 | this, SLOT(slotUndoTextChanged(QString))); |
124 | connect(undoManager, SIGNAL(jobRecordingStarted(CommandType)), |
125 | this, SLOT(clearStatusBar())); |
126 | connect(undoManager, SIGNAL(jobRecordingFinished(CommandType)), |
127 | this, SLOT(showCommand(CommandType))); |
128 | |
129 | GeneralSettings* generalSettings = GeneralSettings::self(); |
130 | const bool firstRun = (generalSettings->version() < 200); |
131 | if (firstRun) { |
132 | generalSettings->setViewPropsTimestamp(QDateTime::currentDateTime()); |
133 | } |
134 | |
135 | setAcceptDrops(true); |
136 | |
137 | setupActions(); |
138 | |
139 | m_actionHandler = new DolphinViewActionHandler(actionCollection(), this); |
140 | connect(m_actionHandler, SIGNAL(actionBeingHandled()), SLOT(clearStatusBar())); |
141 | connect(m_actionHandler, SIGNAL(createDirectory()), SLOT(createDirectory())); |
142 | |
143 | m_remoteEncoding = new DolphinRemoteEncoding(this, m_actionHandler); |
144 | connect(this, SIGNAL(urlChanged(KUrl)), |
145 | m_remoteEncoding, SLOT(slotAboutToOpenUrl())); |
146 | |
147 | m_tabBar = new KTabBar(this); |
148 | m_tabBar->setMovable(true); |
149 | m_tabBar->setTabsClosable(true); |
150 | connect(m_tabBar, SIGNAL(currentChanged(int)), |
151 | this, SLOT(setActiveTab(int))); |
152 | connect(m_tabBar, SIGNAL(tabCloseRequested(int)), |
153 | this, SLOT(closeTab(int))); |
154 | connect(m_tabBar, SIGNAL(contextMenu(int,QPoint)), |
155 | this, SLOT(openTabContextMenu(int,QPoint))); |
156 | connect(m_tabBar, SIGNAL(newTabRequest()), |
157 | this, SLOT(openNewTab())); |
158 | connect(m_tabBar, SIGNAL(testCanDecode(const QDragMoveEvent*,bool&)), |
159 | this, SLOT(slotTestCanDecode(const QDragMoveEvent*,bool&))); |
160 | connect(m_tabBar, SIGNAL(mouseMiddleClick(int)), |
161 | this, SLOT(closeTab(int))); |
162 | connect(m_tabBar, SIGNAL(tabMoved(int,int)), |
163 | this, SLOT(slotTabMoved(int,int))); |
164 | connect(m_tabBar, SIGNAL(receivedDropEvent(int,QDropEvent*)), |
165 | this, SLOT(tabDropEvent(int,QDropEvent*))); |
166 | |
167 | m_tabBar->blockSignals(true); // signals get unblocked after at least 2 tabs are open |
168 | m_tabBar->hide(); |
169 | |
170 | QWidget* centralWidget = new QWidget(this); |
171 | m_centralWidgetLayout = new QVBoxLayout(centralWidget); |
172 | m_centralWidgetLayout->setSpacing(0); |
173 | m_centralWidgetLayout->setMargin(0); |
174 | m_centralWidgetLayout->addWidget(m_tabBar); |
175 | |
176 | setCentralWidget(centralWidget); |
177 | setupDockWidgets(); |
178 | |
179 | setupGUI(Keys | Save | Create | ToolBar); |
180 | stateChanged("new_file" ); |
181 | |
182 | QClipboard* clipboard = QApplication::clipboard(); |
183 | connect(clipboard, SIGNAL(dataChanged()), |
184 | this, SLOT(updatePasteAction())); |
185 | |
186 | QAction* showFilterBarAction = actionCollection()->action("show_filter_bar" ); |
187 | showFilterBarAction->setChecked(generalSettings->filterBar()); |
188 | |
189 | if (firstRun) { |
190 | menuBar()->setVisible(false); |
191 | // Assure a proper default size if Dolphin runs the first time |
192 | resize(750, 500); |
193 | } |
194 | |
195 | const bool = !menuBar()->isHidden(); |
196 | QAction* = actionCollection()->action(KStandardAction::name(KStandardAction::ShowMenubar)); |
197 | showMenuBarAction->setChecked(showMenu); // workaround for bug #171080 |
198 | if (!showMenu) { |
199 | createControlButton(); |
200 | } |
201 | } |
202 | |
203 | DolphinMainWindow::~DolphinMainWindow() |
204 | { |
205 | } |
206 | |
207 | void DolphinMainWindow::openDirectories(const QList<KUrl>& dirs) |
208 | { |
209 | const bool hasSplitView = GeneralSettings::splitView(); |
210 | |
211 | // Open each directory inside a new tab. If the "split view" option has been enabled, |
212 | // always show two directories within one tab. |
213 | QList<KUrl>::const_iterator it = dirs.constBegin(); |
214 | while (it != dirs.constEnd()) { |
215 | const KUrl& primaryUrl = *(it++); |
216 | if (hasSplitView && (it != dirs.constEnd())) { |
217 | const KUrl& secondaryUrl = *(it++); |
218 | openNewTab(primaryUrl, secondaryUrl); |
219 | } else { |
220 | openNewTab(primaryUrl); |
221 | } |
222 | } |
223 | } |
224 | |
225 | void DolphinMainWindow::openFiles(const QList<KUrl>& files) |
226 | { |
227 | if (files.isEmpty()) { |
228 | return; |
229 | } |
230 | |
231 | // Get all distinct directories from 'files' and open a tab |
232 | // for each directory. If the "split view" option is enabled, two |
233 | // directories are shown inside one tab (see openDirectories()). |
234 | QList<KUrl> dirs; |
235 | foreach (const KUrl& url, files) { |
236 | const KUrl dir(url.directory()); |
237 | if (!dirs.contains(dir)) { |
238 | dirs.append(dir); |
239 | } |
240 | } |
241 | |
242 | openDirectories(dirs); |
243 | |
244 | // Select the files. Although the files can be split between several |
245 | // tabs, there is no need to split 'files' accordingly, as |
246 | // the DolphinView will just ignore invalid selections. |
247 | foreach (DolphinTabPage* tabPage, m_viewTab) { |
248 | tabPage->markUrlsAsSelected(files); |
249 | tabPage->markUrlAsCurrent(files.first()); |
250 | } |
251 | } |
252 | |
253 | void DolphinMainWindow::showCommand(CommandType command) |
254 | { |
255 | DolphinStatusBar* statusBar = m_activeViewContainer->statusBar(); |
256 | switch (command) { |
257 | case KIO::FileUndoManager::Copy: |
258 | statusBar->setText(i18nc("@info:status" , "Successfully copied." )); |
259 | break; |
260 | case KIO::FileUndoManager::Move: |
261 | statusBar->setText(i18nc("@info:status" , "Successfully moved." )); |
262 | break; |
263 | case KIO::FileUndoManager::Link: |
264 | statusBar->setText(i18nc("@info:status" , "Successfully linked." )); |
265 | break; |
266 | case KIO::FileUndoManager::Trash: |
267 | statusBar->setText(i18nc("@info:status" , "Successfully moved to trash." )); |
268 | break; |
269 | case KIO::FileUndoManager::Rename: |
270 | statusBar->setText(i18nc("@info:status" , "Successfully renamed." )); |
271 | break; |
272 | |
273 | case KIO::FileUndoManager::Mkdir: |
274 | statusBar->setText(i18nc("@info:status" , "Created folder." )); |
275 | break; |
276 | |
277 | default: |
278 | break; |
279 | } |
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) { |
298 | view->setUrl(url); |
299 | updateEditActions(); |
300 | updatePasteAction(); |
301 | updateViewActions(); |
302 | updateGoActions(); |
303 | setUrlAsCaption(url); |
304 | |
305 | const QString iconName = KMimeType::iconNameForUrl(url); |
306 | m_tabBar->setTabIcon(m_tabIndex, KIcon(iconName)); |
307 | m_tabBar->setTabText(m_tabIndex, squeezedText(tabName(view->url()))); |
308 | |
309 | emit urlChanged(url); |
310 | } |
311 | } |
312 | |
313 | void DolphinMainWindow::slotTerminalDirectoryChanged(const KUrl& url) |
314 | { |
315 | m_activeViewContainer->setAutoGrabFocus(false); |
316 | changeUrl(url); |
317 | m_activeViewContainer->setAutoGrabFocus(true); |
318 | } |
319 | |
320 | void DolphinMainWindow::slotEditableStateChanged(bool editable) |
321 | { |
322 | KToggleAction* editableLocationAction = |
323 | static_cast<KToggleAction*>(actionCollection()->action("editable_location" )); |
324 | editableLocationAction->setChecked(editable); |
325 | } |
326 | |
327 | void DolphinMainWindow::slotSelectionChanged(const KFileItemList& selection) |
328 | { |
329 | updateEditActions(); |
330 | |
331 | const int selectedUrlsCount = m_viewTab.at(m_tabIndex)->selectedItemsCount(); |
332 | |
333 | QAction* compareFilesAction = actionCollection()->action("compare_files" ); |
334 | if (selectedUrlsCount == 2) { |
335 | compareFilesAction->setEnabled(isKompareInstalled()); |
336 | } else { |
337 | compareFilesAction->setEnabled(false); |
338 | } |
339 | |
340 | emit selectionChanged(selection); |
341 | } |
342 | |
343 | void DolphinMainWindow::slotRequestItemInfo(const KFileItem& item) |
344 | { |
345 | emit requestItemInfo(item); |
346 | } |
347 | |
348 | void DolphinMainWindow::updateHistory() |
349 | { |
350 | const KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); |
351 | const int index = urlNavigator->historyIndex(); |
352 | |
353 | QAction* backAction = actionCollection()->action("go_back" ); |
354 | if (backAction) { |
355 | backAction->setToolTip(i18nc("@info" , "Go back" )); |
356 | backAction->setEnabled(index < urlNavigator->historySize() - 1); |
357 | } |
358 | |
359 | QAction* forwardAction = actionCollection()->action("go_forward" ); |
360 | if (forwardAction) { |
361 | forwardAction->setToolTip(i18nc("@info" , "Go forward" )); |
362 | forwardAction->setEnabled(index > 0); |
363 | } |
364 | } |
365 | |
366 | void DolphinMainWindow::updateFilterBarAction(bool show) |
367 | { |
368 | QAction* showFilterBarAction = actionCollection()->action("show_filter_bar" ); |
369 | showFilterBarAction->setChecked(show); |
370 | } |
371 | |
372 | void DolphinMainWindow::openNewMainWindow() |
373 | { |
374 | KRun::run("dolphin %u" , KUrl::List(), this); |
375 | } |
376 | |
377 | void DolphinMainWindow::openNewTab() |
378 | { |
379 | const bool isUrlEditable = m_activeViewContainer->urlNavigator()->isUrlEditable(); |
380 | |
381 | openNewTab(m_activeViewContainer->url()); |
382 | m_tabBar->setCurrentIndex(m_viewTab.count() - 1); |
383 | |
384 | // The URL navigator of the new tab should have the same editable state |
385 | // as the current tab |
386 | KUrlNavigator* navigator = m_activeViewContainer->urlNavigator(); |
387 | navigator->setUrlEditable(isUrlEditable); |
388 | |
389 | if (isUrlEditable) { |
390 | // If a new tab is opened and the URL is editable, assure that |
391 | // the user can edit the URL without manually setting the focus |
392 | navigator->setFocus(); |
393 | } |
394 | } |
395 | |
396 | void DolphinMainWindow::openNewTab(const KUrl& primaryUrl, const KUrl& secondaryUrl) |
397 | { |
398 | QWidget* focusWidget = QApplication::focusWidget(); |
399 | |
400 | DolphinTabPage* tabPage = new DolphinTabPage(primaryUrl, secondaryUrl, this); |
401 | m_viewTab.append(tabPage); |
402 | |
403 | connect(tabPage, SIGNAL(activeViewChanged()), |
404 | this, SLOT(activeViewChanged())); |
405 | |
406 | // The places-selector from the URL navigator should only be shown |
407 | // if the places dock is invisible |
408 | QDockWidget* placesDock = findChild<QDockWidget*>("placesDock" ); |
409 | const bool placesSelectorVisible = !placesDock || !placesDock->isVisible(); |
410 | tabPage->setPlacesSelectorVisible(placesSelectorVisible); |
411 | |
412 | DolphinViewContainer* primaryContainer = tabPage->primaryViewContainer(); |
413 | connectViewSignals(primaryContainer); |
414 | |
415 | if (tabPage->splitViewEnabled()) { |
416 | DolphinViewContainer* secondaryContainer = tabPage->secondaryViewContainer(); |
417 | connectViewSignals(secondaryContainer); |
418 | } |
419 | |
420 | tabPage->hide(); |
421 | |
422 | m_tabBar->addTab(KIcon(KMimeType::iconNameForUrl(primaryUrl)), |
423 | squeezedText(tabName(primaryUrl))); |
424 | |
425 | if (m_viewTab.count() > 1) { |
426 | actionCollection()->action("close_tab" )->setEnabled(true); |
427 | actionCollection()->action("activate_prev_tab" )->setEnabled(true); |
428 | actionCollection()->action("activate_next_tab" )->setEnabled(true); |
429 | m_tabBar->show(); |
430 | m_tabBar->blockSignals(false); |
431 | } |
432 | |
433 | if (focusWidget) { |
434 | // The DolphinViewContainer grabbed the keyboard focus. As the tab is opened |
435 | // in background, assure that the previous focused widget gets the focus back. |
436 | focusWidget->setFocus(); |
437 | } |
438 | } |
439 | |
440 | void DolphinMainWindow::openNewActivatedTab(const KUrl& primaryUrl, const KUrl& secondaryUrl) |
441 | { |
442 | openNewTab(primaryUrl, secondaryUrl); |
443 | setActiveTab(m_viewTab.count() - 1); |
444 | } |
445 | |
446 | void DolphinMainWindow::activateNextTab() |
447 | { |
448 | if (m_viewTab.count() >= 2) { |
449 | const int tabIndex = (m_tabBar->currentIndex() + 1) % m_tabBar->count(); |
450 | setActiveTab(tabIndex); |
451 | } |
452 | } |
453 | |
454 | void DolphinMainWindow::activatePrevTab() |
455 | { |
456 | if (m_viewTab.count() >= 2) { |
457 | int tabIndex = m_tabBar->currentIndex() - 1; |
458 | if (tabIndex == -1) { |
459 | tabIndex = m_tabBar->count() - 1; |
460 | } |
461 | setActiveTab(tabIndex); |
462 | } |
463 | } |
464 | |
465 | void DolphinMainWindow::openInNewTab() |
466 | { |
467 | const KFileItemList& list = m_activeViewContainer->view()->selectedItems(); |
468 | if (list.isEmpty()) { |
469 | openNewTab(m_activeViewContainer->url()); |
470 | } else { |
471 | foreach (const KFileItem& item, list) { |
472 | const KUrl& url = DolphinView::openItemAsFolderUrl(item); |
473 | if (!url.isEmpty()) { |
474 | openNewTab(url); |
475 | } |
476 | } |
477 | } |
478 | } |
479 | |
480 | void DolphinMainWindow::openInNewWindow() |
481 | { |
482 | KUrl newWindowUrl; |
483 | |
484 | const KFileItemList list = m_activeViewContainer->view()->selectedItems(); |
485 | if (list.isEmpty()) { |
486 | newWindowUrl = m_activeViewContainer->url(); |
487 | } else if (list.count() == 1) { |
488 | const KFileItem& item = list.first(); |
489 | newWindowUrl = DolphinView::openItemAsFolderUrl(item); |
490 | } |
491 | |
492 | if (!newWindowUrl.isEmpty()) { |
493 | KRun::run("dolphin %u" , KUrl::List() << newWindowUrl, this); |
494 | } |
495 | } |
496 | |
497 | void DolphinMainWindow::showEvent(QShowEvent* event) |
498 | { |
499 | KXmlGuiWindow::showEvent(event); |
500 | |
501 | if (!m_activeViewContainer && m_viewTab.count() > 0) { |
502 | // If we have no active view container yet, we set the primary view container |
503 | // of the first tab as active view container. |
504 | setActiveTab(0); |
505 | } |
506 | |
507 | if (!event->spontaneous()) { |
508 | m_activeViewContainer->view()->setFocus(); |
509 | } |
510 | } |
511 | |
512 | void DolphinMainWindow::closeEvent(QCloseEvent* event) |
513 | { |
514 | // Find out if Dolphin is closed directly by the user or |
515 | // by the session manager because the session is closed |
516 | bool closedByUser = true; |
517 | DolphinApplication *application = qobject_cast<DolphinApplication*>(qApp); |
518 | if (application && application->sessionSaving()) { |
519 | closedByUser = false; |
520 | } |
521 | |
522 | if (m_viewTab.count() > 1 && GeneralSettings::confirmClosingMultipleTabs() && closedByUser) { |
523 | // Ask the user if he really wants to quit and close all tabs. |
524 | // Open a confirmation dialog with 3 buttons: |
525 | // KDialog::Yes -> Quit |
526 | // KDialog::No -> Close only the current tab |
527 | // KDialog::Cancel -> do nothing |
528 | KDialog *dialog = new KDialog(this, Qt::Dialog); |
529 | dialog->setCaption(i18nc("@title:window" , "Confirmation" )); |
530 | dialog->setButtons(KDialog::Yes | KDialog::No | KDialog::Cancel); |
531 | dialog->setModal(true); |
532 | dialog->setButtonGuiItem(KDialog::Yes, KStandardGuiItem::quit()); |
533 | dialog->setButtonGuiItem(KDialog::No, KGuiItem(i18n("C&lose Current Tab" ), KIcon("tab-close" ))); |
534 | dialog->setButtonGuiItem(KDialog::Cancel, KStandardGuiItem::cancel()); |
535 | dialog->setDefaultButton(KDialog::Yes); |
536 | |
537 | bool doNotAskAgainCheckboxResult = false; |
538 | |
539 | const int result = KMessageBox::createKMessageBox(dialog, |
540 | QMessageBox::Warning, |
541 | i18n("You have multiple tabs open in this window, are you sure you want to quit?" ), |
542 | QStringList(), |
543 | i18n("Do not ask again" ), |
544 | &doNotAskAgainCheckboxResult, |
545 | KMessageBox::Notify); |
546 | |
547 | if (doNotAskAgainCheckboxResult) { |
548 | GeneralSettings::setConfirmClosingMultipleTabs(false); |
549 | } |
550 | |
551 | switch (result) { |
552 | case KDialog::Yes: |
553 | // Quit |
554 | break; |
555 | case KDialog::No: |
556 | // Close only the current tab |
557 | closeTab(); |
558 | default: |
559 | event->ignore(); |
560 | return; |
561 | } |
562 | } |
563 | |
564 | GeneralSettings::setVersion(CurrentDolphinVersion); |
565 | GeneralSettings::self()->writeConfig(); |
566 | |
567 | KXmlGuiWindow::closeEvent(event); |
568 | } |
569 | |
570 | void DolphinMainWindow::saveProperties(KConfigGroup& group) |
571 | { |
572 | const int tabCount = m_viewTab.count(); |
573 | group.writeEntry("Tab Count" , tabCount); |
574 | group.writeEntry("Active Tab Index" , m_tabBar->currentIndex()); |
575 | |
576 | for (int i = 0; i < tabCount; ++i) { |
577 | const DolphinTabPage* tabPage = m_viewTab.at(i); |
578 | group.writeEntry("Tab " % QString::number(i), tabPage->saveState()); |
579 | } |
580 | } |
581 | |
582 | void DolphinMainWindow::readProperties(const KConfigGroup& group) |
583 | { |
584 | const int tabCount = group.readEntry("Tab Count" , 1); |
585 | for (int i = 0; i < tabCount; ++i) { |
586 | const QByteArray state = group.readEntry("Tab " % QString::number(i), QByteArray()); |
587 | DolphinTabPage* tabPage = m_viewTab.at(i); |
588 | tabPage->restoreState(state); |
589 | |
590 | // openNewTab() needs to be called only tabCount - 1 times |
591 | if (i != tabCount - 1) { |
592 | openNewTab(); |
593 | } |
594 | } |
595 | |
596 | const int index = group.readEntry("Active Tab Index" , 0); |
597 | m_tabBar->setCurrentIndex(index); |
598 | } |
599 | |
600 | void DolphinMainWindow::updateNewMenu() |
601 | { |
602 | m_newFileMenu->setViewShowsHiddenFiles(activeViewContainer()->view()->hiddenFilesShown()); |
603 | m_newFileMenu->checkUpToDate(); |
604 | m_newFileMenu->setPopupFiles(activeViewContainer()->url()); |
605 | } |
606 | |
607 | void DolphinMainWindow::createDirectory() |
608 | { |
609 | m_newFileMenu->setViewShowsHiddenFiles(activeViewContainer()->view()->hiddenFilesShown()); |
610 | m_newFileMenu->setPopupFiles(activeViewContainer()->url()); |
611 | m_newFileMenu->createDirectory(); |
612 | } |
613 | |
614 | void DolphinMainWindow::quit() |
615 | { |
616 | close(); |
617 | } |
618 | |
619 | void DolphinMainWindow::showErrorMessage(const QString& message) |
620 | { |
621 | m_activeViewContainer->showMessage(message, DolphinViewContainer::Error); |
622 | } |
623 | |
624 | void DolphinMainWindow::slotUndoAvailable(bool available) |
625 | { |
626 | QAction* undoAction = actionCollection()->action(KStandardAction::name(KStandardAction::Undo)); |
627 | if (undoAction) { |
628 | undoAction->setEnabled(available); |
629 | } |
630 | } |
631 | |
632 | void DolphinMainWindow::slotUndoTextChanged(const QString& text) |
633 | { |
634 | QAction* undoAction = actionCollection()->action(KStandardAction::name(KStandardAction::Undo)); |
635 | if (undoAction) { |
636 | undoAction->setText(text); |
637 | } |
638 | } |
639 | |
640 | void DolphinMainWindow::undo() |
641 | { |
642 | clearStatusBar(); |
643 | KIO::FileUndoManager::self()->uiInterface()->setParentWidget(this); |
644 | KIO::FileUndoManager::self()->undo(); |
645 | } |
646 | |
647 | void DolphinMainWindow::cut() |
648 | { |
649 | m_activeViewContainer->view()->cutSelectedItems(); |
650 | } |
651 | |
652 | void DolphinMainWindow::copy() |
653 | { |
654 | m_activeViewContainer->view()->copySelectedItems(); |
655 | } |
656 | |
657 | void DolphinMainWindow::paste() |
658 | { |
659 | m_activeViewContainer->view()->paste(); |
660 | } |
661 | |
662 | void DolphinMainWindow::find() |
663 | { |
664 | m_activeViewContainer->setSearchModeEnabled(true); |
665 | } |
666 | |
667 | void DolphinMainWindow::updatePasteAction() |
668 | { |
669 | QAction* pasteAction = actionCollection()->action(KStandardAction::name(KStandardAction::Paste)); |
670 | QPair<bool, QString> pasteInfo = m_activeViewContainer->view()->pasteInfo(); |
671 | pasteAction->setEnabled(pasteInfo.first); |
672 | pasteAction->setText(pasteInfo.second); |
673 | } |
674 | |
675 | void DolphinMainWindow::selectAll() |
676 | { |
677 | clearStatusBar(); |
678 | |
679 | // if the URL navigator is editable and focused, select the whole |
680 | // URL instead of all items of the view |
681 | |
682 | KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); |
683 | QLineEdit* lineEdit = urlNavigator->editor()->lineEdit(); // krazy:exclude=qclasses |
684 | const bool selectUrl = urlNavigator->isUrlEditable() && |
685 | lineEdit->hasFocus(); |
686 | if (selectUrl) { |
687 | lineEdit->selectAll(); |
688 | } else { |
689 | m_activeViewContainer->view()->selectAll(); |
690 | } |
691 | } |
692 | |
693 | void DolphinMainWindow::invertSelection() |
694 | { |
695 | clearStatusBar(); |
696 | m_activeViewContainer->view()->invertSelection(); |
697 | } |
698 | |
699 | void DolphinMainWindow::toggleSplitView() |
700 | { |
701 | DolphinTabPage* tabPage = m_viewTab.at(m_tabIndex); |
702 | tabPage->setSplitViewEnabled(!tabPage->splitViewEnabled()); |
703 | |
704 | if (tabPage->splitViewEnabled()) { |
705 | connectViewSignals(tabPage->secondaryViewContainer()); |
706 | } |
707 | |
708 | updateViewActions(); |
709 | } |
710 | |
711 | void DolphinMainWindow::reloadView() |
712 | { |
713 | clearStatusBar(); |
714 | m_activeViewContainer->view()->reload(); |
715 | } |
716 | |
717 | void DolphinMainWindow::stopLoading() |
718 | { |
719 | m_activeViewContainer->view()->stopLoading(); |
720 | } |
721 | |
722 | void DolphinMainWindow::enableStopAction() |
723 | { |
724 | actionCollection()->action("stop" )->setEnabled(true); |
725 | } |
726 | |
727 | void DolphinMainWindow::disableStopAction() |
728 | { |
729 | actionCollection()->action("stop" )->setEnabled(false); |
730 | } |
731 | |
732 | void DolphinMainWindow::showFilterBar() |
733 | { |
734 | m_activeViewContainer->setFilterBarVisible(true); |
735 | } |
736 | |
737 | void DolphinMainWindow::toggleEditLocation() |
738 | { |
739 | clearStatusBar(); |
740 | |
741 | QAction* action = actionCollection()->action("editable_location" ); |
742 | KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); |
743 | urlNavigator->setUrlEditable(action->isChecked()); |
744 | } |
745 | |
746 | void DolphinMainWindow::replaceLocation() |
747 | { |
748 | KUrlNavigator* navigator = m_activeViewContainer->urlNavigator(); |
749 | navigator->setUrlEditable(true); |
750 | navigator->setFocus(); |
751 | |
752 | // select the whole text of the combo box editor |
753 | QLineEdit* lineEdit = navigator->editor()->lineEdit(); // krazy:exclude=qclasses |
754 | lineEdit->selectAll(); |
755 | } |
756 | |
757 | void DolphinMainWindow::togglePanelLockState() |
758 | { |
759 | const bool newLockState = !GeneralSettings::lockPanels(); |
760 | foreach (QObject* child, children()) { |
761 | DolphinDockWidget* dock = qobject_cast<DolphinDockWidget*>(child); |
762 | if (dock) { |
763 | dock->setLocked(newLockState); |
764 | } |
765 | } |
766 | |
767 | GeneralSettings::setLockPanels(newLockState); |
768 | } |
769 | |
770 | void DolphinMainWindow::slotPlacesPanelVisibilityChanged(bool visible) |
771 | { |
772 | foreach (DolphinTabPage* tabPage, m_viewTab) { |
773 | // The Places selector in the location bar should be shown if and only if the Places panel is hidden. |
774 | tabPage->setPlacesSelectorVisible(!visible); |
775 | } |
776 | } |
777 | |
778 | void DolphinMainWindow::goBack() |
779 | { |
780 | KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); |
781 | urlNavigator->goBack(); |
782 | |
783 | if (urlNavigator->locationState().isEmpty()) { |
784 | // An empty location state indicates a redirection URL, |
785 | // which must be skipped too |
786 | urlNavigator->goBack(); |
787 | } |
788 | } |
789 | |
790 | void DolphinMainWindow::goForward() |
791 | { |
792 | m_activeViewContainer->urlNavigator()->goForward(); |
793 | } |
794 | |
795 | void DolphinMainWindow::goUp() |
796 | { |
797 | m_activeViewContainer->urlNavigator()->goUp(); |
798 | } |
799 | |
800 | void DolphinMainWindow::goHome() |
801 | { |
802 | m_activeViewContainer->urlNavigator()->goHome(); |
803 | } |
804 | |
805 | void DolphinMainWindow::goBack(Qt::MouseButtons buttons) |
806 | { |
807 | // The default case (left button pressed) is handled in goBack(). |
808 | if (buttons == Qt::MidButton) { |
809 | KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigator(); |
810 | const int index = urlNavigator->historyIndex() + 1; |
811 | openNewTab(urlNavigator->locationUrl(index)); |
812 | } |
813 | } |
814 | |
815 | void DolphinMainWindow::goForward(Qt::MouseButtons buttons) |
816 | { |
817 | // The default case (left button pressed) is handled in goForward(). |
818 | if (buttons == Qt::MidButton) { |
819 | KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigator(); |
820 | const int index = urlNavigator->historyIndex() - 1; |
821 | openNewTab(urlNavigator->locationUrl(index)); |
822 | } |
823 | } |
824 | |
825 | void DolphinMainWindow::goUp(Qt::MouseButtons buttons) |
826 | { |
827 | // The default case (left button pressed) is handled in goUp(). |
828 | if (buttons == Qt::MidButton) { |
829 | openNewTab(activeViewContainer()->url().upUrl()); |
830 | } |
831 | } |
832 | |
833 | void DolphinMainWindow::goHome(Qt::MouseButtons buttons) |
834 | { |
835 | // The default case (left button pressed) is handled in goHome(). |
836 | if (buttons == Qt::MidButton) { |
837 | openNewTab(GeneralSettings::self()->homeUrl()); |
838 | } |
839 | } |
840 | |
841 | void DolphinMainWindow::compareFiles() |
842 | { |
843 | const KFileItemList items = m_viewTab.at(m_tabIndex)->selectedItems(); |
844 | if (items.count() != 2) { |
845 | // The action is disabled in this case, but it could have been triggered |
846 | // via D-Bus, see https://bugs.kde.org/show_bug.cgi?id=325517 |
847 | return; |
848 | } |
849 | |
850 | KUrl urlA = items.at(0).url(); |
851 | KUrl urlB = items.at(1).url(); |
852 | |
853 | QString command("kompare -c \"" ); |
854 | command.append(urlA.pathOrUrl()); |
855 | command.append("\" \"" ); |
856 | command.append(urlB.pathOrUrl()); |
857 | command.append('\"'); |
858 | KRun::runCommand(command, "Kompare" , "kompare" , this); |
859 | } |
860 | |
861 | void DolphinMainWindow::toggleShowMenuBar() |
862 | { |
863 | const bool visible = menuBar()->isVisible(); |
864 | menuBar()->setVisible(!visible); |
865 | if (visible) { |
866 | createControlButton(); |
867 | } else { |
868 | deleteControlButton(); |
869 | } |
870 | } |
871 | |
872 | void DolphinMainWindow::openTerminal() |
873 | { |
874 | QString dir(QDir::homePath()); |
875 | |
876 | // If the given directory is not local, it can still be the URL of an |
877 | // ioslave using UDS_LOCAL_PATH which to be converted first. |
878 | KUrl url = KIO::NetAccess::mostLocalUrl(m_activeViewContainer->url(), this); |
879 | |
880 | //If the URL is local after the above conversion, set the directory. |
881 | if (url.isLocalFile()) { |
882 | dir = url.toLocalFile(); |
883 | } |
884 | |
885 | KToolInvocation::invokeTerminal(QString(), dir); |
886 | } |
887 | |
888 | void DolphinMainWindow::editSettings() |
889 | { |
890 | if (!m_settingsDialog) { |
891 | DolphinViewContainer* container = activeViewContainer(); |
892 | container->view()->writeSettings(); |
893 | |
894 | const KUrl url = container->url(); |
895 | DolphinSettingsDialog* settingsDialog = new DolphinSettingsDialog(url, this); |
896 | connect(settingsDialog, SIGNAL(settingsChanged()), this, SLOT(refreshViews())); |
897 | settingsDialog->setAttribute(Qt::WA_DeleteOnClose); |
898 | settingsDialog->show(); |
899 | m_settingsDialog = settingsDialog; |
900 | } else { |
901 | m_settingsDialog.data()->raise(); |
902 | } |
903 | } |
904 | |
905 | void DolphinMainWindow::setActiveTab(int index) |
906 | { |
907 | Q_ASSERT(index >= 0); |
908 | Q_ASSERT(index < m_viewTab.count()); |
909 | if (index == m_tabIndex) { |
910 | return; |
911 | } |
912 | |
913 | m_tabBar->setCurrentIndex(index); |
914 | |
915 | // hide current tab content |
916 | if (m_tabIndex >= 0) { |
917 | DolphinTabPage* hiddenTabPage = m_viewTab.at(m_tabIndex); |
918 | hiddenTabPage->hide(); |
919 | m_centralWidgetLayout->removeWidget(hiddenTabPage); |
920 | } |
921 | |
922 | // show active tab content |
923 | m_tabIndex = index; |
924 | |
925 | DolphinTabPage* tabPage = m_viewTab.at(index); |
926 | m_centralWidgetLayout->addWidget(tabPage, 1); |
927 | tabPage->show(); |
928 | |
929 | setActiveViewContainer(tabPage->activeViewContainer()); |
930 | } |
931 | |
932 | void DolphinMainWindow::closeTab() |
933 | { |
934 | closeTab(m_tabBar->currentIndex()); |
935 | } |
936 | |
937 | void DolphinMainWindow::closeTab(int index) |
938 | { |
939 | Q_ASSERT(index >= 0); |
940 | Q_ASSERT(index < m_viewTab.count()); |
941 | if (m_viewTab.count() == 1) { |
942 | // the last tab may never get closed |
943 | return; |
944 | } |
945 | |
946 | if (index == m_tabIndex) { |
947 | // The tab that should be closed is the active tab. Activate the |
948 | // previous tab before closing the tab. |
949 | m_tabBar->setCurrentIndex((index > 0) ? index - 1 : 1); |
950 | } |
951 | |
952 | DolphinTabPage* tabPage = m_viewTab.at(index); |
953 | |
954 | if (tabPage->splitViewEnabled()) { |
955 | emit rememberClosedTab(tabPage->primaryViewContainer()->url(), |
956 | tabPage->secondaryViewContainer()->url()); |
957 | } else { |
958 | emit rememberClosedTab(tabPage->primaryViewContainer()->url(), KUrl()); |
959 | } |
960 | |
961 | // delete tab |
962 | m_viewTab.removeAt(index); |
963 | tabPage->deleteLater(); |
964 | |
965 | m_tabBar->blockSignals(true); |
966 | m_tabBar->removeTab(index); |
967 | |
968 | if (m_tabIndex > index) { |
969 | m_tabIndex--; |
970 | Q_ASSERT(m_tabIndex >= 0); |
971 | } |
972 | |
973 | // if only one tab is left, also remove the tab entry so that |
974 | // closing the last tab is not possible |
975 | if (m_viewTab.count() < 2) { |
976 | actionCollection()->action("close_tab" )->setEnabled(false); |
977 | actionCollection()->action("activate_prev_tab" )->setEnabled(false); |
978 | actionCollection()->action("activate_next_tab" )->setEnabled(false); |
979 | m_tabBar->hide(); |
980 | } else { |
981 | m_tabBar->blockSignals(false); |
982 | } |
983 | } |
984 | |
985 | void DolphinMainWindow::openTabContextMenu(int index, const QPoint& pos) |
986 | { |
987 | KMenu (this); |
988 | |
989 | QAction* newTabAction = menu.addAction(KIcon("tab-new" ), i18nc("@action:inmenu" , "New Tab" )); |
990 | newTabAction->setShortcut(actionCollection()->action("new_tab" )->shortcut()); |
991 | |
992 | QAction* detachTabAction = menu.addAction(KIcon("tab-detach" ), i18nc("@action:inmenu" , "Detach Tab" )); |
993 | |
994 | QAction* closeOtherTabsAction = menu.addAction(KIcon("tab-close-other" ), i18nc("@action:inmenu" , "Close Other Tabs" )); |
995 | |
996 | QAction* closeTabAction = menu.addAction(KIcon("tab-close" ), i18nc("@action:inmenu" , "Close Tab" )); |
997 | closeTabAction->setShortcut(actionCollection()->action("close_tab" )->shortcut()); |
998 | QAction* selectedAction = menu.exec(pos); |
999 | if (selectedAction == newTabAction) { |
1000 | const KUrl url = m_viewTab.at(index)->activeViewContainer()->url(); |
1001 | openNewTab(url); |
1002 | m_tabBar->setCurrentIndex(m_viewTab.count() - 1); |
1003 | } else if (selectedAction == detachTabAction) { |
1004 | const QString separator(QLatin1Char(' ')); |
1005 | QString command = QLatin1String("dolphin" ); |
1006 | |
1007 | const DolphinTabPage* tabPage = m_viewTab.at(index); |
1008 | |
1009 | command += separator + tabPage->primaryViewContainer()->url().url(); |
1010 | if (tabPage->splitViewEnabled()) { |
1011 | command += separator + tabPage->secondaryViewContainer()->url().url(); |
1012 | command += separator + QLatin1String("-split" ); |
1013 | } |
1014 | |
1015 | KRun::runCommand(command, this); |
1016 | |
1017 | closeTab(index); |
1018 | } else if (selectedAction == closeOtherTabsAction) { |
1019 | const int count = m_tabBar->count(); |
1020 | for (int i = 0; i < index; ++i) { |
1021 | closeTab(0); |
1022 | } |
1023 | for (int i = index + 1; i < count; ++i) { |
1024 | closeTab(1); |
1025 | } |
1026 | } else if (selectedAction == closeTabAction) { |
1027 | closeTab(index); |
1028 | } |
1029 | } |
1030 | |
1031 | void DolphinMainWindow::slotTabMoved(int from, int to) |
1032 | { |
1033 | m_viewTab.move(from, to); |
1034 | m_tabIndex = m_tabBar->currentIndex(); |
1035 | } |
1036 | |
1037 | void DolphinMainWindow::slotTestCanDecode(const QDragMoveEvent* event, bool& canDecode) |
1038 | { |
1039 | canDecode = KUrl::List::canDecode(event->mimeData()); |
1040 | } |
1041 | |
1042 | void DolphinMainWindow::handleUrl(const KUrl& url) |
1043 | { |
1044 | delete m_lastHandleUrlStatJob; |
1045 | m_lastHandleUrlStatJob = 0; |
1046 | |
1047 | if (url.isLocalFile() && QFileInfo(url.toLocalFile()).isDir()) { |
1048 | activeViewContainer()->setUrl(url); |
1049 | } else if (KProtocolManager::supportsListing(url)) { |
1050 | // stat the URL to see if it is a dir or not |
1051 | m_lastHandleUrlStatJob = KIO::stat(url, KIO::HideProgressInfo); |
1052 | if (m_lastHandleUrlStatJob->ui()) { |
1053 | m_lastHandleUrlStatJob->ui()->setWindow(this); |
1054 | } |
1055 | connect(m_lastHandleUrlStatJob, SIGNAL(result(KJob*)), |
1056 | this, SLOT(slotHandleUrlStatFinished(KJob*))); |
1057 | |
1058 | } else { |
1059 | new KRun(url, this); // Automatically deletes itself after being finished |
1060 | } |
1061 | } |
1062 | |
1063 | void DolphinMainWindow::slotHandleUrlStatFinished(KJob* job) |
1064 | { |
1065 | m_lastHandleUrlStatJob = 0; |
1066 | const KIO::UDSEntry entry = static_cast<KIO::StatJob*>(job)->statResult(); |
1067 | const KUrl url = static_cast<KIO::StatJob*>(job)->url(); |
1068 | if (entry.isDir()) { |
1069 | activeViewContainer()->setUrl(url); |
1070 | } else { |
1071 | new KRun(url, this); // Automatically deletes itself after being finished |
1072 | } |
1073 | } |
1074 | |
1075 | void DolphinMainWindow::tabDropEvent(int tab, QDropEvent* event) |
1076 | { |
1077 | const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData()); |
1078 | if (!urls.isEmpty() && tab != -1) { |
1079 | const DolphinView* view = m_viewTab.at(tab)->activeViewContainer()->view(); |
1080 | |
1081 | QString error; |
1082 | DragAndDropHelper::dropUrls(view->rootItem(), view->url(), event, error); |
1083 | if (!error.isEmpty()) { |
1084 | activeViewContainer()->showMessage(error, DolphinViewContainer::Error); |
1085 | } |
1086 | } |
1087 | } |
1088 | |
1089 | void DolphinMainWindow::slotWriteStateChanged(bool isFolderWritable) |
1090 | { |
1091 | newFileMenu()->setEnabled(isFolderWritable); |
1092 | } |
1093 | |
1094 | void DolphinMainWindow::openContextMenu(const QPoint& pos, |
1095 | const KFileItem& item, |
1096 | const KUrl& url, |
1097 | const QList<QAction*>& customActions) |
1098 | { |
1099 | QWeakPointer<DolphinContextMenu> = new DolphinContextMenu(this, pos, item, url); |
1100 | contextMenu.data()->setCustomActions(customActions); |
1101 | const DolphinContextMenu::Command command = contextMenu.data()->open(); |
1102 | |
1103 | switch (command) { |
1104 | case DolphinContextMenu::OpenParentFolderInNewWindow: { |
1105 | KRun::run("dolphin %u" , KUrl::List() << item.url().upUrl(), this); |
1106 | break; |
1107 | } |
1108 | |
1109 | case DolphinContextMenu::OpenParentFolderInNewTab: |
1110 | openNewTab(item.url().upUrl()); |
1111 | break; |
1112 | |
1113 | case DolphinContextMenu::None: |
1114 | default: |
1115 | break; |
1116 | } |
1117 | |
1118 | delete contextMenu.data(); |
1119 | } |
1120 | |
1121 | void DolphinMainWindow::updateControlMenu() |
1122 | { |
1123 | KMenu* = qobject_cast<KMenu*>(sender()); |
1124 | Q_ASSERT(menu); |
1125 | |
1126 | // All actions get cleared by KMenu::clear(). The sub-menus are deleted |
1127 | // by connecting to the aboutToHide() signal from the parent-menu. |
1128 | menu->clear(); |
1129 | |
1130 | KActionCollection* ac = actionCollection(); |
1131 | |
1132 | // Add "Edit" actions |
1133 | bool added = addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Undo)), menu) | |
1134 | addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Find)), menu) | |
1135 | addActionToMenu(ac->action("select_all" ), menu) | |
1136 | addActionToMenu(ac->action("invert_selection" ), menu); |
1137 | |
1138 | if (added) { |
1139 | menu->addSeparator(); |
1140 | } |
1141 | |
1142 | // Add "View" actions |
1143 | if (!GeneralSettings::showZoomSlider()) { |
1144 | addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ZoomIn)), menu); |
1145 | addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ZoomOut)), menu); |
1146 | menu->addSeparator(); |
1147 | } |
1148 | |
1149 | added = addActionToMenu(ac->action("view_mode" ), menu) | |
1150 | addActionToMenu(ac->action("sort" ), menu) | |
1151 | addActionToMenu(ac->action("additional_info" ), menu) | |
1152 | addActionToMenu(ac->action("show_preview" ), menu) | |
1153 | addActionToMenu(ac->action("show_in_groups" ), menu) | |
1154 | addActionToMenu(ac->action("show_hidden_files" ), menu); |
1155 | |
1156 | if (added) { |
1157 | menu->addSeparator(); |
1158 | } |
1159 | |
1160 | added = addActionToMenu(ac->action("split_view" ), menu) | |
1161 | addActionToMenu(ac->action("reload" ), menu) | |
1162 | addActionToMenu(ac->action("view_properties" ), menu); |
1163 | if (added) { |
1164 | menu->addSeparator(); |
1165 | } |
1166 | |
1167 | addActionToMenu(ac->action("panels" ), menu); |
1168 | KMenu* = new KMenu(i18nc("@action:inmenu" , "Location Bar" ), menu); |
1169 | locationBarMenu->addAction(ac->action("editable_location" )); |
1170 | locationBarMenu->addAction(ac->action("replace_location" )); |
1171 | menu->addMenu(locationBarMenu); |
1172 | |
1173 | menu->addSeparator(); |
1174 | |
1175 | // Add "Go" menu |
1176 | KMenu* = new KMenu(i18nc("@action:inmenu" , "Go" ), menu); |
1177 | connect(menu, SIGNAL(aboutToHide()), goMenu, SLOT(deleteLater())); |
1178 | goMenu->addAction(ac->action(KStandardAction::name(KStandardAction::Back))); |
1179 | goMenu->addAction(ac->action(KStandardAction::name(KStandardAction::Forward))); |
1180 | goMenu->addAction(ac->action(KStandardAction::name(KStandardAction::Up))); |
1181 | goMenu->addAction(ac->action(KStandardAction::name(KStandardAction::Home))); |
1182 | goMenu->addAction(ac->action("closed_tabs" )); |
1183 | menu->addMenu(goMenu); |
1184 | |
1185 | // Add "Tool" menu |
1186 | KMenu* = new KMenu(i18nc("@action:inmenu" , "Tools" ), menu); |
1187 | connect(menu, SIGNAL(aboutToHide()), toolsMenu, SLOT(deleteLater())); |
1188 | toolsMenu->addAction(ac->action("show_filter_bar" )); |
1189 | toolsMenu->addAction(ac->action("compare_files" )); |
1190 | toolsMenu->addAction(ac->action("open_terminal" )); |
1191 | toolsMenu->addAction(ac->action("change_remote_encoding" )); |
1192 | menu->addMenu(toolsMenu); |
1193 | |
1194 | // Add "Settings" menu entries |
1195 | addActionToMenu(ac->action(KStandardAction::name(KStandardAction::KeyBindings)), menu); |
1196 | addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ConfigureToolbars)), menu); |
1197 | addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Preferences)), menu); |
1198 | |
1199 | // Add "Help" menu |
1200 | KMenu* = new KMenu(i18nc("@action:inmenu" , "Help" ), menu); |
1201 | connect(menu, SIGNAL(aboutToHide()), helpMenu, SLOT(deleteLater())); |
1202 | helpMenu->addAction(ac->action(KStandardAction::name(KStandardAction::HelpContents))); |
1203 | helpMenu->addAction(ac->action(KStandardAction::name(KStandardAction::WhatsThis))); |
1204 | helpMenu->addSeparator(); |
1205 | helpMenu->addAction(ac->action(KStandardAction::name(KStandardAction::ReportBug))); |
1206 | helpMenu->addSeparator(); |
1207 | helpMenu->addAction(ac->action(KStandardAction::name(KStandardAction::SwitchApplicationLanguage))); |
1208 | helpMenu->addSeparator(); |
1209 | helpMenu->addAction(ac->action(KStandardAction::name(KStandardAction::AboutApp))); |
1210 | helpMenu->addAction(ac->action(KStandardAction::name(KStandardAction::AboutKDE))); |
1211 | menu->addMenu(helpMenu); |
1212 | |
1213 | menu->addSeparator(); |
1214 | addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ShowMenubar)), menu); |
1215 | } |
1216 | |
1217 | void DolphinMainWindow::updateToolBar() |
1218 | { |
1219 | if (!menuBar()->isVisible()) { |
1220 | createControlButton(); |
1221 | } |
1222 | } |
1223 | |
1224 | void DolphinMainWindow::slotControlButtonDeleted() |
1225 | { |
1226 | m_controlButton = 0; |
1227 | m_updateToolBarTimer->start(); |
1228 | } |
1229 | |
1230 | void DolphinMainWindow::slotPanelErrorMessage(const QString& error) |
1231 | { |
1232 | activeViewContainer()->showMessage(error, DolphinViewContainer::Error); |
1233 | } |
1234 | |
1235 | void DolphinMainWindow::slotPlaceActivated(const KUrl& url) |
1236 | { |
1237 | DolphinViewContainer* view = activeViewContainer(); |
1238 | |
1239 | if (view->url() == url) { |
1240 | // We can end up here if the user clicked a device in the Places Panel |
1241 | // which had been unmounted earlier, see https://bugs.kde.org/show_bug.cgi?id=161385. |
1242 | reloadView(); |
1243 | } else { |
1244 | changeUrl(url); |
1245 | } |
1246 | } |
1247 | |
1248 | void DolphinMainWindow::activeViewChanged() |
1249 | { |
1250 | const DolphinTabPage* tabPage = m_viewTab.at(m_tabIndex); |
1251 | setActiveViewContainer(tabPage->activeViewContainer()); |
1252 | } |
1253 | |
1254 | void DolphinMainWindow::setActiveViewContainer(DolphinViewContainer* viewContainer) |
1255 | { |
1256 | Q_ASSERT(viewContainer); |
1257 | Q_ASSERT((viewContainer == m_viewTab.at(m_tabIndex)->primaryViewContainer()) || |
1258 | (viewContainer == m_viewTab.at(m_tabIndex)->secondaryViewContainer())); |
1259 | if (m_activeViewContainer == viewContainer) { |
1260 | return; |
1261 | } |
1262 | |
1263 | m_activeViewContainer = viewContainer; |
1264 | m_actionHandler->setCurrentView(viewContainer->view()); |
1265 | |
1266 | updateHistory(); |
1267 | updateEditActions(); |
1268 | updatePasteAction(); |
1269 | updateViewActions(); |
1270 | updateGoActions(); |
1271 | |
1272 | const KUrl url = m_activeViewContainer->url(); |
1273 | setUrlAsCaption(url); |
1274 | m_tabBar->setTabText(m_tabIndex, squeezedText(tabName(url))); |
1275 | m_tabBar->setTabIcon(m_tabIndex, KIcon(KMimeType::iconNameForUrl(url))); |
1276 | |
1277 | emit urlChanged(url); |
1278 | } |
1279 | |
1280 | void DolphinMainWindow::setupActions() |
1281 | { |
1282 | // setup 'File' menu |
1283 | m_newFileMenu = new DolphinNewFileMenu(actionCollection(), this); |
1284 | KMenu* = m_newFileMenu->menu(); |
1285 | menu->setTitle(i18nc("@title:menu Create new folder, file, link, etc." , "Create New" )); |
1286 | menu->setIcon(KIcon("document-new" )); |
1287 | m_newFileMenu->setDelayed(false); |
1288 | connect(menu, SIGNAL(aboutToShow()), |
1289 | this, SLOT(updateNewMenu())); |
1290 | |
1291 | KAction* newWindow = actionCollection()->addAction("new_window" ); |
1292 | newWindow->setIcon(KIcon("window-new" )); |
1293 | newWindow->setText(i18nc("@action:inmenu File" , "New &Window" )); |
1294 | newWindow->setShortcut(Qt::CTRL | Qt::Key_N); |
1295 | connect(newWindow, SIGNAL(triggered()), this, SLOT(openNewMainWindow())); |
1296 | |
1297 | KAction* newTab = actionCollection()->addAction("new_tab" ); |
1298 | newTab->setIcon(KIcon("tab-new" )); |
1299 | newTab->setText(i18nc("@action:inmenu File" , "New Tab" )); |
1300 | newTab->setShortcut(KShortcut(Qt::CTRL | Qt::Key_T, Qt::CTRL | Qt::SHIFT | Qt::Key_N)); |
1301 | connect(newTab, SIGNAL(triggered()), this, SLOT(openNewTab())); |
1302 | |
1303 | KAction* closeTab = actionCollection()->addAction("close_tab" ); |
1304 | closeTab->setIcon(KIcon("tab-close" )); |
1305 | closeTab->setText(i18nc("@action:inmenu File" , "Close Tab" )); |
1306 | closeTab->setShortcut(Qt::CTRL | Qt::Key_W); |
1307 | closeTab->setEnabled(false); |
1308 | connect(closeTab, SIGNAL(triggered()), this, SLOT(closeTab())); |
1309 | |
1310 | KStandardAction::quit(this, SLOT(quit()), actionCollection()); |
1311 | |
1312 | // setup 'Edit' menu |
1313 | KStandardAction::undo(this, |
1314 | SLOT(undo()), |
1315 | actionCollection()); |
1316 | |
1317 | // need to remove shift+del from cut action, else the shortcut for deletejob |
1318 | // doesn't work |
1319 | KAction* cut = KStandardAction::cut(this, SLOT(cut()), actionCollection()); |
1320 | KShortcut cutShortcut = cut->shortcut(); |
1321 | cutShortcut.remove(Qt::SHIFT | Qt::Key_Delete, KShortcut::KeepEmpty); |
1322 | cut->setShortcut(cutShortcut); |
1323 | KStandardAction::copy(this, SLOT(copy()), actionCollection()); |
1324 | KAction* paste = KStandardAction::paste(this, SLOT(paste()), actionCollection()); |
1325 | // The text of the paste-action is modified dynamically by Dolphin |
1326 | // (e. g. to "Paste One Folder"). To prevent that the size of the toolbar changes |
1327 | // due to the long text, the text "Paste" is used: |
1328 | paste->setIconText(i18nc("@action:inmenu Edit" , "Paste" )); |
1329 | |
1330 | KStandardAction::find(this, SLOT(find()), actionCollection()); |
1331 | |
1332 | KAction* selectAll = actionCollection()->addAction("select_all" ); |
1333 | selectAll->setText(i18nc("@action:inmenu Edit" , "Select All" )); |
1334 | selectAll->setShortcut(Qt::CTRL | Qt::Key_A); |
1335 | connect(selectAll, SIGNAL(triggered()), this, SLOT(selectAll())); |
1336 | |
1337 | KAction* invertSelection = actionCollection()->addAction("invert_selection" ); |
1338 | invertSelection->setText(i18nc("@action:inmenu Edit" , "Invert Selection" )); |
1339 | invertSelection->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_A); |
1340 | connect(invertSelection, SIGNAL(triggered()), this, SLOT(invertSelection())); |
1341 | |
1342 | // setup 'View' menu |
1343 | // (note that most of it is set up in DolphinViewActionHandler) |
1344 | |
1345 | KAction* split = actionCollection()->addAction("split_view" ); |
1346 | split->setShortcut(Qt::Key_F3); |
1347 | connect(split, SIGNAL(triggered()), this, SLOT(toggleSplitView())); |
1348 | |
1349 | KAction* reload = actionCollection()->addAction("reload" ); |
1350 | reload->setText(i18nc("@action:inmenu View" , "Reload" )); |
1351 | reload->setShortcut(Qt::Key_F5); |
1352 | reload->setIcon(KIcon("view-refresh" )); |
1353 | connect(reload, SIGNAL(triggered()), this, SLOT(reloadView())); |
1354 | |
1355 | KAction* stop = actionCollection()->addAction("stop" ); |
1356 | stop->setText(i18nc("@action:inmenu View" , "Stop" )); |
1357 | stop->setToolTip(i18nc("@info" , "Stop loading" )); |
1358 | stop->setIcon(KIcon("process-stop" )); |
1359 | connect(stop, SIGNAL(triggered()), this, SLOT(stopLoading())); |
1360 | |
1361 | KToggleAction* editableLocation = actionCollection()->add<KToggleAction>("editable_location" ); |
1362 | editableLocation->setText(i18nc("@action:inmenu Navigation Bar" , "Editable Location" )); |
1363 | editableLocation->setShortcut(Qt::Key_F6); |
1364 | connect(editableLocation, SIGNAL(triggered()), this, SLOT(toggleEditLocation())); |
1365 | |
1366 | KAction* replaceLocation = actionCollection()->addAction("replace_location" ); |
1367 | replaceLocation->setText(i18nc("@action:inmenu Navigation Bar" , "Replace Location" )); |
1368 | replaceLocation->setShortcut(Qt::CTRL | Qt::Key_L); |
1369 | connect(replaceLocation, SIGNAL(triggered()), this, SLOT(replaceLocation())); |
1370 | |
1371 | // setup 'Go' menu |
1372 | KAction* backAction = KStandardAction::back(this, SLOT(goBack()), actionCollection()); |
1373 | connect(backAction, SIGNAL(triggered(Qt::MouseButtons,Qt::KeyboardModifiers)), this, SLOT(goBack(Qt::MouseButtons))); |
1374 | KShortcut backShortcut = backAction->shortcut(); |
1375 | backShortcut.setAlternate(Qt::Key_Backspace); |
1376 | backAction->setShortcut(backShortcut); |
1377 | |
1378 | DolphinRecentTabsMenu* = new DolphinRecentTabsMenu(this); |
1379 | actionCollection()->addAction("closed_tabs" , recentTabsMenu); |
1380 | connect(this, SIGNAL(rememberClosedTab(KUrl,KUrl)), |
1381 | recentTabsMenu, SLOT(rememberClosedTab(KUrl,KUrl))); |
1382 | connect(recentTabsMenu, SIGNAL(restoreClosedTab(KUrl,KUrl)), |
1383 | this, SLOT(openNewActivatedTab(KUrl,KUrl))); |
1384 | |
1385 | KAction* forwardAction = KStandardAction::forward(this, SLOT(goForward()), actionCollection()); |
1386 | connect(forwardAction, SIGNAL(triggered(Qt::MouseButtons,Qt::KeyboardModifiers)), this, SLOT(goForward(Qt::MouseButtons))); |
1387 | |
1388 | KAction* upAction = KStandardAction::up(this, SLOT(goUp()), actionCollection()); |
1389 | connect(upAction, SIGNAL(triggered(Qt::MouseButtons,Qt::KeyboardModifiers)), this, SLOT(goUp(Qt::MouseButtons))); |
1390 | |
1391 | KAction* homeAction = KStandardAction::home(this, SLOT(goHome()), actionCollection()); |
1392 | connect(homeAction, SIGNAL(triggered(Qt::MouseButtons,Qt::KeyboardModifiers)), this, SLOT(goHome(Qt::MouseButtons))); |
1393 | |
1394 | // setup 'Tools' menu |
1395 | KAction* showFilterBar = actionCollection()->addAction("show_filter_bar" ); |
1396 | showFilterBar->setText(i18nc("@action:inmenu Tools" , "Show Filter Bar" )); |
1397 | showFilterBar->setIcon(KIcon("view-filter" )); |
1398 | showFilterBar->setShortcut(Qt::CTRL | Qt::Key_I); |
1399 | connect(showFilterBar, SIGNAL(triggered()), this, SLOT(showFilterBar())); |
1400 | |
1401 | KAction* compareFiles = actionCollection()->addAction("compare_files" ); |
1402 | compareFiles->setText(i18nc("@action:inmenu Tools" , "Compare Files" )); |
1403 | compareFiles->setIcon(KIcon("kompare" )); |
1404 | compareFiles->setEnabled(false); |
1405 | connect(compareFiles, SIGNAL(triggered()), this, SLOT(compareFiles())); |
1406 | |
1407 | KAction* openTerminal = actionCollection()->addAction("open_terminal" ); |
1408 | openTerminal->setText(i18nc("@action:inmenu Tools" , "Open Terminal" )); |
1409 | openTerminal->setIcon(KIcon("utilities-terminal" )); |
1410 | openTerminal->setShortcut(Qt::SHIFT | Qt::Key_F4); |
1411 | connect(openTerminal, SIGNAL(triggered()), this, SLOT(openTerminal())); |
1412 | |
1413 | // setup 'Settings' menu |
1414 | KToggleAction* = KStandardAction::showMenubar(0, 0, actionCollection()); |
1415 | connect(showMenuBar, SIGNAL(triggered(bool)), // Fixes #286822 |
1416 | this, SLOT(toggleShowMenuBar()), Qt::QueuedConnection); |
1417 | KStandardAction::preferences(this, SLOT(editSettings()), actionCollection()); |
1418 | |
1419 | // not in menu actions |
1420 | QList<QKeySequence> nextTabKeys; |
1421 | nextTabKeys.append(KStandardShortcut::tabNext().primary()); |
1422 | nextTabKeys.append(QKeySequence(Qt::CTRL | Qt::Key_Tab)); |
1423 | |
1424 | QList<QKeySequence> prevTabKeys; |
1425 | prevTabKeys.append(KStandardShortcut::tabPrev().primary()); |
1426 | prevTabKeys.append(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_Tab)); |
1427 | |
1428 | KAction* activateNextTab = actionCollection()->addAction("activate_next_tab" ); |
1429 | activateNextTab->setIconText(i18nc("@action:inmenu" , "Next Tab" )); |
1430 | activateNextTab->setText(i18nc("@action:inmenu" , "Activate Next Tab" )); |
1431 | activateNextTab->setEnabled(false); |
1432 | connect(activateNextTab, SIGNAL(triggered()), SLOT(activateNextTab())); |
1433 | activateNextTab->setShortcuts(QApplication::isRightToLeft() ? prevTabKeys : nextTabKeys); |
1434 | |
1435 | KAction* activatePrevTab = actionCollection()->addAction("activate_prev_tab" ); |
1436 | activatePrevTab->setIconText(i18nc("@action:inmenu" , "Previous Tab" )); |
1437 | activatePrevTab->setText(i18nc("@action:inmenu" , "Activate Previous Tab" )); |
1438 | activatePrevTab->setEnabled(false); |
1439 | connect(activatePrevTab, SIGNAL(triggered()), SLOT(activatePrevTab())); |
1440 | activatePrevTab->setShortcuts(QApplication::isRightToLeft() ? nextTabKeys : prevTabKeys); |
1441 | |
1442 | // for context menu |
1443 | KAction* openInNewTab = actionCollection()->addAction("open_in_new_tab" ); |
1444 | openInNewTab->setText(i18nc("@action:inmenu" , "Open in New Tab" )); |
1445 | openInNewTab->setIcon(KIcon("tab-new" )); |
1446 | connect(openInNewTab, SIGNAL(triggered()), this, SLOT(openInNewTab())); |
1447 | |
1448 | KAction* openInNewTabs = actionCollection()->addAction("open_in_new_tabs" ); |
1449 | openInNewTabs->setText(i18nc("@action:inmenu" , "Open in New Tabs" )); |
1450 | openInNewTabs->setIcon(KIcon("tab-new" )); |
1451 | connect(openInNewTabs, SIGNAL(triggered()), this, SLOT(openInNewTab())); |
1452 | |
1453 | KAction* openInNewWindow = actionCollection()->addAction("open_in_new_window" ); |
1454 | openInNewWindow->setText(i18nc("@action:inmenu" , "Open in New Window" )); |
1455 | openInNewWindow->setIcon(KIcon("window-new" )); |
1456 | connect(openInNewWindow, SIGNAL(triggered()), this, SLOT(openInNewWindow())); |
1457 | } |
1458 | |
1459 | void DolphinMainWindow::setupDockWidgets() |
1460 | { |
1461 | const bool lock = GeneralSettings::lockPanels(); |
1462 | |
1463 | KDualAction* lockLayoutAction = actionCollection()->add<KDualAction>("lock_panels" ); |
1464 | lockLayoutAction->setActiveText(i18nc("@action:inmenu Panels" , "Unlock Panels" )); |
1465 | lockLayoutAction->setActiveIcon(KIcon("object-unlocked" )); |
1466 | lockLayoutAction->setInactiveText(i18nc("@action:inmenu Panels" , "Lock Panels" )); |
1467 | lockLayoutAction->setInactiveIcon(KIcon("object-locked" )); |
1468 | lockLayoutAction->setActive(lock); |
1469 | connect(lockLayoutAction, SIGNAL(triggered()), this, SLOT(togglePanelLockState())); |
1470 | |
1471 | // Setup "Information" |
1472 | DolphinDockWidget* infoDock = new DolphinDockWidget(i18nc("@title:window" , "Information" )); |
1473 | infoDock->setLocked(lock); |
1474 | infoDock->setObjectName("infoDock" ); |
1475 | infoDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); |
1476 | Panel* infoPanel = new InformationPanel(infoDock); |
1477 | infoPanel->setCustomContextMenuActions(QList<QAction*>() << lockLayoutAction); |
1478 | connect(infoPanel, SIGNAL(urlActivated(KUrl)), this, SLOT(handleUrl(KUrl))); |
1479 | infoDock->setWidget(infoPanel); |
1480 | |
1481 | QAction* infoAction = infoDock->toggleViewAction(); |
1482 | createPanelAction(KIcon("dialog-information" ), Qt::Key_F11, infoAction, "show_information_panel" ); |
1483 | |
1484 | addDockWidget(Qt::RightDockWidgetArea, infoDock); |
1485 | connect(this, SIGNAL(urlChanged(KUrl)), |
1486 | infoPanel, SLOT(setUrl(KUrl))); |
1487 | connect(this, SIGNAL(selectionChanged(KFileItemList)), |
1488 | infoPanel, SLOT(setSelection(KFileItemList))); |
1489 | connect(this, SIGNAL(requestItemInfo(KFileItem)), |
1490 | infoPanel, SLOT(requestDelayedItemInfo(KFileItem))); |
1491 | |
1492 | // Setup "Folders" |
1493 | DolphinDockWidget* foldersDock = new DolphinDockWidget(i18nc("@title:window" , "Folders" )); |
1494 | foldersDock->setLocked(lock); |
1495 | foldersDock->setObjectName("foldersDock" ); |
1496 | foldersDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); |
1497 | FoldersPanel* foldersPanel = new FoldersPanel(foldersDock); |
1498 | foldersPanel->setCustomContextMenuActions(QList<QAction*>() << lockLayoutAction); |
1499 | foldersDock->setWidget(foldersPanel); |
1500 | |
1501 | QAction* foldersAction = foldersDock->toggleViewAction(); |
1502 | createPanelAction(KIcon("folder" ), Qt::Key_F7, foldersAction, "show_folders_panel" ); |
1503 | |
1504 | addDockWidget(Qt::LeftDockWidgetArea, foldersDock); |
1505 | connect(this, SIGNAL(urlChanged(KUrl)), |
1506 | foldersPanel, SLOT(setUrl(KUrl))); |
1507 | connect(foldersPanel, SIGNAL(folderActivated(KUrl)), |
1508 | this, SLOT(changeUrl(KUrl))); |
1509 | connect(foldersPanel, SIGNAL(folderMiddleClicked(KUrl)), |
1510 | this, SLOT(openNewTab(KUrl))); |
1511 | connect(foldersPanel, SIGNAL(errorMessage(QString)), |
1512 | this, SLOT(slotPanelErrorMessage(QString))); |
1513 | |
1514 | // Setup "Terminal" |
1515 | #ifndef Q_OS_WIN |
1516 | DolphinDockWidget* terminalDock = new DolphinDockWidget(i18nc("@title:window Shell terminal" , "Terminal" )); |
1517 | terminalDock->setLocked(lock); |
1518 | terminalDock->setObjectName("terminalDock" ); |
1519 | terminalDock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); |
1520 | Panel* terminalPanel = new TerminalPanel(terminalDock); |
1521 | terminalPanel->setCustomContextMenuActions(QList<QAction*>() << lockLayoutAction); |
1522 | terminalDock->setWidget(terminalPanel); |
1523 | |
1524 | connect(terminalPanel, SIGNAL(hideTerminalPanel()), terminalDock, SLOT(hide())); |
1525 | connect(terminalPanel, SIGNAL(changeUrl(KUrl)), this, SLOT(slotTerminalDirectoryChanged(KUrl))); |
1526 | connect(terminalDock, SIGNAL(visibilityChanged(bool)), |
1527 | terminalPanel, SLOT(dockVisibilityChanged())); |
1528 | |
1529 | QAction* terminalAction = terminalDock->toggleViewAction(); |
1530 | createPanelAction(KIcon("utilities-terminal" ), Qt::Key_F4, terminalAction, "show_terminal_panel" ); |
1531 | |
1532 | addDockWidget(Qt::BottomDockWidgetArea, terminalDock); |
1533 | connect(this, SIGNAL(urlChanged(KUrl)), |
1534 | terminalPanel, SLOT(setUrl(KUrl))); |
1535 | #endif |
1536 | |
1537 | if (GeneralSettings::version() < 200) { |
1538 | infoDock->hide(); |
1539 | foldersDock->hide(); |
1540 | #ifndef Q_OS_WIN |
1541 | terminalDock->hide(); |
1542 | #endif |
1543 | } |
1544 | |
1545 | // Setup "Places" |
1546 | DolphinDockWidget* placesDock = new DolphinDockWidget(i18nc("@title:window" , "Places" )); |
1547 | placesDock->setLocked(lock); |
1548 | placesDock->setObjectName("placesDock" ); |
1549 | placesDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); |
1550 | |
1551 | PlacesPanel* placesPanel = new PlacesPanel(placesDock); |
1552 | placesPanel->setCustomContextMenuActions(QList<QAction*>() << lockLayoutAction); |
1553 | placesDock->setWidget(placesPanel); |
1554 | |
1555 | QAction* placesAction = placesDock->toggleViewAction(); |
1556 | createPanelAction(KIcon("bookmarks" ), Qt::Key_F9, placesAction, "show_places_panel" ); |
1557 | |
1558 | addDockWidget(Qt::LeftDockWidgetArea, placesDock); |
1559 | connect(placesPanel, SIGNAL(placeActivated(KUrl)), |
1560 | this, SLOT(slotPlaceActivated(KUrl))); |
1561 | connect(placesPanel, SIGNAL(placeMiddleClicked(KUrl)), |
1562 | this, SLOT(openNewTab(KUrl))); |
1563 | connect(placesPanel, SIGNAL(errorMessage(QString)), |
1564 | this, SLOT(slotPanelErrorMessage(QString))); |
1565 | connect(this, SIGNAL(urlChanged(KUrl)), |
1566 | placesPanel, SLOT(setUrl(KUrl))); |
1567 | connect(placesDock, SIGNAL(visibilityChanged(bool)), |
1568 | this, SLOT(slotPlacesPanelVisibilityChanged(bool))); |
1569 | connect(this, SIGNAL(settingsChanged()), |
1570 | placesPanel, SLOT(readSettings())); |
1571 | |
1572 | // Add actions into the "Panels" menu |
1573 | KActionMenu* = new KActionMenu(i18nc("@action:inmenu View" , "Panels" ), this); |
1574 | actionCollection()->addAction("panels" , panelsMenu); |
1575 | panelsMenu->setDelayed(false); |
1576 | const KActionCollection* ac = actionCollection(); |
1577 | panelsMenu->addAction(ac->action("show_places_panel" )); |
1578 | panelsMenu->addAction(ac->action("show_information_panel" )); |
1579 | panelsMenu->addAction(ac->action("show_folders_panel" )); |
1580 | #ifndef Q_OS_WIN |
1581 | panelsMenu->addAction(ac->action("show_terminal_panel" )); |
1582 | #endif |
1583 | panelsMenu->addSeparator(); |
1584 | panelsMenu->addAction(lockLayoutAction); |
1585 | } |
1586 | |
1587 | void DolphinMainWindow::updateEditActions() |
1588 | { |
1589 | const KFileItemList list = m_activeViewContainer->view()->selectedItems(); |
1590 | if (list.isEmpty()) { |
1591 | stateChanged("has_no_selection" ); |
1592 | } else { |
1593 | stateChanged("has_selection" ); |
1594 | |
1595 | KActionCollection* col = actionCollection(); |
1596 | QAction* renameAction = col->action("rename" ); |
1597 | QAction* moveToTrashAction = col->action("move_to_trash" ); |
1598 | QAction* deleteAction = col->action("delete" ); |
1599 | QAction* cutAction = col->action(KStandardAction::name(KStandardAction::Cut)); |
1600 | QAction* deleteWithTrashShortcut = col->action("delete_shortcut" ); // see DolphinViewActionHandler |
1601 | |
1602 | KFileItemListProperties capabilities(list); |
1603 | const bool enableMoveToTrash = capabilities.isLocal() && capabilities.supportsMoving(); |
1604 | |
1605 | renameAction->setEnabled(capabilities.supportsMoving()); |
1606 | moveToTrashAction->setEnabled(enableMoveToTrash); |
1607 | deleteAction->setEnabled(capabilities.supportsDeleting()); |
1608 | deleteWithTrashShortcut->setEnabled(capabilities.supportsDeleting() && !enableMoveToTrash); |
1609 | cutAction->setEnabled(capabilities.supportsMoving()); |
1610 | } |
1611 | } |
1612 | |
1613 | void DolphinMainWindow::updateViewActions() |
1614 | { |
1615 | m_actionHandler->updateViewActions(); |
1616 | |
1617 | QAction* showFilterBarAction = actionCollection()->action("show_filter_bar" ); |
1618 | showFilterBarAction->setChecked(m_activeViewContainer->isFilterBarVisible()); |
1619 | |
1620 | updateSplitAction(); |
1621 | |
1622 | QAction* editableLocactionAction = actionCollection()->action("editable_location" ); |
1623 | const KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); |
1624 | editableLocactionAction->setChecked(urlNavigator->isUrlEditable()); |
1625 | } |
1626 | |
1627 | void DolphinMainWindow::updateGoActions() |
1628 | { |
1629 | QAction* goUpAction = actionCollection()->action(KStandardAction::name(KStandardAction::Up)); |
1630 | const KUrl currentUrl = m_activeViewContainer->url(); |
1631 | goUpAction->setEnabled(currentUrl.upUrl() != currentUrl); |
1632 | } |
1633 | |
1634 | void DolphinMainWindow::createControlButton() |
1635 | { |
1636 | if (m_controlButton) { |
1637 | return; |
1638 | } |
1639 | Q_ASSERT(!m_controlButton); |
1640 | |
1641 | m_controlButton = new QToolButton(this); |
1642 | m_controlButton->setIcon(KIcon("applications-system" )); |
1643 | m_controlButton->setText(i18nc("@action" , "Control" )); |
1644 | m_controlButton->setPopupMode(QToolButton::InstantPopup); |
1645 | m_controlButton->setToolButtonStyle(toolBar()->toolButtonStyle()); |
1646 | |
1647 | KMenu* = new KMenu(m_controlButton); |
1648 | connect(controlMenu, SIGNAL(aboutToShow()), this, SLOT(updateControlMenu())); |
1649 | |
1650 | m_controlButton->setMenu(controlMenu); |
1651 | |
1652 | toolBar()->addWidget(m_controlButton); |
1653 | connect(toolBar(), SIGNAL(iconSizeChanged(QSize)), |
1654 | m_controlButton, SLOT(setIconSize(QSize))); |
1655 | connect(toolBar(), SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)), |
1656 | m_controlButton, SLOT(setToolButtonStyle(Qt::ToolButtonStyle))); |
1657 | |
1658 | // The added widgets are owned by the toolbar and may get deleted when e.g. the toolbar |
1659 | // gets edited. In this case we must add them again. The adding is done asynchronously by |
1660 | // m_updateToolBarTimer. |
1661 | connect(m_controlButton, SIGNAL(destroyed()), this, SLOT(slotControlButtonDeleted())); |
1662 | m_updateToolBarTimer = new QTimer(this); |
1663 | m_updateToolBarTimer->setInterval(500); |
1664 | connect(m_updateToolBarTimer, SIGNAL(timeout()), this, SLOT(updateToolBar())); |
1665 | } |
1666 | |
1667 | void DolphinMainWindow::deleteControlButton() |
1668 | { |
1669 | delete m_controlButton; |
1670 | m_controlButton = 0; |
1671 | |
1672 | delete m_updateToolBarTimer; |
1673 | m_updateToolBarTimer = 0; |
1674 | } |
1675 | |
1676 | bool DolphinMainWindow::addActionToMenu(QAction* action, KMenu* ) |
1677 | { |
1678 | Q_ASSERT(action); |
1679 | Q_ASSERT(menu); |
1680 | |
1681 | const KToolBar* toolBarWidget = toolBar(); |
1682 | foreach (const QWidget* widget, action->associatedWidgets()) { |
1683 | if (widget == toolBarWidget) { |
1684 | return false; |
1685 | } |
1686 | } |
1687 | |
1688 | menu->addAction(action); |
1689 | return true; |
1690 | } |
1691 | |
1692 | void DolphinMainWindow::refreshViews() |
1693 | { |
1694 | foreach (DolphinTabPage* tabPage, m_viewTab) { |
1695 | tabPage->refreshViews(); |
1696 | } |
1697 | |
1698 | if (GeneralSettings::modifiedStartupSettings()) { |
1699 | // The startup settings have been changed by the user (see bug #254947). |
1700 | // Synchronize the split-view setting with the active view: |
1701 | const bool splitView = GeneralSettings::splitView(); |
1702 | m_viewTab.at(m_tabIndex)->setSplitViewEnabled(splitView); |
1703 | updateSplitAction(); |
1704 | } |
1705 | |
1706 | emit settingsChanged(); |
1707 | } |
1708 | |
1709 | void DolphinMainWindow::clearStatusBar() |
1710 | { |
1711 | m_activeViewContainer->statusBar()->resetToDefaultText(); |
1712 | } |
1713 | |
1714 | void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container) |
1715 | { |
1716 | connect(container, SIGNAL(showFilterBarChanged(bool)), |
1717 | this, SLOT(updateFilterBarAction(bool))); |
1718 | connect(container, SIGNAL(writeStateChanged(bool)), |
1719 | this, SLOT(slotWriteStateChanged(bool))); |
1720 | |
1721 | const DolphinView* view = container->view(); |
1722 | connect(view, SIGNAL(selectionChanged(KFileItemList)), |
1723 | this, SLOT(slotSelectionChanged(KFileItemList))); |
1724 | connect(view, SIGNAL(requestItemInfo(KFileItem)), |
1725 | this, SLOT(slotRequestItemInfo(KFileItem))); |
1726 | connect(view, SIGNAL(tabRequested(KUrl)), |
1727 | this, SLOT(openNewTab(KUrl))); |
1728 | connect(view, SIGNAL(requestContextMenu(QPoint,KFileItem,KUrl,QList<QAction*>)), |
1729 | this, SLOT(openContextMenu(QPoint,KFileItem,KUrl,QList<QAction*>))); |
1730 | connect(view, SIGNAL(directoryLoadingStarted()), |
1731 | this, SLOT(enableStopAction())); |
1732 | connect(view, SIGNAL(directoryLoadingCompleted()), |
1733 | this, SLOT(disableStopAction())); |
1734 | connect(view, SIGNAL(goBackRequested()), |
1735 | this, SLOT(goBack())); |
1736 | connect(view, SIGNAL(goForwardRequested()), |
1737 | this, SLOT(goForward())); |
1738 | |
1739 | const KUrlNavigator* navigator = container->urlNavigator(); |
1740 | connect(navigator, SIGNAL(urlChanged(KUrl)), |
1741 | this, SLOT(changeUrl(KUrl))); |
1742 | connect(navigator, SIGNAL(historyChanged()), |
1743 | this, SLOT(updateHistory())); |
1744 | connect(navigator, SIGNAL(editableStateChanged(bool)), |
1745 | this, SLOT(slotEditableStateChanged(bool))); |
1746 | connect(navigator, SIGNAL(tabRequested(KUrl)), |
1747 | this, SLOT(openNewTab(KUrl))); |
1748 | } |
1749 | |
1750 | void DolphinMainWindow::updateSplitAction() |
1751 | { |
1752 | QAction* splitAction = actionCollection()->action("split_view" ); |
1753 | const DolphinTabPage* tabPage = m_viewTab.at(m_tabIndex); |
1754 | if (tabPage->splitViewEnabled()) { |
1755 | if (tabPage->primaryViewActive()) { |
1756 | splitAction->setText(i18nc("@action:intoolbar Close left view" , "Close" )); |
1757 | splitAction->setToolTip(i18nc("@info" , "Close left view" )); |
1758 | splitAction->setIcon(KIcon("view-left-close" )); |
1759 | } else { |
1760 | splitAction->setText(i18nc("@action:intoolbar Close right view" , "Close" )); |
1761 | splitAction->setToolTip(i18nc("@info" , "Close right view" )); |
1762 | splitAction->setIcon(KIcon("view-right-close" )); |
1763 | } |
1764 | } else { |
1765 | splitAction->setText(i18nc("@action:intoolbar Split view" , "Split" )); |
1766 | splitAction->setToolTip(i18nc("@info" , "Split view" )); |
1767 | splitAction->setIcon(KIcon("view-right-new" )); |
1768 | } |
1769 | } |
1770 | |
1771 | QString DolphinMainWindow::tabName(const KUrl& url) const |
1772 | { |
1773 | QString name; |
1774 | if (url.equals(KUrl("file:///" ))) { |
1775 | name = '/'; |
1776 | } else { |
1777 | name = url.fileName(); |
1778 | if (name.isEmpty()) { |
1779 | name = url.protocol(); |
1780 | } else { |
1781 | // Make sure that a '&' inside the directory name is displayed correctly |
1782 | // and not misinterpreted as a keyboard shortcut in QTabBar::setTabText() |
1783 | name.replace('&', "&&" ); |
1784 | } |
1785 | } |
1786 | return name; |
1787 | } |
1788 | |
1789 | bool DolphinMainWindow::isKompareInstalled() const |
1790 | { |
1791 | static bool initialized = false; |
1792 | static bool installed = false; |
1793 | if (!initialized) { |
1794 | // TODO: maybe replace this approach later by using a menu |
1795 | // plugin like kdiff3plugin.cpp |
1796 | installed = !KGlobal::dirs()->findExe("kompare" ).isEmpty(); |
1797 | initialized = true; |
1798 | } |
1799 | return installed; |
1800 | } |
1801 | |
1802 | void DolphinMainWindow::setUrlAsCaption(const KUrl& url) |
1803 | { |
1804 | QString caption; |
1805 | if (!url.isLocalFile()) { |
1806 | caption.append(url.protocol() + " - " ); |
1807 | if (url.hasHost()) { |
1808 | caption.append(url.host() + " - " ); |
1809 | } |
1810 | } |
1811 | |
1812 | const QString fileName = url.fileName().isEmpty() ? "/" : url.fileName(); |
1813 | caption.append(fileName); |
1814 | |
1815 | setCaption(caption); |
1816 | } |
1817 | |
1818 | QString DolphinMainWindow::squeezedText(const QString& text) const |
1819 | { |
1820 | const QFontMetrics fm = fontMetrics(); |
1821 | return fm.elidedText(text, Qt::ElideMiddle, fm.maxWidth() * 10); |
1822 | } |
1823 | |
1824 | void DolphinMainWindow::createPanelAction(const KIcon& icon, |
1825 | const QKeySequence& shortcut, |
1826 | QAction* dockAction, |
1827 | const QString& actionName) |
1828 | { |
1829 | KAction* panelAction = actionCollection()->addAction(actionName); |
1830 | panelAction->setCheckable(true); |
1831 | panelAction->setChecked(dockAction->isChecked()); |
1832 | panelAction->setText(dockAction->text()); |
1833 | panelAction->setIcon(icon); |
1834 | panelAction->setShortcut(shortcut); |
1835 | |
1836 | connect(panelAction, SIGNAL(triggered()), dockAction, SLOT(trigger())); |
1837 | connect(dockAction, SIGNAL(toggled(bool)), panelAction, SLOT(setChecked(bool))); |
1838 | } |
1839 | |
1840 | DolphinMainWindow::UndoUiInterface::UndoUiInterface() : |
1841 | KIO::FileUndoManager::UiInterface() |
1842 | { |
1843 | } |
1844 | |
1845 | DolphinMainWindow::UndoUiInterface::~UndoUiInterface() |
1846 | { |
1847 | } |
1848 | |
1849 | void DolphinMainWindow::UndoUiInterface::jobError(KIO::Job* job) |
1850 | { |
1851 | DolphinMainWindow* mainWin= qobject_cast<DolphinMainWindow *>(parentWidget()); |
1852 | if (mainWin) { |
1853 | DolphinViewContainer* container = mainWin->activeViewContainer(); |
1854 | container->showMessage(job->errorString(), DolphinViewContainer::Error); |
1855 | } else { |
1856 | KIO::FileUndoManager::UiInterface::jobError(job); |
1857 | } |
1858 | } |
1859 | |
1860 | #include "dolphinmainwindow.moc" |
1861 | |