]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphinmainwindow.cpp
Applied some patches found by EBN (thanks to Nicolas Lécureuil for the patches!).
[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
24 #include <assert.h>
25
26 #include <kactioncollection.h>
27 #include <ktoggleaction.h>
28 #include <kbookmarkmanager.h>
29 #include <kglobal.h>
30 #include <kpropertiesdialog.h>
31 #include <kicon.h>
32 #include <kiconloader.h>
33 #include <kdeversion.h>
34 #include <kstatusbar.h>
35 #include <kio/netaccess.h>
36 #include <kfiledialog.h>
37 #include <kconfig.h>
38 #include <kurl.h>
39 #include <kaction.h>
40 #include <kstandardaction.h>
41 #include <kmenu.h>
42 #include <kio/renamedialog.h>
43 #include <kinputdialog.h>
44 #include <kshell.h>
45 #include <kdesktopfile.h>
46 #include <kstandarddirs.h>
47 #include <kprotocolinfo.h>
48 #include <kmessagebox.h>
49 #include <kservice.h>
50 #include <kstandarddirs.h>
51 #include <krun.h>
52 #include <klocale.h>
53 #include <konqmimedata.h>
54
55 #include <qclipboard.h>
56 #include <q3dragobject.h>
57 //Added by qt3to4:
58 #include <Q3ValueList>
59 #include <QCloseEvent>
60 #include <QSplitter>
61 #include <QDockWidget>
62
63 #include "urlnavigator.h"
64 #include "viewpropertiesdialog.h"
65 #include "viewproperties.h"
66 #include "dolphinsettings.h"
67 #include "dolphinsettingsdialog.h"
68 #include "dolphinstatusbar.h"
69 #include "dolphinapplication.h"
70 #include "undomanager.h"
71 #include "progressindicator.h"
72 #include "dolphinsettings.h"
73 #include "bookmarkssidebarpage.h"
74 #include "infosidebarpage.h"
75 #include "generalsettings.h"
76 #include "dolphinapplication.h"
77
78
79 DolphinMainWindow::DolphinMainWindow() :
80 KMainWindow(0),
81 m_splitter(0),
82 m_activeView(0)
83 {
84 setObjectName("Dolphin");
85 m_view[PrimaryIdx] = 0;
86 m_view[SecondaryIdx] = 0;
87 }
88
89 DolphinMainWindow::~DolphinMainWindow()
90 {
91 qDeleteAll(m_fileGroupActions);
92 m_fileGroupActions.clear();
93
94 DolphinApplication::app()->removeMainWindow(this);
95 }
96
97 void DolphinMainWindow::setActiveView(DolphinView* view)
98 {
99 assert((view == m_view[PrimaryIdx]) || (view == m_view[SecondaryIdx]));
100 if (m_activeView == view) {
101 return;
102 }
103
104 m_activeView = view;
105
106 updateHistory();
107 updateEditActions();
108 updateViewActions();
109 updateGoActions();
110
111 setCaption(m_activeView->url().fileName());
112
113 emit activeViewChanged();
114 }
115
116 void DolphinMainWindow::dropUrls(const KUrl::List& urls,
117 const KUrl& destination)
118 {
119 m_dropDestination = destination;
120 m_droppedUrls = urls;
121
122 /* KDE4-TODO
123 const ButtonState keyboardState = KApplication::keyboardMouseState();
124 const bool shiftPressed = (keyboardState & ShiftButton) > 0;
125 const bool controlPressed = (keyboardState & ControlButton) > 0;
126
127
128
129 if (shiftPressed && controlPressed) {
130 // shortcut for 'Linke Here' is used
131 selectedIndex = 2;
132 }
133 else if (controlPressed) {
134 // shortcut for 'Copy Here' is used
135 selectedIndex = 1;
136 }
137 else if (shiftPressed) {
138 // shortcut for 'Move Here' is used
139 selectedIndex = 0;
140 }
141 else*/ {
142 // no shortcut is used, hence open a popup menu
143 KMenu popup(this);
144
145 QAction* moveAction = popup.addAction(SmallIcon("goto"), i18n("&Move Here"));
146 connect(moveAction, SIGNAL(triggered()), this, SLOT(moveDroppedItems()));
147
148 QAction* copyAction = popup.addAction(SmallIcon("editcopy"), i18n( "&Copy Here" ));
149 connect(copyAction, SIGNAL(triggered()), this, SLOT(copyDroppedItems()));
150
151 QAction* linkAction = popup.addAction(i18n("&Link Here"));
152 connect(linkAction, SIGNAL(triggered()), this, SLOT(linkDroppedItems()));
153
154 QAction* cancelAction = popup.addAction(SmallIcon("stop"), i18n("Cancel"));
155 popup.insertSeparator(cancelAction);
156
157 popup.exec(QCursor::pos());
158 }
159
160 m_droppedUrls.clear();
161 }
162
163 void DolphinMainWindow::refreshViews()
164 {
165 const bool split = DolphinSettings::instance().generalSettings()->splitView();
166 const bool isPrimaryViewActive = (m_activeView == m_view[PrimaryIdx]);
167 KUrl url;
168 for (int i = PrimaryIdx; i <= SecondaryIdx; ++i) {
169 if (m_view[i] != 0) {
170 url = m_view[i]->url();
171
172 // delete view instance...
173 m_view[i]->close();
174 m_view[i]->deleteLater();
175 m_view[i] = 0;
176 }
177
178 if (split || (i == PrimaryIdx)) {
179 // ... and recreate it
180 ViewProperties props(url);
181 m_view[i] = new DolphinView(this,
182 m_splitter,
183 url,
184 props.viewMode(),
185 props.showHiddenFiles());
186 connectViewSignals(i);
187 m_view[i]->show();
188 }
189 }
190
191 m_activeView = isPrimaryViewActive ? m_view[PrimaryIdx] : m_view[SecondaryIdx];
192 assert(m_activeView != 0);
193
194 updateViewActions();
195 emit activeViewChanged();
196 }
197
198 void DolphinMainWindow::slotViewModeChanged()
199 {
200 updateViewActions();
201 }
202
203 void DolphinMainWindow::slotShowHiddenFilesChanged()
204 {
205 KToggleAction* showHiddenFilesAction =
206 static_cast<KToggleAction*>(actionCollection()->action("show_hidden_files"));
207 showHiddenFilesAction->setChecked(m_activeView->showHiddenFiles());
208 }
209
210 void DolphinMainWindow::slotSortingChanged(DolphinView::Sorting sorting)
211 {
212 QAction* action = 0;
213 switch (sorting) {
214 case DolphinView::SortByName:
215 action = actionCollection()->action("by_name");
216 break;
217 case DolphinView::SortBySize:
218 action = actionCollection()->action("by_size");
219 break;
220 case DolphinView::SortByDate:
221 action = actionCollection()->action("by_date");
222 break;
223 default:
224 break;
225 }
226
227 if (action != 0) {
228 KToggleAction* toggleAction = static_cast<KToggleAction*>(action);
229 toggleAction->setChecked(true);
230 }
231 }
232
233 void DolphinMainWindow::slotSortOrderChanged(Qt::SortOrder order)
234 {
235 KToggleAction* descending = static_cast<KToggleAction*>(actionCollection()->action("descending"));
236 const bool sortDescending = (order == Qt::Descending);
237 descending->setChecked(sortDescending);
238 }
239
240 void DolphinMainWindow::slotSelectionChanged()
241 {
242 updateEditActions();
243
244 assert(m_view[PrimaryIdx] != 0);
245 int selectedUrlsCount = m_view[PrimaryIdx]->selectedUrls().count();
246 if (m_view[SecondaryIdx] != 0) {
247 selectedUrlsCount += m_view[SecondaryIdx]->selectedUrls().count();
248 }
249
250 QAction* compareFilesAction = actionCollection()->action("compare_files");
251 compareFilesAction->setEnabled(selectedUrlsCount == 2);
252
253 m_activeView->updateStatusBar();
254
255 emit selectionChanged();
256 }
257
258 void DolphinMainWindow::slotHistoryChanged()
259 {
260 updateHistory();
261 }
262
263 void DolphinMainWindow::slotUrlChanged(const KUrl& url)
264 {
265 updateEditActions();
266 updateGoActions();
267 setCaption(url.fileName());
268 }
269
270 void DolphinMainWindow::updateFilterBarAction(bool show)
271 {
272 KToggleAction* showFilterBarAction =
273 static_cast<KToggleAction*>(actionCollection()->action("show_filter_bar"));
274 showFilterBarAction->setChecked(show);
275 }
276
277 void DolphinMainWindow::redo()
278 {
279 UndoManager::instance().redo(this);
280 }
281
282 void DolphinMainWindow::undo()
283 {
284 UndoManager::instance().undo(this);
285 }
286
287 void DolphinMainWindow::openNewMainWindow()
288 {
289 DolphinApplication::app()->createMainWindow()->show();
290 }
291
292 void DolphinMainWindow::moveDroppedItems()
293 {
294 moveUrls(m_droppedUrls, m_dropDestination);
295 }
296
297 void DolphinMainWindow::copyDroppedItems()
298 {
299 copyUrls(m_droppedUrls, m_dropDestination);
300 }
301
302 void DolphinMainWindow::linkDroppedItems()
303 {
304 KIO::Job* job = KIO::link(m_droppedUrls, m_dropDestination);
305 addPendingUndoJob(job, DolphinCommand::Link, m_droppedUrls, m_dropDestination);
306 }
307
308 void DolphinMainWindow::closeEvent(QCloseEvent* event)
309 {
310 DolphinSettings& settings = DolphinSettings::instance();
311 GeneralSettings* generalSettings = settings.generalSettings();
312 generalSettings->setFirstRun(false);
313
314 settings.save();
315
316 // TODO: I assume there will be a generic way in KDE 4 to store the docks
317 // of the main window. In the meantime they are stored manually:
318 QString filename = KStandardDirs::locateLocal("data", KGlobal::instance()->instanceName());
319 filename.append("/panels_layout");
320 QFile file(filename);
321 if (file.open(QIODevice::WriteOnly)) {
322 QByteArray data = saveState();
323 file.write(data);
324 file.close();
325 }
326
327 KMainWindow::closeEvent(event);
328 }
329
330 void DolphinMainWindow::saveProperties(KConfig* config)
331 {
332 config->setGroup("Primary view");
333 config->writeEntry("Url", m_view[PrimaryIdx]->url().url());
334 config->writeEntry("Editable Url", m_view[PrimaryIdx]->isUrlEditable());
335 if (m_view[SecondaryIdx] != 0) {
336 config->setGroup("Secondary view");
337 config->writeEntry("Url", m_view[SecondaryIdx]->url().url());
338 config->writeEntry("Editable Url", m_view[SecondaryIdx]->isUrlEditable());
339 }
340 }
341
342 void DolphinMainWindow::readProperties(KConfig* config)
343 {
344 config->setGroup("Primary view");
345 m_view[PrimaryIdx]->setUrl(config->readEntry("Url"));
346 m_view[PrimaryIdx]->setUrlEditable(config->readEntry("Editable Url", false));
347 if (config->hasGroup("Secondary view")) {
348 config->setGroup("Secondary view");
349 if (m_view[SecondaryIdx] == 0) {
350 toggleSplitView();
351 }
352 m_view[SecondaryIdx]->setUrl(config->readEntry("Url"));
353 m_view[SecondaryIdx]->setUrlEditable(config->readEntry("Editable Url", false));
354 }
355 else if (m_view[SecondaryIdx] != 0) {
356 toggleSplitView();
357 }
358 }
359
360 void DolphinMainWindow::createFolder()
361 {
362 // Parts of the following code have been taken
363 // from the class KonqPopupMenu located in
364 // libqonq/konq_popupmenu.h of Konqueror.
365 // (Copyright (C) 2000 David Faure <faure@kde.org>,
366 // Copyright (C) 2001 Holger Freyther <freyther@yahoo.com>)
367
368 clearStatusBar();
369
370 DolphinStatusBar* statusBar = m_activeView->statusBar();
371 const KUrl baseUrl(m_activeView->url());
372
373 QString name(i18n("New Folder"));
374 baseUrl.path(KUrl::AddTrailingSlash);
375
376
377 if (baseUrl.isLocalFile() && QFileInfo(baseUrl.path(KUrl::AddTrailingSlash) + name).exists()) {
378 name = KIO::RenameDialog::suggestName(baseUrl, i18n("New Folder"));
379 }
380
381 bool ok = false;
382 name = KInputDialog::getText(i18n("New Folder"),
383 i18n("Enter folder name:" ),
384 name,
385 &ok,
386 this);
387
388 if (!ok) {
389 // the user has pressed 'Cancel'
390 return;
391 }
392
393 assert(!name.isEmpty());
394
395 KUrl url;
396 if ((name[0] == '/') || (name[0] == '~')) {
397 url.setPath(KShell::tildeExpand(name));
398 }
399 else {
400 name = KIO::encodeFileName(name);
401 url = baseUrl;
402 url.addPath(name);
403 }
404 ok = KIO::NetAccess::mkdir(url, this);
405
406 // TODO: provide message type hint
407 if (ok) {
408 statusBar->setMessage(i18n("Created folder %1.",url.path()),
409 DolphinStatusBar::OperationCompleted);
410
411 DolphinCommand command(DolphinCommand::CreateFolder, KUrl::List(), url);
412 UndoManager::instance().addCommand(command);
413 }
414 else {
415 // Creating of the folder has been failed. Check whether the creating
416 // has been failed because a folder with the same name exists...
417 if (KIO::NetAccess::exists(url, true, this)) {
418 statusBar->setMessage(i18n("A folder named %1 already exists.",url.path()),
419 DolphinStatusBar::Error);
420 }
421 else {
422 statusBar->setMessage(i18n("Creating of folder %1 failed.",url.path()),
423 DolphinStatusBar::Error);
424 }
425
426 }
427 }
428
429 void DolphinMainWindow::createFile()
430 {
431 // Parts of the following code have been taken
432 // from the class KonqPopupMenu located in
433 // libqonq/konq_popupmenu.h of Konqueror.
434 // (Copyright (C) 2000 David Faure <faure@kde.org>,
435 // Copyright (C) 2001 Holger Freyther <freyther@yahoo.com>)
436
437 clearStatusBar();
438
439 // TODO: const Entry& entry = m_createFileTemplates[QString(sender->name())];
440 // should be enough. Anyway: the implementation of [] does a linear search internally too.
441 KSortableList<CreateFileEntry, QString>::ConstIterator it = m_createFileTemplates.begin();
442 KSortableList<CreateFileEntry, QString>::ConstIterator end = m_createFileTemplates.end();
443
444 const QString senderName(sender()->objectName());
445 bool found = false;
446 CreateFileEntry entry;
447 while (!found && (it != end)) {
448 if ((*it).key() == senderName) {
449 entry = (*it).value();
450 found = true;
451 }
452 else {
453 ++it;
454 }
455 }
456
457 DolphinStatusBar* statusBar = m_activeView->statusBar();
458 if (!found || !QFile::exists(entry.templatePath)) {
459 statusBar->setMessage(i18n("Could not create file."), DolphinStatusBar::Error);
460 return;
461 }
462
463 // Get the source path of the template which should be copied.
464 // The source path is part of the Url entry of the desktop file.
465 const int pos = entry.templatePath.lastIndexOf('/');
466 QString sourcePath(entry.templatePath.left(pos + 1));
467 sourcePath += KDesktopFile(entry.templatePath, true).readPathEntry("Url");
468
469 QString name(i18n(entry.name.toAscii()));
470 // Most entry names end with "..." (e. g. "HTML File..."), which is ok for
471 // menus but no good choice for a new file name -> remove the dots...
472 name.replace("...", QString::null);
473
474 // add the file extension to the name
475 name.append(sourcePath.right(sourcePath.length() - sourcePath.lastIndexOf('.')));
476
477 // Check whether a file with the current name already exists. If yes suggest automatically
478 // a unique file name (e. g. "HTML File" will be replaced by "HTML File_1").
479 const KUrl viewUrl(m_activeView->url());
480 const bool fileExists = viewUrl.isLocalFile() &&
481 QFileInfo(viewUrl.path(KUrl::AddTrailingSlash) + KIO::encodeFileName(name)).exists();
482 if (fileExists) {
483 name = KIO::RenameDialog::suggestName(viewUrl, name);
484 }
485
486 // let the user change the suggested file name
487 bool ok = false;
488 name = KInputDialog::getText(entry.name,
489 entry.comment,
490 name,
491 &ok,
492 this);
493 if (!ok) {
494 // the user has pressed 'Cancel'
495 return;
496 }
497
498 // before copying the template to the destination path check whether a file
499 // with the given name already exists
500 const QString destPath(viewUrl.pathOrUrl() + "/" + KIO::encodeFileName(name));
501 const KUrl destUrl(destPath);
502 if (KIO::NetAccess::exists(destUrl, false, this)) {
503 statusBar->setMessage(i18n("A file named %1 already exists.",name),
504 DolphinStatusBar::Error);
505 return;
506 }
507
508 // copy the template to the destination path
509 const KUrl sourceUrl(sourcePath);
510 KIO::CopyJob* job = KIO::copyAs(sourceUrl, destUrl);
511 job->setDefaultPermissions(true);
512 if (KIO::NetAccess::synchronousRun(job, this)) {
513 statusBar->setMessage(i18n("Created file %1.",name),
514 DolphinStatusBar::OperationCompleted);
515
516 KUrl::List list;
517 list.append(sourceUrl);
518 DolphinCommand command(DolphinCommand::CreateFile, list, destUrl);
519 UndoManager::instance().addCommand(command);
520
521 }
522 else {
523 statusBar->setMessage(i18n("Creating of file %1 failed.",name),
524 DolphinStatusBar::Error);
525 }
526 }
527
528 void DolphinMainWindow::rename()
529 {
530 clearStatusBar();
531 m_activeView->renameSelectedItems();
532 }
533
534 void DolphinMainWindow::moveToTrash()
535 {
536 clearStatusBar();
537 KUrl::List selectedUrls = m_activeView->selectedUrls();
538 KIO::Job* job = KIO::trash(selectedUrls);
539 addPendingUndoJob(job, DolphinCommand::Trash, selectedUrls, m_activeView->url());
540 }
541
542 void DolphinMainWindow::deleteItems()
543 {
544 clearStatusBar();
545
546 KUrl::List list = m_activeView->selectedUrls();
547 const uint itemCount = list.count();
548 assert(itemCount >= 1);
549
550 QString text;
551 if (itemCount > 1) {
552 text = i18n("Do you really want to delete the %1 selected items?",itemCount);
553 }
554 else {
555 const KUrl& url = list.first();
556 text = i18n("Do you really want to delete '%1'?",url.fileName());
557 }
558
559 const bool del = KMessageBox::warningContinueCancel(this,
560 text,
561 QString::null,
562 KGuiItem(i18n("Delete"), KIcon("editdelete"))
563 ) == KMessageBox::Continue;
564 if (del) {
565 KIO::Job* job = KIO::del(list);
566 connect(job, SIGNAL(result(KJob*)),
567 this, SLOT(slotHandleJobError(KJob*)));
568 connect(job, SIGNAL(result(KJob*)),
569 this, SLOT(slotDeleteFileFinished(KJob*)));
570 }
571 }
572
573 void DolphinMainWindow::properties()
574 {
575 const KFileItemList list = m_activeView->selectedItems();
576 new KPropertiesDialog(list, this);
577 }
578
579 void DolphinMainWindow::quit()
580 {
581 close();
582 }
583
584 void DolphinMainWindow::slotHandleJobError(KJob* job)
585 {
586 if (job->error() != 0) {
587 m_activeView->statusBar()->setMessage(job->errorString(),
588 DolphinStatusBar::Error);
589 }
590 }
591
592 void DolphinMainWindow::slotDeleteFileFinished(KJob* job)
593 {
594 if (job->error() == 0) {
595 m_activeView->statusBar()->setMessage(i18n("Delete operation completed."),
596 DolphinStatusBar::OperationCompleted);
597
598 // TODO: In opposite to the 'Move to Trash' operation in the class KFileIconView
599 // no rearranging of the item position is done when a file has been deleted.
600 // This is bypassed by reloading the view, but it might be worth to investigate
601 // deeper for the root of this issue.
602 m_activeView->reload();
603 }
604 }
605
606 void DolphinMainWindow::slotUndoAvailable(bool available)
607 {
608 QAction* undoAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::Undo));
609 if (undoAction != 0) {
610 undoAction->setEnabled(available);
611 }
612 }
613
614 void DolphinMainWindow::slotUndoTextChanged(const QString& text)
615 {
616 QAction* undoAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::Undo));
617 if (undoAction != 0) {
618 undoAction->setText(text);
619 }
620 }
621
622 void DolphinMainWindow::slotRedoAvailable(bool available)
623 {
624 QAction* redoAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::Redo));
625 if (redoAction != 0) {
626 redoAction->setEnabled(available);
627 }
628 }
629
630 void DolphinMainWindow::slotRedoTextChanged(const QString& text)
631 {
632 QAction* redoAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::Redo));
633 if (redoAction != 0) {
634 redoAction->setText(text);
635 }
636 }
637
638 void DolphinMainWindow::cut()
639 {
640 QMimeData* mimeData = new QMimeData();
641 const KUrl::List kdeUrls = m_activeView->selectedUrls();
642 const KUrl::List mostLocalUrls;
643 KonqMimeData::populateMimeData(mimeData, kdeUrls, mostLocalUrls, true);
644 QApplication::clipboard()->setMimeData(mimeData);
645 }
646
647 void DolphinMainWindow::copy()
648 {
649 QMimeData* mimeData = new QMimeData();
650 const KUrl::List kdeUrls = m_activeView->selectedUrls();
651 const KUrl::List mostLocalUrls;
652 KonqMimeData::populateMimeData(mimeData, kdeUrls, mostLocalUrls, false);
653
654 QApplication::clipboard()->setMimeData(mimeData);
655 }
656
657 void DolphinMainWindow::paste()
658 {
659 QClipboard* clipboard = QApplication::clipboard();
660 const QMimeData* mimeData = clipboard->mimeData();
661
662 clearStatusBar();
663
664 const KUrl::List sourceUrls = KUrl::List::fromMimeData(mimeData);
665
666 // per default the pasting is done into the current Url of the view
667 KUrl destUrl(m_activeView->url());
668
669 // check whether the pasting should be done into a selected directory
670 KUrl::List selectedUrls = m_activeView->selectedUrls();
671 if (selectedUrls.count() == 1) {
672 const KFileItem fileItem(S_IFDIR,
673 KFileItem::Unknown,
674 selectedUrls.first(),
675 true);
676 if (fileItem.isDir()) {
677 // only one item is selected which is a directory, hence paste
678 // into this directory
679 destUrl = selectedUrls.first();
680 }
681 }
682
683 if (KonqMimeData::decodeIsCutSelection(mimeData)) {
684 moveUrls(sourceUrls, destUrl);
685 clipboard->clear();
686 }
687 else {
688 copyUrls(sourceUrls, destUrl);
689 }
690 }
691
692 void DolphinMainWindow::updatePasteAction()
693 {
694 QAction* pasteAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::Paste));
695 if (pasteAction == 0) {
696 return;
697 }
698
699 QString text(i18n("Paste"));
700 QClipboard* clipboard = QApplication::clipboard();
701 const QMimeData* mimeData = clipboard->mimeData();
702
703 KUrl::List urls = KUrl::List::fromMimeData(mimeData);
704 if (!urls.isEmpty()) {
705 pasteAction->setEnabled(true);
706
707 const int count = urls.count();
708 if (count == 1) {
709 pasteAction->setText(i18n("Paste 1 File"));
710 }
711 else {
712 pasteAction->setText(i18n("Paste %1 Files").arg(count));
713 }
714 }
715 else {
716 pasteAction->setEnabled(false);
717 pasteAction->setText(i18n("Paste"));
718 }
719
720 if (pasteAction->isEnabled()) {
721 KUrl::List urls = m_activeView->selectedUrls();
722 const uint count = urls.count();
723 if (count > 1) {
724 // pasting should not be allowed when more than one file
725 // is selected
726 pasteAction->setEnabled(false);
727 }
728 else if (count == 1) {
729 // Only one file is selected. Pasting is only allowed if this
730 // file is a directory.
731 // TODO: this doesn't work with remote protocols; instead we need a
732 // m_activeView->selectedFileItems() to get the real KFileItems
733 const KFileItem fileItem(S_IFDIR,
734 KFileItem::Unknown,
735 urls.first(),
736 true);
737 pasteAction->setEnabled(fileItem.isDir());
738 }
739 }
740 }
741
742 void DolphinMainWindow::selectAll()
743 {
744 clearStatusBar();
745 m_activeView->selectAll();
746 }
747
748 void DolphinMainWindow::invertSelection()
749 {
750 clearStatusBar();
751 m_activeView->invertSelection();
752 }
753 void DolphinMainWindow::setIconsView()
754 {
755 m_activeView->setMode(DolphinView::IconsView);
756 }
757
758 void DolphinMainWindow::setDetailsView()
759 {
760 m_activeView->setMode(DolphinView::DetailsView);
761 }
762
763 void DolphinMainWindow::sortByName()
764 {
765 m_activeView->setSorting(DolphinView::SortByName);
766 }
767
768 void DolphinMainWindow::sortBySize()
769 {
770 m_activeView->setSorting(DolphinView::SortBySize);
771 }
772
773 void DolphinMainWindow::sortByDate()
774 {
775 m_activeView->setSorting(DolphinView::SortByDate);
776 }
777
778 void DolphinMainWindow::toggleSortOrder()
779 {
780 const Qt::SortOrder order = (m_activeView->sortOrder() == Qt::Ascending) ?
781 Qt::Descending :
782 Qt::Ascending;
783 m_activeView->setSortOrder(order);
784 }
785
786 void DolphinMainWindow::toggleSplitView()
787 {
788 if (m_view[SecondaryIdx] == 0) {
789 const int newWidth = (m_view[PrimaryIdx]->width() - m_splitter->handleWidth()) / 2;
790 // create a secondary view
791 m_view[SecondaryIdx] = new DolphinView(this,
792 0,
793 m_view[PrimaryIdx]->url(),
794 m_view[PrimaryIdx]->mode(),
795 m_view[PrimaryIdx]->showHiddenFiles());
796 connectViewSignals(SecondaryIdx);
797 m_splitter->addWidget(m_view[SecondaryIdx]);
798 m_splitter->setSizes(QList<int>() << newWidth << newWidth);
799 m_view[SecondaryIdx]->show();
800 }
801 else {
802 // remove secondary view
803 if (m_activeView == m_view[PrimaryIdx]) {
804 m_view[SecondaryIdx]->close();
805 m_view[SecondaryIdx]->deleteLater();
806 m_view[SecondaryIdx] = 0;
807 setActiveView(m_view[PrimaryIdx]);
808 }
809 else {
810 // The secondary view is active, hence from the users point of view
811 // the content of the secondary view should be moved to the primary view.
812 // From an implementation point of view it is more efficient to close
813 // the primary view and exchange the internal pointers afterwards.
814 m_view[PrimaryIdx]->close();
815 delete m_view[PrimaryIdx];
816 m_view[PrimaryIdx] = m_view[SecondaryIdx];
817 m_view[SecondaryIdx] = 0;
818 setActiveView(m_view[PrimaryIdx]);
819 }
820 }
821 }
822
823 void DolphinMainWindow::reloadView()
824 {
825 clearStatusBar();
826 m_activeView->reload();
827 }
828
829 void DolphinMainWindow::stopLoading()
830 {
831 }
832
833 void DolphinMainWindow::togglePreview()
834 {
835 clearStatusBar();
836
837 const KToggleAction* showPreviewAction =
838 static_cast<KToggleAction*>(actionCollection()->action("show_preview"));
839 const bool show = showPreviewAction->isChecked();
840 m_activeView->setShowPreview(show);
841 }
842
843 void DolphinMainWindow::toggleShowHiddenFiles()
844 {
845 clearStatusBar();
846
847 const KToggleAction* showHiddenFilesAction =
848 static_cast<KToggleAction*>(actionCollection()->action("show_hidden_files"));
849 const bool show = showHiddenFilesAction->isChecked();
850 m_activeView->setShowHiddenFiles(show);
851 }
852
853 void DolphinMainWindow::showFilterBar()
854 {
855 const KToggleAction* showFilterBarAction =
856 static_cast<KToggleAction*>(actionCollection()->action("show_filter_bar"));
857 const bool show = showFilterBarAction->isChecked();
858 m_activeView->slotShowFilterBar(show);
859 }
860
861 void DolphinMainWindow::zoomIn()
862 {
863 m_activeView->zoomIn();
864 updateViewActions();
865 }
866
867 void DolphinMainWindow::zoomOut()
868 {
869 m_activeView->zoomOut();
870 updateViewActions();
871 }
872
873 void DolphinMainWindow::toggleEditLocation()
874 {
875 clearStatusBar();
876
877 KToggleAction* action = static_cast<KToggleAction*>(actionCollection()->action("editable_location"));
878
879 bool editOrBrowse = action->isChecked();
880 // action->setChecked(action->setChecked);
881 m_activeView->setUrlEditable(editOrBrowse);
882 }
883
884 void DolphinMainWindow::editLocation()
885 {
886 KToggleAction* action = static_cast<KToggleAction*>(actionCollection()->action("editable_location"));
887 action->setChecked(true);
888 m_activeView->setUrlEditable(true);
889 }
890
891 void DolphinMainWindow::adjustViewProperties()
892 {
893 clearStatusBar();
894 ViewPropertiesDialog dlg(m_activeView);
895 dlg.exec();
896 }
897
898 void DolphinMainWindow::goBack()
899 {
900 clearStatusBar();
901 m_activeView->goBack();
902 }
903
904 void DolphinMainWindow::goForward()
905 {
906 clearStatusBar();
907 m_activeView->goForward();
908 }
909
910 void DolphinMainWindow::goUp()
911 {
912 clearStatusBar();
913 m_activeView->goUp();
914 }
915
916 void DolphinMainWindow::goHome()
917 {
918 clearStatusBar();
919 m_activeView->goHome();
920 }
921
922 void DolphinMainWindow::openTerminal()
923 {
924 QString command("konsole --workdir \"");
925 command.append(m_activeView->url().path());
926 command.append('\"');
927
928 KRun::runCommand(command, "Konsole", "konsole");
929 }
930
931 void DolphinMainWindow::findFile()
932 {
933 KRun::run("kfind", m_activeView->url());
934 }
935
936 void DolphinMainWindow::compareFiles()
937 {
938 // The method is only invoked if exactly 2 files have
939 // been selected. The selected files may be:
940 // - both in the primary view
941 // - both in the secondary view
942 // - one in the primary view and the other in the secondary
943 // view
944 assert(m_view[PrimaryIdx] != 0);
945
946 KUrl urlA;
947 KUrl urlB;
948 KUrl::List urls = m_view[PrimaryIdx]->selectedUrls();
949
950 switch (urls.count()) {
951 case 0: {
952 assert(m_view[SecondaryIdx] != 0);
953 urls = m_view[SecondaryIdx]->selectedUrls();
954 assert(urls.count() == 2);
955 urlA = urls[0];
956 urlB = urls[1];
957 break;
958 }
959
960 case 1: {
961 urlA = urls[0];
962 assert(m_view[SecondaryIdx] != 0);
963 urls = m_view[SecondaryIdx]->selectedUrls();
964 assert(urls.count() == 1);
965 urlB = urls[0];
966 break;
967 }
968
969 case 2: {
970 urlA = urls[0];
971 urlB = urls[1];
972 break;
973 }
974
975 default: {
976 // may not happen: compareFiles may only get invoked if 2
977 // files are selected
978 assert(false);
979 }
980 }
981
982 QString command("kompare -c \"");
983 command.append(urlA.pathOrUrl());
984 command.append("\" \"");
985 command.append(urlB.pathOrUrl());
986 command.append('\"');
987 KRun::runCommand(command, "Kompare", "kompare");
988
989 }
990
991 void DolphinMainWindow::editSettings()
992 {
993 // TODO: make a static method for opening the settings dialog
994 DolphinSettingsDialog dlg(this);
995 dlg.exec();
996 }
997
998 void DolphinMainWindow::addUndoOperation(KJob* job)
999 {
1000 if (job->error() != 0) {
1001 slotHandleJobError(job);
1002 }
1003 else {
1004 const int id = job->progressId();
1005
1006 // set iterator to the executed command with the current id...
1007 Q3ValueList<UndoInfo>::Iterator it = m_pendingUndoJobs.begin();
1008 const Q3ValueList<UndoInfo>::Iterator end = m_pendingUndoJobs.end();
1009 bool found = false;
1010 while (!found && (it != end)) {
1011 if ((*it).id == id) {
1012 found = true;
1013 }
1014 else {
1015 ++it;
1016 }
1017 }
1018
1019 if (found) {
1020 DolphinCommand command = (*it).command;
1021 if (command.type() == DolphinCommand::Trash) {
1022 // To be able to perform an undo for the 'Move to Trash' operation
1023 // all source Urls must be updated with the trash Url. E. g. when moving
1024 // a file "test.txt" and a second file "test.txt" to the trash,
1025 // then the filenames in the trash are "0-test.txt" and "1-test.txt".
1026 QMap<QString, QString> metaData;
1027 KIO::Job *kiojob = qobject_cast<KIO::Job*>( job );
1028 if ( kiojob )
1029 {
1030 metaData = kiojob->metaData();
1031 }
1032 KUrl::List newSourceUrls;
1033
1034 KUrl::List sourceUrls = command.source();
1035 KUrl::List::Iterator sourceIt = sourceUrls.begin();
1036 const KUrl::List::Iterator sourceEnd = sourceUrls.end();
1037
1038 while (sourceIt != sourceEnd) {
1039 QMap<QString, QString>::ConstIterator metaIt = metaData.find("trashUrl-" + (*sourceIt).path());
1040 if (metaIt != metaData.end()) {
1041 newSourceUrls.append(KUrl(metaIt.value()));
1042 }
1043 ++sourceIt;
1044 }
1045 command.setSource(newSourceUrls);
1046 }
1047
1048 UndoManager::instance().addCommand(command);
1049 m_pendingUndoJobs.erase(it);
1050
1051 DolphinStatusBar* statusBar = m_activeView->statusBar();
1052 switch (command.type()) {
1053 case DolphinCommand::Copy:
1054 statusBar->setMessage(i18n("Copy operation completed."),
1055 DolphinStatusBar::OperationCompleted);
1056 break;
1057 case DolphinCommand::Move:
1058 statusBar->setMessage(i18n("Move operation completed."),
1059 DolphinStatusBar::OperationCompleted);
1060 break;
1061 case DolphinCommand::Trash:
1062 statusBar->setMessage(i18n("Move to trash operation completed."),
1063 DolphinStatusBar::OperationCompleted);
1064 break;
1065 default:
1066 break;
1067 }
1068 }
1069 }
1070 }
1071
1072 void DolphinMainWindow::init()
1073 {
1074 // Check whether Dolphin runs the first time. If yes then
1075 // a proper default window size is given at the end of DolphinMainWindow::init().
1076 GeneralSettings* generalSettings = DolphinSettings::instance().generalSettings();
1077 const bool firstRun = generalSettings->firstRun();
1078
1079 setAcceptDrops(true);
1080
1081 m_splitter = new QSplitter(this);
1082
1083 DolphinSettings& settings = DolphinSettings::instance();
1084
1085 KBookmarkManager* manager = settings.bookmarkManager();
1086 assert(manager != 0);
1087 KBookmarkGroup root = manager->root();
1088 if (root.first().isNull()) {
1089 root.addBookmark(manager, i18n("Home"), settings.generalSettings()->homeUrl(), "folder_home");
1090 root.addBookmark(manager, i18n("Storage Media"), KUrl("media:/"), "blockdevice");
1091 root.addBookmark(manager, i18n("Network"), KUrl("remote:/"), "network_local");
1092 root.addBookmark(manager, i18n("Root"), KUrl("/"), "folder_red");
1093 root.addBookmark(manager, i18n("Trash"), KUrl("trash:/"), "trashcan_full");
1094 }
1095
1096 setupActions();
1097
1098 const KUrl& homeUrl = root.first().url();
1099 setCaption(homeUrl.fileName());
1100 ViewProperties props(homeUrl);
1101 m_view[PrimaryIdx] = new DolphinView(this,
1102 m_splitter,
1103 homeUrl,
1104 props.viewMode(),
1105 props.showHiddenFiles());
1106 connectViewSignals(PrimaryIdx);
1107 m_view[PrimaryIdx]->show();
1108
1109 m_activeView = m_view[PrimaryIdx];
1110
1111 setCentralWidget(m_splitter);
1112 setupDockWidgets();
1113
1114 setupGUI(Keys|Save|Create|ToolBar);
1115 createGUI();
1116
1117 stateChanged("new_file");
1118 setAutoSaveSettings();
1119
1120 QClipboard* clipboard = QApplication::clipboard();
1121 connect(clipboard, SIGNAL(dataChanged()),
1122 this, SLOT(updatePasteAction()));
1123 updatePasteAction();
1124 updateGoActions();
1125
1126 setupCreateNewMenuActions();
1127
1128 loadSettings();
1129
1130 if (firstRun) {
1131 // assure a proper default size if Dolphin runs the first time
1132 resize(640, 480);
1133 }
1134 }
1135
1136 void DolphinMainWindow::loadSettings()
1137 {
1138 GeneralSettings* settings = DolphinSettings::instance().generalSettings();
1139
1140 KToggleAction* splitAction = static_cast<KToggleAction*>(actionCollection()->action("split_view"));
1141 if (settings->splitView()) {
1142 splitAction->setChecked(true);
1143 toggleSplitView();
1144 }
1145
1146 updateViewActions();
1147
1148 // TODO: I assume there will be a generic way in KDE 4 to restore the docks
1149 // of the main window. In the meantime they are restored manually (see also
1150 // DolphinMainWindow::closeEvent() for more details):
1151 QString filename = KStandardDirs::locateLocal("data", KGlobal::instance()->instanceName());
1152 filename.append("/panels_layout");
1153 QFile file(filename);
1154 if (file.open(QIODevice::ReadOnly)) {
1155 QByteArray data = file.readAll();
1156 restoreState(data);
1157 file.close();
1158 }
1159 }
1160
1161 void DolphinMainWindow::setupActions()
1162 {
1163 // setup 'File' menu
1164 QAction *action = actionCollection()->addAction("new_window");
1165 action->setIcon(KIcon("window_new"));
1166 action->setText(i18n("New &Window"));
1167 connect(action, SIGNAL(triggered()), this, SLOT(openNewMainWindow()));
1168
1169 QAction* createFolder = actionCollection()->addAction("create_folder");
1170 createFolder->setText(i18n("Folder..."));
1171 createFolder->setIcon(KIcon("folder"));
1172 createFolder->setShortcut(Qt::Key_N);
1173 connect(createFolder, SIGNAL(triggered()), this, SLOT(createFolder()));
1174
1175 QAction* rename = actionCollection()->addAction("rename");
1176 rename->setText(i18n("Rename"));
1177 rename->setShortcut(Qt::Key_F2);
1178 connect(rename, SIGNAL(triggered()), this, SLOT(rename()));
1179
1180 QAction* moveToTrash = actionCollection()->addAction("move_to_trash");
1181 moveToTrash->setText(i18n("Move to Trash"));
1182 moveToTrash->setIcon(KIcon("edittrash"));
1183 moveToTrash->setShortcut(QKeySequence::Delete);
1184 connect(moveToTrash, SIGNAL(triggered()), this, SLOT(moveToTrash()));
1185
1186 QAction* deleteAction = actionCollection()->addAction("delete");
1187 deleteAction->setText(i18n("Delete"));
1188 deleteAction->setShortcut(Qt::ALT | Qt::Key_Delete);
1189 deleteAction->setIcon(KIcon("editdelete"));
1190 connect(deleteAction, SIGNAL(triggered()), this, SLOT(deleteItems()));
1191
1192 QAction* properties = actionCollection()->addAction("properties");
1193 properties->setText(i18n("Propert&ies"));
1194 properties->setShortcut(Qt::Key_Alt | Qt::Key_Return);
1195 connect(properties, SIGNAL(triggered()), this, SLOT(properties()));
1196
1197 KStandardAction::quit(this, SLOT(quit()), actionCollection());
1198
1199 // setup 'Edit' menu
1200 UndoManager& undoManager = UndoManager::instance();
1201 KStandardAction::undo(this,
1202 SLOT(undo()),
1203 actionCollection());
1204 connect(&undoManager, SIGNAL(undoAvailable(bool)),
1205 this, SLOT(slotUndoAvailable(bool)));
1206 connect(&undoManager, SIGNAL(undoTextChanged(const QString&)),
1207 this, SLOT(slotUndoTextChanged(const QString&)));
1208
1209 KStandardAction::redo(this,
1210 SLOT(redo()),
1211 actionCollection());
1212 connect(&undoManager, SIGNAL(redoAvailable(bool)),
1213 this, SLOT(slotRedoAvailable(bool)));
1214 connect(&undoManager, SIGNAL(redoTextChanged(const QString&)),
1215 this, SLOT(slotRedoTextChanged(const QString&)));
1216
1217 KStandardAction::cut(this, SLOT(cut()), actionCollection());
1218 KStandardAction::copy(this, SLOT(copy()), actionCollection());
1219 KStandardAction::paste(this, SLOT(paste()), actionCollection());
1220
1221 QAction* selectAll = actionCollection()->addAction("select_all");
1222 selectAll->setText(i18n("Select All"));
1223 selectAll->setShortcut(Qt::CTRL + Qt::Key_A);
1224 connect(selectAll, SIGNAL(triggered()), this, SLOT(selectAll()));
1225
1226 QAction* invertSelection = actionCollection()->addAction("invert_selection");
1227 invertSelection->setText(i18n("Invert Selection"));
1228 invertSelection->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_A);
1229 connect(invertSelection, SIGNAL(triggered()), this, SLOT(invertSelection()));
1230
1231 // setup 'View' menu
1232 KStandardAction::zoomIn(this,
1233 SLOT(zoomIn()),
1234 actionCollection());
1235
1236 KStandardAction::zoomOut(this,
1237 SLOT(zoomOut()),
1238 actionCollection());
1239
1240 KToggleAction* iconsView = actionCollection()->add<KToggleAction>("icons");
1241 iconsView->setText(i18n("Icons"));
1242 iconsView->setShortcut(Qt::CTRL | Qt::Key_1);
1243 iconsView->setIcon(KIcon("view_icon"));
1244 connect(iconsView, SIGNAL(triggered()), this, SLOT(setIconsView()));
1245
1246 KToggleAction* detailsView = actionCollection()->add<KToggleAction>("details");
1247 detailsView->setText(i18n("Details"));
1248 detailsView->setShortcut(Qt::CTRL | Qt::Key_2);
1249 detailsView->setIcon(KIcon("view_text"));
1250 connect(detailsView, SIGNAL(triggered()), this, SLOT(setDetailsView()));
1251
1252 QActionGroup* viewModeGroup = new QActionGroup(this);
1253 viewModeGroup->addAction(iconsView);
1254 viewModeGroup->addAction(detailsView);
1255
1256 KToggleAction* sortByName = actionCollection()->add<KToggleAction>("by_name");
1257 sortByName->setText(i18n("By Name"));
1258 connect(sortByName, SIGNAL(triggered()), this, SLOT(sortByName()));
1259
1260 KToggleAction* sortBySize = actionCollection()->add<KToggleAction>("by_size");
1261 sortBySize->setText(i18n("By Size"));
1262 connect(sortBySize, SIGNAL(triggered()), this, SLOT(sortBySize()));
1263
1264 KToggleAction* sortByDate = actionCollection()->add<KToggleAction>("by_date");
1265 sortByDate->setText(i18n("By Date"));
1266 connect(sortByDate, SIGNAL(triggered()), this, SLOT(sortByDate()));
1267
1268 QActionGroup* sortGroup = new QActionGroup(this);
1269 sortGroup->addAction(sortByName);
1270 sortGroup->addAction(sortBySize);
1271 sortGroup->addAction(sortByDate);
1272
1273 KToggleAction* sortDescending = actionCollection()->add<KToggleAction>("descending");
1274 sortDescending->setText(i18n("Descending"));
1275 connect(sortDescending, SIGNAL(triggered()), this, SLOT(toggleSortOrder()));
1276
1277 KToggleAction* showPreview = actionCollection()->add<KToggleAction>("show_preview");
1278 showPreview->setText(i18n("Show Preview"));
1279 connect(showPreview, SIGNAL(triggered()), this, SLOT(togglePreview()));
1280
1281 KToggleAction* showHiddenFiles = actionCollection()->add<KToggleAction>("show_hidden_files");
1282 showHiddenFiles->setText(i18n("Show Hidden Files"));
1283 //showHiddenFiles->setShortcut(Qt::ALT | Qt::Key_ KDE4-TODO: what Qt-Key represents '.'?
1284 connect(showHiddenFiles, SIGNAL(triggered()), this, SLOT(toggleShowHiddenFiles()));
1285
1286 KToggleAction* split = actionCollection()->add<KToggleAction>("split_view");
1287 split->setText(i18n("Split View"));
1288 split->setShortcut(Qt::Key_F10);
1289 split->setIcon(KIcon("view_left_right"));
1290 connect(split, SIGNAL(triggered()), this, SLOT(toggleSplitView()));
1291
1292 QAction* reload = actionCollection()->addAction("reload");
1293 reload->setText(i18n("Reload"));
1294 reload->setShortcut(Qt::Key_F5);
1295 reload->setIcon(KIcon("reload"));
1296 connect(reload, SIGNAL(triggered()), this, SLOT(reloadView()));
1297
1298 QAction* stop = actionCollection()->addAction("stop");
1299 stop->setText(i18n("Stop"));
1300 stop->setIcon(KIcon("stop"));
1301 connect(stop, SIGNAL(triggered()), this, SLOT(stopLoading()));
1302
1303 KToggleAction* showFullLocation = actionCollection()->add<KToggleAction>("editable_location");
1304 showFullLocation->setText(i18n("Show Full Location"));
1305 showFullLocation->setShortcut(Qt::CTRL | Qt::Key_L);
1306 connect(showFullLocation, SIGNAL(triggered()), this, SLOT(toggleEditLocation()));
1307
1308 KToggleAction* editLocation = actionCollection()->add<KToggleAction>("edit_location");
1309 editLocation->setText(i18n("Edit Location"));
1310 editLocation->setShortcut(Qt::Key_F6);
1311 connect(editLocation, SIGNAL(triggered()), this, SLOT(editLocation()));
1312
1313 QAction* adjustViewProps = actionCollection()->addAction("view_properties");
1314 adjustViewProps->setText(i18n("Adjust View Properties..."));
1315 connect(adjustViewProps, SIGNAL(triggered()), this, SLOT(adjustViewProperties()));
1316
1317 // setup 'Go' menu
1318 KStandardAction::back(this, SLOT(goBack()), actionCollection());
1319 KStandardAction::forward(this, SLOT(goForward()), actionCollection());
1320 KStandardAction::up(this, SLOT(goUp()), actionCollection());
1321 KStandardAction::home(this, SLOT(goHome()), actionCollection());
1322
1323 // setup 'Tools' menu
1324 QAction* openTerminal = actionCollection()->addAction("open_terminal");
1325 openTerminal->setText(i18n("Open Terminal"));
1326 openTerminal->setShortcut(Qt::Key_F4);
1327 openTerminal->setIcon(KIcon("konsole"));
1328 connect(openTerminal, SIGNAL(triggered()), this, SLOT(openTerminal()));
1329
1330 QAction* findFile = actionCollection()->addAction("find_file");
1331 findFile->setText(i18n("Find File..."));
1332 findFile->setShortcut(Qt::Key_F);
1333 findFile->setIcon(KIcon("filefind"));
1334 connect(findFile, SIGNAL(triggered()), this, SLOT(findFile()));
1335
1336 KToggleAction* showFilterBar = actionCollection()->add<KToggleAction>("show_filter_bar");
1337 showFilterBar->setText(i18n("Show Filter Bar"));
1338 showFilterBar->setShortcut(Qt::Key_Slash);
1339 connect(showFilterBar, SIGNAL(triggered()), this, SLOT(showFilterBar()));
1340
1341 QAction* compareFiles = actionCollection()->addAction("compare_files");
1342 compareFiles->setText(i18n("Compare Files"));
1343 compareFiles->setIcon(KIcon("kompare"));
1344 compareFiles->setEnabled(false);
1345 connect(compareFiles, SIGNAL(triggered()), this, SLOT(compareFiles()));
1346
1347 // setup 'Settings' menu
1348 KStandardAction::preferences(this, SLOT(editSettings()), actionCollection());
1349 }
1350
1351 void DolphinMainWindow::setupDockWidgets()
1352 {
1353 QDockWidget* shortcutsDock = new QDockWidget(i18n("Bookmarks"));
1354 shortcutsDock->setObjectName("bookmarksDock");
1355 shortcutsDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
1356 shortcutsDock->setWidget(new BookmarksSidebarPage(this));
1357
1358 shortcutsDock->toggleViewAction()->setText(i18n("Show Bookmarks Panel"));
1359 actionCollection()->addAction("show_bookmarks_panel", shortcutsDock->toggleViewAction());
1360
1361 addDockWidget(Qt::LeftDockWidgetArea, shortcutsDock);
1362
1363 QDockWidget* infoDock = new QDockWidget(i18n("Information"));
1364 infoDock->setObjectName("infoDock");
1365 infoDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
1366 infoDock->setWidget(new InfoSidebarPage(this));
1367
1368 infoDock->toggleViewAction()->setText(i18n("Show Information Panel"));
1369 actionCollection()->addAction("show_info_panel", infoDock->toggleViewAction());
1370
1371 addDockWidget(Qt::RightDockWidgetArea, infoDock);
1372 }
1373
1374 void DolphinMainWindow::setupCreateNewMenuActions()
1375 {
1376 // Parts of the following code have been taken
1377 // from the class KNewMenu located in
1378 // libqonq/knewmenu.h of Konqueror.
1379 // Copyright (C) 1998, 1999 David Faure <faure@kde.org>
1380 // 2003 Sven Leiber <s.leiber@web.de>
1381
1382 QStringList files = actionCollection()->instance()->dirs()->findAllResources("templates");
1383 for (QStringList::Iterator it = files.begin() ; it != files.end(); ++it) {
1384 if ((*it)[0] != '.' ) {
1385 KSimpleConfig config(*it, true);
1386 config.setDesktopGroup();
1387
1388 // tricky solution to ensure that TextFile is at the beginning
1389 // because this filetype is the most used (according kde-core discussion)
1390 const QString name(config.readEntry("Name"));
1391 QString key(name);
1392
1393 const QString path(config.readPathEntry("Url"));
1394 if (!path.endsWith("emptydir")) {
1395 if (path.endsWith("TextFile.txt")) {
1396 key = "1" + key;
1397 }
1398 else if (!KDesktopFile::isDesktopFile(path)) {
1399 key = "2" + key;
1400 }
1401 else if (path.endsWith("Url.desktop")){
1402 key = "3" + key;
1403 }
1404 else if (path.endsWith("Program.desktop")){
1405 key = "4" + key;
1406 }
1407 else {
1408 key = "5";
1409 }
1410
1411 const QString icon(config.readEntry("Icon"));
1412 const QString comment(config.readEntry("Comment"));
1413 const QString type(config.readEntry("Type"));
1414
1415 const QString filePath(*it);
1416
1417
1418 if (type == "Link") {
1419 CreateFileEntry entry;
1420 entry.name = name;
1421 entry.icon = icon;
1422 entry.comment = comment;
1423 entry.templatePath = filePath;
1424 m_createFileTemplates.insert(key, entry);
1425 }
1426 }
1427 }
1428 }
1429 m_createFileTemplates.sort();
1430
1431 unplugActionList("create_actions");
1432 KSortableList<CreateFileEntry, QString>::ConstIterator it = m_createFileTemplates.begin();
1433 KSortableList<CreateFileEntry, QString>::ConstIterator end = m_createFileTemplates.end();
1434 /* KDE4-TODO: don't port this code; use KNewMenu instead
1435 while (it != end) {
1436 CreateFileEntry entry = (*it).value();
1437 KAction* action = new KAction(entry.name);
1438 action->setIcon(entry.icon);
1439 action->setName((*it).index());
1440 connect(action, SIGNAL(activated()),
1441 this, SLOT(createFile()));
1442
1443 const QChar section = ((*it).index()[0]);
1444 switch (section) {
1445 case '1':
1446 case '2': {
1447 m_fileGroupActions.append(action);
1448 break;
1449 }
1450
1451 case '3':
1452 case '4': {
1453 // TODO: not used yet. See documentation of DolphinMainWindow::linkGroupActions()
1454 // and DolphinMainWindow::linkToDeviceActions() in the header file for details.
1455 //m_linkGroupActions.append(action);
1456 break;
1457 }
1458
1459 case '5': {
1460 // TODO: not used yet. See documentation of DolphinMainWindow::linkGroupActions()
1461 // and DolphinMainWindow::linkToDeviceActions() in the header file for details.
1462 //m_linkToDeviceActions.append(action);
1463 break;
1464 }
1465 default:
1466 break;
1467 }
1468 ++it;
1469 }
1470
1471 plugActionList("create_file_group", m_fileGroupActions);
1472 //plugActionList("create_link_group", m_linkGroupActions);
1473 //plugActionList("link_to_device", m_linkToDeviceActions);*/
1474 }
1475
1476 void DolphinMainWindow::updateHistory()
1477 {
1478 int index = 0;
1479 const Q3ValueList<UrlNavigator::HistoryElem> list = m_activeView->urlHistory(index);
1480
1481 QAction* backAction = actionCollection()->action("go_back");
1482 if (backAction != 0) {
1483 backAction->setEnabled(index < static_cast<int>(list.count()) - 1);
1484 }
1485
1486 QAction* forwardAction = actionCollection()->action("go_forward");
1487 if (forwardAction != 0) {
1488 forwardAction->setEnabled(index > 0);
1489 }
1490 }
1491
1492 void DolphinMainWindow::updateEditActions()
1493 {
1494 const KFileItemList list = m_activeView->selectedItems();
1495 if (list.isEmpty()) {
1496 stateChanged("has_no_selection");
1497 }
1498 else {
1499 stateChanged("has_selection");
1500
1501 QAction* renameAction = actionCollection()->action("rename");
1502 if (renameAction != 0) {
1503 renameAction->setEnabled(list.count() >= 1);
1504 }
1505
1506 bool enableMoveToTrash = true;
1507
1508 KFileItemList::const_iterator it = list.begin();
1509 const KFileItemList::const_iterator end = list.end();
1510 while (it != end) {
1511 KFileItem* item = *it;
1512 const KUrl& url = item->url();
1513 // only enable the 'Move to Trash' action for local files
1514 if (!url.isLocalFile()) {
1515 enableMoveToTrash = false;
1516 }
1517 ++it;
1518 }
1519
1520 QAction* moveToTrashAction = actionCollection()->action("move_to_trash");
1521 moveToTrashAction->setEnabled(enableMoveToTrash);
1522 }
1523 updatePasteAction();
1524 }
1525
1526 void DolphinMainWindow::updateViewActions()
1527 {
1528 QAction* zoomInAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::ZoomIn));
1529 if (zoomInAction != 0) {
1530 zoomInAction->setEnabled(m_activeView->isZoomInPossible());
1531 }
1532
1533 QAction* zoomOutAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::ZoomOut));
1534 if (zoomOutAction != 0) {
1535 zoomOutAction->setEnabled(m_activeView->isZoomOutPossible());
1536 }
1537
1538 QAction* action = 0;
1539 switch (m_activeView->mode()) {
1540 case DolphinView::IconsView:
1541 action = actionCollection()->action("icons");
1542 break;
1543 case DolphinView::DetailsView:
1544 action = actionCollection()->action("details");
1545 break;
1546 //case DolphinView::PreviewsView:
1547 // action = actionCollection()->action("previews");
1548 // break;
1549 default:
1550 break;
1551 }
1552
1553 if (action != 0) {
1554 KToggleAction* toggleAction = static_cast<KToggleAction*>(action);
1555 toggleAction->setChecked(true);
1556 }
1557
1558 slotSortingChanged(m_activeView->sorting());
1559 slotSortOrderChanged(m_activeView->sortOrder());
1560
1561 KToggleAction* showFilterBarAction =
1562 static_cast<KToggleAction*>(actionCollection()->action("show_filter_bar"));
1563 showFilterBarAction->setChecked(m_activeView->isFilterBarVisible());
1564
1565 KToggleAction* showHiddenFilesAction =
1566 static_cast<KToggleAction*>(actionCollection()->action("show_hidden_files"));
1567 showHiddenFilesAction->setChecked(m_activeView->showHiddenFiles());
1568
1569 KToggleAction* splitAction = static_cast<KToggleAction*>(actionCollection()->action("split_view"));
1570 splitAction->setChecked(m_view[SecondaryIdx] != 0);
1571 }
1572
1573 void DolphinMainWindow::updateGoActions()
1574 {
1575 QAction* goUpAction = actionCollection()->action(KStandardAction::stdName(KStandardAction::Up));
1576 const KUrl& currentUrl = m_activeView->url();
1577 goUpAction->setEnabled(currentUrl.upUrl() != currentUrl);
1578 }
1579
1580 void DolphinMainWindow::copyUrls(const KUrl::List& source, const KUrl& dest)
1581 {
1582 KIO::Job* job = KIO::copy(source, dest);
1583 addPendingUndoJob(job, DolphinCommand::Copy, source, dest);
1584 }
1585
1586 void DolphinMainWindow::moveUrls(const KUrl::List& source, const KUrl& dest)
1587 {
1588 KIO::Job* job = KIO::move(source, dest);
1589 addPendingUndoJob(job, DolphinCommand::Move, source, dest);
1590 }
1591
1592 void DolphinMainWindow::addPendingUndoJob(KIO::Job* job,
1593 DolphinCommand::Type commandType,
1594 const KUrl::List& source,
1595 const KUrl& dest)
1596 {
1597 connect(job, SIGNAL(result(KJob*)),
1598 this, SLOT(addUndoOperation(KJob*)));
1599
1600 UndoInfo undoInfo;
1601 undoInfo.id = job->progressId();
1602 undoInfo.command = DolphinCommand(commandType, source, dest);
1603 m_pendingUndoJobs.append(undoInfo);
1604 }
1605
1606 void DolphinMainWindow::clearStatusBar()
1607 {
1608 m_activeView->statusBar()->clear();
1609 }
1610
1611 void DolphinMainWindow::connectViewSignals(int viewIndex)
1612 {
1613 DolphinView* view = m_view[viewIndex];
1614 connect(view, SIGNAL(modeChanged()),
1615 this, SLOT(slotViewModeChanged()));
1616 connect(view, SIGNAL(showHiddenFilesChanged()),
1617 this, SLOT(slotShowHiddenFilesChanged()));
1618 connect(view, SIGNAL(sortingChanged(DolphinView::Sorting)),
1619 this, SLOT(slotSortingChanged(DolphinView::Sorting)));
1620 connect(view, SIGNAL(sortOrderChanged(Qt::SortOrder)),
1621 this, SLOT(slotSortOrderChanged(Qt::SortOrder)));
1622 connect(view, SIGNAL(selectionChanged()),
1623 this, SLOT(slotSelectionChanged()));
1624 connect(view, SIGNAL(showFilterBarChanged(bool)),
1625 this, SLOT(updateFilterBarAction(bool)));
1626
1627 const UrlNavigator* navigator = view->urlNavigator();
1628 connect(navigator, SIGNAL(urlChanged(const KUrl&)),
1629 this, SLOT(slotUrlChanged(const KUrl&)));
1630 connect(navigator, SIGNAL(historyChanged()),
1631 this, SLOT(slotHistoryChanged()));
1632
1633 }
1634
1635 #include "dolphinmainwindow.moc"