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