]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphinviewcontainer.cpp
msvc compile++
[dolphin.git] / src / dolphinviewcontainer.cpp
1 /***************************************************************************
2 * Copyright (C) 2007 by Peter Penz <peter.penz@gmx.at> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 ***************************************************************************/
19
20 #include "dolphinviewcontainer.h"
21
22 #include <QtGui/QApplication>
23 #include <QtGui/QClipboard>
24 #include <QtGui/QKeyEvent>
25 #include <QtGui/QItemSelection>
26 #include <QtGui/QBoxLayout>
27 #include <QtCore/QTimer>
28 #include <QtGui/QScrollBar>
29
30 #include <kfileitemdelegate.h>
31 #include <kfileplacesmodel.h>
32 #include <kglobalsettings.h>
33 #include <klocale.h>
34 #include <kiconeffect.h>
35 #include <kio/netaccess.h>
36 #include <kio/renamedialog.h>
37 #include <kio/previewjob.h>
38 #include <kmimetyperesolver.h>
39 #include <konqmimedata.h>
40 #include <konq_operations.h>
41 #include <kurl.h>
42
43 #include "dolphinmodel.h"
44 #include "dolphincolumnview.h"
45 #include "dolphincontroller.h"
46 #include "dolphinstatusbar.h"
47 #include "dolphinmainwindow.h"
48 #include "dolphindirlister.h"
49 #include "dolphinsortfilterproxymodel.h"
50 #include "dolphindetailsview.h"
51 #include "dolphiniconsview.h"
52 #include "dolphincontextmenu.h"
53 #include "filterbar.h"
54 #include "renamedialog.h"
55 #include "kurlnavigator.h"
56 #include "viewproperties.h"
57 #include "dolphinsettings.h"
58 #include "dolphin_generalsettings.h"
59
60 DolphinViewContainer::DolphinViewContainer(DolphinMainWindow* mainWindow,
61 QWidget* parent,
62 const KUrl& url) :
63 QWidget(parent),
64 m_showProgress(false),
65 m_folderCount(0),
66 m_fileCount(0),
67 m_mainWindow(mainWindow),
68 m_topLayout(0),
69 m_urlNavigator(0),
70 m_view(0),
71 m_filterBar(0),
72 m_statusBar(0),
73 m_dirLister(0),
74 m_proxyModel(0)
75 {
76 hide();
77 setFocusPolicy(Qt::StrongFocus);
78 m_topLayout = new QVBoxLayout(this);
79 m_topLayout->setSpacing(0);
80 m_topLayout->setMargin(0);
81
82 m_urlNavigator = new KUrlNavigator(DolphinSettings::instance().placesModel(), url, this);
83 connect(m_urlNavigator, SIGNAL(urlsDropped(const KUrl::List&, const KUrl&)),
84 m_mainWindow, SLOT(dropUrls(const KUrl::List&, const KUrl&)));
85 connect(m_urlNavigator, SIGNAL(activated()),
86 this, SLOT(activate()));
87
88 const GeneralSettings* settings = DolphinSettings::instance().generalSettings();
89 m_urlNavigator->setUrlEditable(settings->editableUrl());
90 m_urlNavigator->setHomeUrl(settings->homeUrl());
91
92 m_dirLister = new DolphinDirLister();
93 m_dirLister->setAutoUpdate(true);
94 m_dirLister->setMainWindow(this);
95 m_dirLister->setDelayedMimeTypes(true);
96
97 m_dolphinModel = new DolphinModel();
98 m_dolphinModel->setDirLister(m_dirLister);
99 m_dolphinModel->setDropsAllowed(DolphinModel::DropOnDirectory);
100
101
102 m_proxyModel = new DolphinSortFilterProxyModel(this);
103 m_proxyModel->setSourceModel(m_dolphinModel);
104
105 connect(m_dirLister, SIGNAL(clear()),
106 this, SLOT(updateStatusBar()));
107 connect(m_dirLister, SIGNAL(percent(int)),
108 this, SLOT(updateProgress(int)));
109 connect(m_dirLister, SIGNAL(deleteItem(KFileItem*)),
110 this, SLOT(updateStatusBar()));
111 connect(m_dirLister, SIGNAL(completed()),
112 this, SLOT(updateItemCount()));
113 connect(m_dirLister, SIGNAL(infoMessage(const QString&)),
114 this, SLOT(showInfoMessage(const QString&)));
115 connect(m_dirLister, SIGNAL(errorMessage(const QString&)),
116 this, SLOT(showErrorMessage(const QString&)));
117
118 m_view = new DolphinView(this,
119 url,
120 m_dirLister,
121 m_dolphinModel,
122 m_proxyModel);
123 connect(m_view, SIGNAL(urlChanged(const KUrl&)),
124 m_urlNavigator, SLOT(setUrl(const KUrl&)));
125 connect(m_view, SIGNAL(requestContextMenu(KFileItem, const KUrl&)),
126 this, SLOT(openContextMenu(KFileItem, const KUrl&)));
127 connect(m_view, SIGNAL(urlsDropped(const KUrl::List&, const KUrl&)),
128 m_mainWindow, SLOT(dropUrls(const KUrl::List&, const KUrl&)));
129 connect(m_view, SIGNAL(contentsMoved(int, int)),
130 this, SLOT(saveContentsPos(int, int)));
131 connect(m_view, SIGNAL(requestItemInfo(KFileItem)),
132 this, SLOT(showItemInfo(KFileItem)));
133 connect(m_view, SIGNAL(errorMessage(const QString&)),
134 this, SLOT(showErrorMessage(const QString&)));
135 connect(m_view, SIGNAL(infoMessage(const QString&)),
136 this, SLOT(showInfoMessage(const QString&)));
137 connect(m_view, SIGNAL(itemTriggered(KFileItem)),
138 this, SLOT(slotItemTriggered(KFileItem)));
139
140 connect(m_urlNavigator, SIGNAL(urlChanged(const KUrl&)),
141 m_view, SLOT(setUrl(const KUrl&)));
142
143 m_statusBar = new DolphinStatusBar(this, url);
144 connect(m_view, SIGNAL(urlChanged(const KUrl&)),
145 m_statusBar, SLOT(updateSpaceInfoContent(const KUrl&)));
146
147 m_filterBar = new FilterBar(this);
148 m_filterBar->setVisible(settings->filterBar());
149 connect(m_filterBar, SIGNAL(filterChanged(const QString&)),
150 this, SLOT(changeNameFilter(const QString&)));
151 connect(m_filterBar, SIGNAL(closeRequest()),
152 this, SLOT(closeFilterBar()));
153
154 m_topLayout->addWidget(m_urlNavigator);
155 m_topLayout->addWidget(m_view);
156 m_topLayout->addWidget(m_filterBar);
157 m_topLayout->addWidget(m_statusBar);
158 }
159
160 DolphinViewContainer::~DolphinViewContainer()
161 {
162 delete m_dirLister;
163 m_dirLister = 0;
164 }
165
166 void DolphinViewContainer::setUrl(const KUrl& url)
167 {
168 m_urlNavigator->setUrl(url);
169 }
170
171 const KUrl& DolphinViewContainer::url() const
172 {
173 return m_urlNavigator->url();
174 }
175
176 void DolphinViewContainer::setActive(bool active)
177 {
178 m_urlNavigator->setActive(active);
179 m_view->setActive(active);
180 }
181
182 bool DolphinViewContainer::isActive() const
183 {
184 Q_ASSERT(m_view->isActive() == m_urlNavigator->isActive());
185 return m_view->isActive();
186 }
187
188 void DolphinViewContainer::renameSelectedItems()
189 {
190 DolphinViewContainer* view = m_mainWindow->activeViewContainer();
191 const QList<KFileItem> items = m_view->selectedItems();
192 if (items.count() > 1) {
193 // More than one item has been selected for renaming. Open
194 // a rename dialog and rename all items afterwards.
195 RenameDialog dialog(items);
196 if (dialog.exec() == QDialog::Rejected) {
197 return;
198 }
199
200 const QString& newName = dialog.newName();
201 if (newName.isEmpty()) {
202 view->statusBar()->setMessage(dialog.errorString(),
203 DolphinStatusBar::Error);
204 } else {
205 // TODO: check how this can be integrated into KonqUndoManager/KonqOperations
206 // as one operation instead of n rename operations like it is done now...
207 Q_ASSERT(newName.contains('#'));
208
209 // iterate through all selected items and rename them...
210 const int replaceIndex = newName.indexOf('#');
211 Q_ASSERT(replaceIndex >= 0);
212 int index = 1;
213
214 QList<KFileItem>::const_iterator it = items.begin();
215 QList<KFileItem>::const_iterator end = items.end();
216 while (it != end) {
217 const KUrl& oldUrl = (*it).url();
218 QString number;
219 number.setNum(index++);
220
221 QString name(newName);
222 name.replace(replaceIndex, 1, number);
223
224 if (oldUrl.fileName() != name) {
225 KUrl newUrl = oldUrl;
226 newUrl.setFileName(name);
227 m_mainWindow->rename(oldUrl, newUrl);
228 }
229 ++it;
230 }
231 }
232 } else {
233 // Only one item has been selected for renaming. Use the custom
234 // renaming mechanism from the views.
235 Q_ASSERT(items.count() == 1);
236
237 // TODO: Think about using KFileItemDelegate as soon as it supports editing.
238 // Currently the RenameDialog is used, but I'm not sure whether inline renaming
239 // is a benefit for the user at all -> let's wait for some input first...
240 RenameDialog dialog(items);
241 if (dialog.exec() == QDialog::Rejected) {
242 return;
243 }
244
245 const QString& newName = dialog.newName();
246 if (newName.isEmpty()) {
247 view->statusBar()->setMessage(dialog.errorString(),
248 DolphinStatusBar::Error);
249 } else {
250 const KUrl& oldUrl = items.first().url();
251 KUrl newUrl = oldUrl;
252 newUrl.setFileName(newName);
253 m_mainWindow->rename(oldUrl, newUrl);
254 }
255 }
256 }
257
258 bool DolphinViewContainer::isFilterBarVisible() const
259 {
260 return m_filterBar->isVisible();
261 }
262
263 bool DolphinViewContainer::isUrlEditable() const
264 {
265 return m_urlNavigator->isUrlEditable();
266 }
267
268 KFileItem DolphinViewContainer::fileItem(const QModelIndex& index) const
269 {
270 const QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(index);
271 return m_dolphinModel->itemForIndex(dolphinModelIndex);
272 }
273
274 void DolphinViewContainer::updateProgress(int percent)
275 {
276 if (!m_showProgress) {
277 // Only show the directory loading progress if the status bar does
278 // not contain another progress information. This means that
279 // the directory loading progress information has the lowest priority.
280 const QString progressText(m_statusBar->progressText());
281 const QString loadingText(i18nc("@info:progress", "Loading folder..."));
282 m_showProgress = progressText.isEmpty() || (progressText == loadingText);
283 if (m_showProgress) {
284 m_statusBar->setProgressText(loadingText);
285 m_statusBar->setProgress(0);
286 }
287 }
288
289 if (m_showProgress) {
290 m_statusBar->setProgress(percent);
291 }
292 }
293
294 void DolphinViewContainer::updateItemCount()
295 {
296 if (m_showProgress) {
297 m_statusBar->setProgressText(QString());
298 m_statusBar->setProgress(100);
299 m_showProgress = false;
300 }
301
302 KFileItemList items(m_dirLister->items());
303 KFileItemList::const_iterator it = items.begin();
304 const KFileItemList::const_iterator end = items.end();
305
306 m_fileCount = 0;
307 m_folderCount = 0;
308
309 while (it != end) {
310 KFileItem* item = *it;
311 if (item->isDir()) {
312 ++m_folderCount;
313 } else {
314 ++m_fileCount;
315 }
316 ++it;
317 }
318
319 updateStatusBar();
320
321 QTimer::singleShot(100, this, SLOT(restoreContentsPos()));
322 }
323
324 void DolphinViewContainer::showItemInfo(const KFileItem& item)
325 {
326 if (item.isNull()) {
327 m_statusBar->clear();
328 } else {
329 m_statusBar->setMessage(item.getStatusBarInfo(), DolphinStatusBar::Default);
330 }
331 }
332
333 void DolphinViewContainer::showInfoMessage(const QString& msg)
334 {
335 m_statusBar->setMessage(msg, DolphinStatusBar::Information);
336 }
337
338 void DolphinViewContainer::showErrorMessage(const QString& msg)
339 {
340 m_statusBar->setMessage(msg, DolphinStatusBar::Error);
341 }
342
343 void DolphinViewContainer::closeFilterBar()
344 {
345 m_filterBar->hide();
346 emit showFilterBarChanged(false);
347 }
348
349 QString DolphinViewContainer::defaultStatusBarText() const
350 {
351 int m_fileCount = 0;
352 int m_folderCount = 0;
353
354 for (int i = 0; i < m_proxyModel->rowCount(); i++)
355 {
356 if (m_dolphinModel->itemForIndex(m_proxyModel->mapToSource(m_proxyModel->index(i, m_proxyModel->sortColumn()))).isDir())
357 {
358 m_folderCount++;
359 }
360 else
361 {
362 m_fileCount++;
363 }
364 }
365
366 return KIO::itemsSummaryString(m_fileCount + m_folderCount,
367 m_fileCount,
368 m_folderCount,
369 0, false);
370 }
371
372 QString DolphinViewContainer::selectionStatusBarText() const
373 {
374 QString text;
375 const QList<KFileItem> list = m_view->selectedItems();
376 if (list.isEmpty()) {
377 // when an item is triggered, it is temporary selected but selectedItems()
378 // will return an empty list
379 return QString();
380 }
381
382 int fileCount = 0;
383 int folderCount = 0;
384 KIO::filesize_t byteSize = 0;
385 QList<KFileItem>::const_iterator it = list.begin();
386 const QList<KFileItem>::const_iterator end = list.end();
387 while (it != end) {
388 const KFileItem& item = *it;
389 if (item.isDir()) {
390 ++folderCount;
391 } else {
392 ++fileCount;
393 byteSize += item.size();
394 }
395 ++it;
396 }
397
398 if (folderCount > 0) {
399 text = i18ncp("@info:status", "1 Folder selected", "%1 Folders selected", folderCount);
400 if (fileCount > 0) {
401 text += ", ";
402 }
403 }
404
405 if (fileCount > 0) {
406 const QString sizeText(KIO::convertSize(byteSize));
407 text += i18ncp("@info:status", "1 File selected (%2)", "%1 Files selected (%2)", fileCount, sizeText);
408 }
409
410 return text;
411 }
412
413 void DolphinViewContainer::showFilterBar(bool show)
414 {
415 Q_ASSERT(m_filterBar != 0);
416 m_filterBar->setVisible(show);
417 }
418
419 void DolphinViewContainer::updateStatusBar()
420 {
421 // As the item count information is less important
422 // in comparison with other messages, it should only
423 // be shown if:
424 // - the status bar is empty or
425 // - shows already the item count information or
426 // - shows only a not very important information
427 // - if any progress is given don't show the item count info at all
428 const QString msg(m_statusBar->message());
429 const bool updateStatusBarMsg = (msg.isEmpty() ||
430 (msg == m_statusBar->defaultText()) ||
431 (m_statusBar->type() == DolphinStatusBar::Information)) &&
432 (m_statusBar->progress() == 100);
433
434 const QString text(m_view->hasSelection() ? selectionStatusBarText() : defaultStatusBarText());
435 m_statusBar->setDefaultText(text);
436
437 if (updateStatusBarMsg) {
438 m_statusBar->setMessage(text, DolphinStatusBar::Default);
439 }
440 }
441
442 void DolphinViewContainer::changeNameFilter(const QString& nameFilter)
443 {
444 // The name filter of KDirLister does a 'hard' filtering, which
445 // means that only the items are shown where the names match
446 // exactly the filter. This is non-transparent for the user, which
447 // just wants to have a 'soft' filtering: does the name contain
448 // the filter string?
449 QString adjustedFilter(nameFilter);
450 adjustedFilter.insert(0, '*');
451 adjustedFilter.append('*');
452
453 // Use the ProxyModel to filter:
454 // This code is #ifdefed as setNameFilter behaves
455 // slightly different than the QSortFilterProxyModel
456 // as it will not remove directories. I will ask
457 // our beloved usability experts for input
458 // -- z.
459 #if 0
460 m_dirLister->setNameFilter(adjustedFilter);
461 m_dirLister->emitChanges();
462 #else
463 m_proxyModel->setFilterRegExp(nameFilter);
464 #endif
465
466 updateStatusBar();
467 }
468
469 void DolphinViewContainer::openContextMenu(const KFileItem& item,
470 const KUrl& url)
471 {
472 DolphinContextMenu contextMenu(m_mainWindow, item, url);
473 contextMenu.open();
474 }
475
476 void DolphinViewContainer::saveContentsPos(int x, int y)
477 {
478 m_urlNavigator->savePosition(x, y);
479 }
480
481 void DolphinViewContainer::restoreContentsPos()
482 {
483 if (!url().isEmpty()) {
484 const QPoint pos = m_urlNavigator->savedPosition();
485 m_view->setContentsPosition(pos.x(), pos.y());
486 }
487 }
488
489 void DolphinViewContainer::activate()
490 {
491 setActive(true);
492 }
493
494 void DolphinViewContainer::slotItemTriggered(const KFileItem& item)
495 {
496 // Prefer the local path over the URL.
497 bool isLocal;
498 KUrl url = item.mostLocalUrl(isLocal);
499
500 if (item.isDir()) {
501 m_view->setUrl(url);
502 } else if (item.isFile()) {
503 // allow to browse through ZIP and tar files
504 KMimeType::Ptr mime = item.mimeTypePtr();
505 if (mime->is("application/zip")) {
506 url.setProtocol("zip");
507 m_view->setUrl(url);
508 } else if (mime->is("application/x-tar") ||
509 mime->is("application/x-tarz") ||
510 mime->is("application/x-bzip-compressed-tar") ||
511 mime->is("application/x-compressed-tar") ||
512 mime->is("application/x-tzo")) {
513 url.setProtocol("tar");
514 m_view->setUrl(url);
515 } else {
516 item.run();
517 }
518 } else {
519 item.run();
520 }
521 }
522
523 #include "dolphinviewcontainer.moc"