1 /*****************************************************************************
2 * Copyright (C) 2000 Shie Erlich <krusader@users.sourceforge.net> *
3 * Copyright (C) 2000 Rafi Yanai <krusader@users.sourceforge.net> *
4 * Copyright (C) 2004-2019 Krusader Krew [https://krusader.org] *
5 * *
6 * This file is part of Krusader [https://krusader.org]. *
7 * *
8 * Krusader is free software: you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation, either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * Krusader is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with Krusader. If not, see [http://www.gnu.org/licenses/]. *
20 *****************************************************************************/
21
22 #include "listpanel.h"
23
24 // QtCore
25 #include <QStringList>
26 #include <QList>
27 #include <QEvent>
28 #include <QMimeData>
29 #include <QTimer>
30 #include <QRegExp>
31 #include <QUrl>
32 // QtGui
33 #include <QBitmap>
34 #include <QKeyEvent>
35 #include <QPixmap>
36 #include <QDropEvent>
37 #include <QHideEvent>
38 #include <QShowEvent>
39 #include <QDrag>
40 #include <QImage>
41 // QtWidgets
42 #include <QHBoxLayout>
43 #include <QFrame>
44 #include <QMenu>
45 #include <QSplitter>
46 #include <QTabBar>
47
48 #include <KCoreAddons/KUrlMimeData>
49 #include <KI18n/KLocalizedString>
50 #include <KIO/DropJob>
51 #include <KWidgetsAddons/KCursor>
52 #include <KWidgetsAddons/KMessageBox>
53 #include <KIOFileWidgets/KFilePlacesModel>
54 #include <KIOWidgets/KUrlComboBox>
55
56 #include "dirhistoryqueue.h"
57 #include "krcolorcache.h"
58 #include "krerrordisplay.h"
59 #include "krlayoutfactory.h"
60 #include "krpreviewpopup.h"
61 #include "krsearchbar.h"
62 #include "listpanelactions.h"
63 #include "panelcontextmenu.h"
64 #include "panelfunc.h"
65 #include "sidebar.h"
66 #include "viewactions.h"
67
68 #include "PanelView/krview.h"
69 #include "PanelView/krviewfactory.h"
70 #include "PanelView/krviewitem.h"
71
72 #include "../defaults.h"
73 #include "../icon.h"
74 #include "../krservices.h"
75 #include "../krslots.h"
76 #include "../krusader.h"
77 #include "../krusaderview.h"
78
79 #include "../Archive/krarchandler.h"
80 #include "../BookMan/krbookmarkbutton.h"
81 #include "../FileSystem/fileitem.h"
82 #include "../FileSystem/filesystem.h"
83 #include "../FileSystem/krpermhandler.h"
84 #include "../FileSystem/sizecalculator.h"
85 #include "../Dialogs/krdialogs.h"
86 #include "../Dialogs/krspwidgets.h"
87 #include "../Dialogs/krsqueezedtextlabel.h"
88 #include "../Dialogs/percentalsplitter.h"
89 #include "../Dialogs/popularurls.h"
90 #include "../GUI/dirhistorybutton.h"
91 #include "../GUI/kcmdline.h"
92 #include "../GUI/mediabutton.h"
93 #include "../MountMan/kmountman.h"
94 #include "../UserAction/useractionpopupmenu.h"
95
96 class ActionButton : public QToolButton
97 {
98 public:
ActionButton(QWidget * parent,ListPanel * panel,QAction * action,QString text=QString ())99 ActionButton(QWidget *parent, ListPanel *panel, QAction *action, QString text = QString()) :
100 QToolButton(parent), panel(panel), action(action) {
101 setText(text);
102 setAutoRaise(true);
103 if(KConfigGroup(krConfig, "ListPanelButtons").readEntry("Icons", false) || text.isEmpty())
104 setIcon(action->icon());
105 setToolTip(action->toolTip());
106 }
107
108 protected:
mousePressEvent(QMouseEvent *)109 virtual void mousePressEvent(QMouseEvent *) Q_DECL_OVERRIDE {
110 panel->slotFocusOnMe();
111 action->trigger();
112 }
113
114 ListPanel *panel;
115 QAction *action;
116 };
117
118
119 /////////////////////////////////////////////////////
120 // The list panel constructor //
121 /////////////////////////////////////////////////////
ListPanel(QWidget * parent,AbstractPanelManager * manager,KConfigGroup cfg)122 ListPanel::ListPanel(QWidget *parent, AbstractPanelManager *manager, KConfigGroup cfg) :
123 QWidget(parent), KrPanel(manager, this, new ListPanelFunc(this)),
124 panelType(-1), colorMask(255), compareMode(false),
125 previewJob(0), inlineRefreshJob(0), searchBar(0), cdRootButton(0), cdUpButton(0),
126 sidebarButton(0), sidebar(0), fileSystemError(0), _navigatorUrl(), _tabState(TabState::DEFAULT)
127 {
128 if(cfg.isValid())
129 panelType = cfg.readEntry("Type", -1);
130 if (panelType == -1)
131 panelType = defaultPanelType();
132
133 _actions = krApp->listPanelActions();
134
135 setAcceptDrops(true);
136
137 QHash<QString, QWidget*> widgets;
138
139 #define ADD_WIDGET(widget) widgets.insert(#widget, widget);
140
141 // media button
142 mediaButton = new MediaButton(this);
143 connect(mediaButton, SIGNAL(aboutToShow()), this, SLOT(slotFocusOnMe()));
144 connect(mediaButton, SIGNAL(openUrl(QUrl)), func, SLOT(openUrl(QUrl)));
145 connect(mediaButton, SIGNAL(newTab(QUrl)), SLOT(newTab(QUrl)));
146 ADD_WIDGET(mediaButton);
147
148 // status bar
149 status = new KrSqueezedTextLabel(this);
150 KConfigGroup group(krConfig, "Look&Feel");
151 status->setFont(group.readEntry("Filelist Font", _FilelistFont));
152 status->setAutoFillBackground(false);
153 status->setText(""); // needed for initialization code!
154 status->setWhatsThis(i18n("The statusbar displays information about the filesystem "
155 "which holds your current folder: total size, free space, "
156 "type of filesystem, etc."));
157 ADD_WIDGET(status);
158
159 // back button
160 backButton = new ActionButton(this, this, _actions->actHistoryBackward);
161 ADD_WIDGET(backButton);
162
163 // forward button
164 forwardButton = new ActionButton(this, this, _actions->actHistoryForward);
165 ADD_WIDGET(forwardButton);
166
167
168 // ... create the history button
169 historyButton = new DirHistoryButton(func->history, this);
170 connect(historyButton, SIGNAL(aboutToShow()), this, SLOT(slotFocusOnMe()));
171 connect(historyButton, SIGNAL(gotoPos(int)), func, SLOT(historyGotoPos(int)));
172 ADD_WIDGET(historyButton);
173
174 // bookmarks button
175 bookmarksButton = new KrBookmarkButton(this);
176 connect(bookmarksButton, SIGNAL(aboutToShow()), this, SLOT(slotFocusOnMe()));
177 connect(bookmarksButton, SIGNAL(openUrl(QUrl)), func, SLOT(openUrl(QUrl)));
178 bookmarksButton->setWhatsThis(i18n("Open menu with bookmarks. You can also add "
179 "current location to the list, edit bookmarks "
180 "or add subfolder to the list."));
181 ADD_WIDGET(bookmarksButton);
182
183 // url input field
184 urlNavigator = new KUrlNavigator(new KFilePlacesModel(this), QUrl(), this);
185 urlNavigator->setWhatsThis(i18n("Name of folder where you are. You can also "
186 "enter name of desired location to move there. "
187 "Use of Net protocols like ftp or fish is possible."));
188 // handle certain key events here in event filter
189 urlNavigator->editor()->installEventFilter(this);
190 urlNavigator->setUrlEditable(isNavigatorEditModeSet());
191 urlNavigator->setShowFullPath(group.readEntry("Navigator Full Path", false));
192 connect(urlNavigator, SIGNAL(returnPressed()), this, SLOT(slotFocusOnMe()));
193 connect(urlNavigator, &KUrlNavigator::urlChanged, this, &ListPanel::slotNavigatorUrlChanged);
194 connect(urlNavigator->editor()->lineEdit(), &QLineEdit::editingFinished, this, &ListPanel::resetNavigatorMode);
195 connect(urlNavigator, SIGNAL(tabRequested(QUrl)), this, SLOT(newTab(QUrl)));
196 connect(urlNavigator, SIGNAL(urlsDropped(QUrl,QDropEvent*)), this, SLOT(handleDrop(QUrl,QDropEvent*)));
197 ADD_WIDGET(urlNavigator);
198
199 // toolbar
200 QWidget * toolbar = new QWidget(this);
201 QHBoxLayout * toolbarLayout = new QHBoxLayout(toolbar);
202 toolbarLayout->setContentsMargins(0, 0, 0, 0);
203 toolbarLayout->setSpacing(0);
204 ADD_WIDGET(toolbar);
205
206 fileSystemError = new KrErrorDisplay(this);
207 fileSystemError->setWordWrap(true);
208 fileSystemError->hide();
209 ADD_WIDGET(fileSystemError);
210
211 // client area
212 clientArea = new QWidget(this);
213 QVBoxLayout *clientLayout = new QVBoxLayout(clientArea);
214 clientLayout->setSpacing(0);
215 clientLayout->setContentsMargins(0, 0, 0, 0);
216 ADD_WIDGET(clientArea);
217
218 // totals label
219 totals = new KrSqueezedTextLabel(this);
220 totals->setFont(group.readEntry("Filelist Font", _FilelistFont));
221 totals->setAutoFillBackground(false);
222 totals->setWhatsThis(i18n("The totals bar shows how many files exist, "
223 "how many selected and the bytes math"));
224 ADD_WIDGET(totals);
225
226 // free space label
227 freeSpace = new KrSqueezedTextLabel(this);
228 freeSpace->setFont(group.readEntry("Filelist Font", _FilelistFont));
229 freeSpace->setAutoFillBackground(false);
230 freeSpace->setText("");
231 freeSpace->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
232 ADD_WIDGET(freeSpace);
233
234 // progress indicator and cancel button for the quick calc size
235 quickSizeCalcProgress = new QProgressBar(this);
236 quickSizeCalcProgress->hide();
237 ADD_WIDGET(quickSizeCalcProgress);
238 cancelQuickSizeCalcButton = new QToolButton(this);
239 cancelQuickSizeCalcButton->hide();
240 cancelQuickSizeCalcButton->setIcon(Icon("dialog-cancel"));
241 cancelQuickSizeCalcButton->setToolTip(i18n("Cancel directory space calculation"));
242 ADD_WIDGET(cancelQuickSizeCalcButton);
243
244 // progress indicator for the preview job
245 previewProgress = new QProgressBar(this);
246 previewProgress->hide();
247 ADD_WIDGET(previewProgress);
248
249 // a cancel button for the filesystem refresh and preview job
250 cancelProgressButton = new QToolButton(this);
251 cancelProgressButton->hide();
252 cancelProgressButton->setIcon(Icon("dialog-cancel"));
253 connect(cancelProgressButton, SIGNAL(clicked()), this, SLOT(cancelProgress()));
254 ADD_WIDGET(cancelProgressButton);
255
256 // button for changing the panel sidebar position in the panel
257 sidebarPositionButton = new QToolButton(this);
258 sidebarPositionButton->hide();
259 sidebarPositionButton->setAutoRaise(true);
260 sidebarPositionButton->setIcon(Icon("exchange-positions"));
261 sidebarPositionButton->setToolTip(i18n("Move Sidebar clockwise"));
262 connect(sidebarPositionButton, &QToolButton::clicked, [this]() {
263 // moving position clockwise
264 setSidebarPosition((sidebarPosition() + 1) % 4); });
265 ADD_WIDGET(sidebarPositionButton);
266
267 // a quick button to open the sidebar
268 sidebarButton = new QToolButton(this);
269 sidebarButton->setAutoRaise(true);
270 sidebarButton->setIcon(Icon("arrow-up"));
271 connect(sidebarButton, &QToolButton::clicked, this, &ListPanel::toggleSidebar);
272 sidebarButton->setToolTip(i18n("Open the Sidebar"));
273 ADD_WIDGET(sidebarButton);
274
275 #undef ADD_WIDGET
276
277 // toolbar buttons
278 cdOtherButton = new ActionButton(toolbar, this, _actions->actCdToOther, "=");
279 toolbarLayout->addWidget(cdOtherButton);
280
281 cdUpButton = new ActionButton(toolbar, this, _actions->actDirUp, "..");
282 toolbarLayout->addWidget(cdUpButton);
283
284 cdHomeButton = new ActionButton(toolbar, this, _actions->actHome, "~");
285 toolbarLayout->addWidget(cdHomeButton);
286
287 cdRootButton = new ActionButton(toolbar, this, _actions->actRoot, "/");
288 toolbarLayout->addWidget(cdRootButton);
289
290 // create the button for sync-browsing
291 syncBrowseButton = new QToolButton(toolbar);
292 syncBrowseButton->setIcon(Icon("kr_syncbrowse_off"));
293 syncBrowseButton->setCheckable(true);
294
295 const QString syncBrowseText = i18n("This button toggles the sync-browse mode.\n"
296 "When active, each folder change is performed in the\n"
297 "active and inactive panel - if possible.");
298 syncBrowseButton->setText(syncBrowseText);
299 syncBrowseButton->setToolTip(syncBrowseText);
300 connect(syncBrowseButton, &QToolButton::toggled, [=](bool checked) {
301 syncBrowseButton->setIcon(
302 Icon(checked ? "kr_syncbrowse_on" : "kr_syncbrowse_off"));
303 });
304 syncBrowseButton->setAutoRaise(true);
305 toolbarLayout->addWidget(syncBrowseButton);
306
307 setButtons();
308
309 // create a splitter to hold the view and the sidebar
310 sidebarSplitter = new PercentalSplitter(clientArea);
311 sidebarSplitter->setChildrenCollapsible(true);
312 sidebarSplitter->setOrientation(Qt::Horizontal);
313 // expand vertical if splitter orientation is horizontal
314 QSizePolicy sizePolicy = sidebarSplitter->sizePolicy();
315 sizePolicy.setVerticalPolicy(QSizePolicy::Expanding);
316 sidebarSplitter->setSizePolicy(sizePolicy);
317 clientLayout->addWidget(sidebarSplitter);
318
319 // view
320 createView();
321
322 // search (in folder) bar
323 searchBar = new KrSearchBar(view, clientArea);
324 searchBar->hide();
325 bool top = group.readEntry("Quicksearch Position", "bottom") == "top";
326 clientLayout->insertWidget(top ? 0 : -1, searchBar);
327
328 // create the layout
329 KrLayoutFactory fact(this, widgets);
330 QLayout *layout = fact.createLayout();
331
332 if(!layout) { // fallback: create a layout by ourself
333 QVBoxLayout *v = new QVBoxLayout;
334 v->setContentsMargins(0, 0, 0, 0);
335 v->setSpacing(0);
336
337 QHBoxLayout *h = new QHBoxLayout;
338 h->setContentsMargins(0, 0, 0, 0);
339 h->setSpacing(0);
340 h->addWidget(urlNavigator);
341 h->addWidget(toolbar);
342 h->addStretch();
343 v->addLayout(h);
344
345 h = new QHBoxLayout;
346 h->setContentsMargins(0, 0, 0, 0);
347 h->setSpacing(0);
348 h->addWidget(mediaButton);
349 h->addWidget(status);
350 h->addWidget(backButton);
351 h->addWidget(forwardButton);
352 h->addWidget(historyButton);
353 h->addWidget(bookmarksButton);
354 v->addLayout(h);
355
356 v->addWidget(fileSystemError);
357 v->addWidget(clientArea);
358
359 h = new QHBoxLayout;
360 h->setContentsMargins(0, 0, 0, 0);
361 h->setSpacing(0);
362 h->addWidget(totals);
363 h->addWidget(freeSpace);
364 h->addWidget(quickSizeCalcProgress);
365 h->addWidget(cancelQuickSizeCalcButton);
366 h->addWidget(previewProgress);
367 h->addWidget(cancelProgressButton);
368 h->addWidget(sidebarButton);
369 v->addLayout(h);
370
371 layout = v;
372 }
373
374 setLayout(layout);
375
376 connect(&KrColorCache::getColorCache(), SIGNAL(colorsRefreshed()), this, SLOT(refreshColors()));
377 connect(krApp, SIGNAL(shutdown()), SLOT(cancelProgress()));
378 }
379
~ListPanel()380 ListPanel::~ListPanel()
381 {
382 view->widget()->removeEventFilter(this);
383 urlNavigator->editor()->removeEventFilter(this);
384 cancelProgress();
385 delete view;
386 view = 0;
387 delete func;
388 delete status;
389 delete bookmarksButton;
390 delete totals;
391 delete urlNavigator;
392 delete cdRootButton;
393 delete cdHomeButton;
394 delete cdUpButton;
395 delete cdOtherButton;
396 delete syncBrowseButton;
397 // delete layout;
398 }
399
reparent(QWidget * parent,AbstractPanelManager * manager)400 void ListPanel::reparent(QWidget *parent, AbstractPanelManager *manager)
401 {
402 setParent(parent);
403 _manager = manager;
404 }
405
defaultPanelType()406 int ListPanel::defaultPanelType()
407 {
408 KConfigGroup group(krConfig, "Look&Feel");
409 return group.readEntry("Default Panel Type", KrViewFactory::defaultViewId());
410 }
411
isNavigatorEditModeSet()412 bool ListPanel::isNavigatorEditModeSet()
413 {
414 KConfigGroup group(krConfig, "Look&Feel");
415 return group.readEntry("Navigator Edit Mode", false);
416 }
417
createView()418 void ListPanel::createView()
419 {
420 view = KrViewFactory::createView(panelType, sidebarSplitter, krConfig);
421 view->init();
422 view->setMainWindow(krApp);
423
424 // KrViewFactory may create a different view type than requested
425 panelType = view->instance()->id();
426
427 if(this == ACTIVE_PANEL)
428 view->prepareForActive();
429 else
430 view->prepareForPassive();
431 view->refreshColors();
432
433 sidebarSplitter->insertWidget(sidebarPosition() < 2 ? 1 : 0, view->widget());
434
435 view->widget()->installEventFilter(this);
436
437 connect(view->op(), &KrViewOperator::quickCalcSpace, func, &ListPanelFunc::quickCalcSpace);
438 connect(view->op(), SIGNAL(goHome()), func, SLOT(home()));
439 connect(view->op(), SIGNAL(dirUp()), func, SLOT(dirUp()));
440 connect(view->op(), &KrViewOperator::defaultDeleteFiles, func, &ListPanelFunc::defaultDeleteFiles);
441 connect(view->op(), SIGNAL(middleButtonClicked(KrViewItem*)), SLOT(newTab(KrViewItem*)));
442 connect(view->op(), SIGNAL(currentChanged(KrViewItem*)), SLOT(slotCurrentChanged(KrViewItem*)));
443 connect(view->op(), SIGNAL(renameItem(QString,QString)),
444 func, SLOT(rename(QString,QString)));
445 connect(view->op(), SIGNAL(executed(QString)), func, SLOT(execute(QString)));
446 connect(view->op(), SIGNAL(goInside(QString)), func, SLOT(goInside(QString)));
447 connect(view->op(), SIGNAL(needFocus()), this, SLOT(slotFocusOnMe()));
448 connect(view->op(), SIGNAL(selectionChanged()), this, SLOT(slotUpdateTotals()));
449 connect(view->op(), SIGNAL(itemDescription(QString)), krApp, SLOT(statusBarUpdate(QString)));
450 connect(view->op(), SIGNAL(contextMenu(QPoint)), this, SLOT(popRightClickMenu(QPoint)));
451 connect(view->op(), SIGNAL(emptyContextMenu(QPoint)),
452 this, SLOT(popEmptyRightClickMenu(QPoint)));
453 connect(view->op(), SIGNAL(letsDrag(QStringList,QPixmap)), this, SLOT(startDragging(QStringList,QPixmap)));
454 connect(view->op(), &KrViewOperator::gotDrop,
455 this, [this](QDropEvent *event) {handleDrop(event, true); });
456 connect(view->op(), SIGNAL(previewJobStarted(KJob*)), this, SLOT(slotPreviewJobStarted(KJob*)));
457 connect(view->op(), SIGNAL(refreshActions()), krApp->viewActions(), SLOT(refreshActions()));
458 connect(view->op(), SIGNAL(currentChanged(KrViewItem*)), func->history, SLOT(saveCurrentItem()));
459 connect(view->op(), &KrViewOperator::goBack, func, &ListPanelFunc::historyBackward);
460 connect(view->op(), &KrViewOperator::goForward, func, &ListPanelFunc::historyForward);
461
462 view->setFiles(func->files());
463
464 func->refreshActions();
465 }
466
changeType(int type)467 void ListPanel::changeType(int type)
468 {
469 if (panelType != type) {
470 QString current = view->getCurrentItem();
471 QList<QUrl> selection = view->selectedUrls();
472 bool filterApplysToDirs = view->properties()->filterApplysToDirs;
473 KrViewProperties::FilterSpec filter = view->filter();
474 FilterSettings filterSettings = view->properties()->filterSettings;
475
476 panelType = type;
477
478 KrView *oldView = view;
479 createView();
480 searchBar->setView(view);
481 delete oldView;
482
483 view->setFilter(filter, filterSettings, filterApplysToDirs);
484 view->setSelectionUrls(selection);
485 view->setCurrentItem(current);
486 view->makeItemVisible(view->getCurrentKrViewItem());
487 }
488 }
489
getProperties()490 int ListPanel::getProperties()
491 {
492 int props = 0;
493 if (syncBrowseButton->isChecked()) {
494 props |= PROP_SYNC_BUTTON_ON;
495 }
496 if (isLocked()) {
497 props |= PROP_LOCKED;
498 } else if (isPinned()) {
499 props |= PROP_PINNED;
500 }
501 return props;
502 }
503
setProperties(int prop)504 void ListPanel::setProperties(int prop)
505 {
506 syncBrowseButton->setChecked(prop & PROP_SYNC_BUTTON_ON);
507 if (prop & PROP_LOCKED) {
508 _tabState = TabState::LOCKED;
509 } else if (prop & PROP_PINNED) {
510 _tabState = TabState::PINNED;
511 } else {
512 _tabState = TabState::DEFAULT;
513 }
514 }
515
eventFilter(QObject * watched,QEvent * e)516 bool ListPanel::eventFilter(QObject * watched, QEvent * e)
517 {
518 if(view && watched == view->widget()) {
519 if(e->type() == QEvent::FocusIn && this != ACTIVE_PANEL && !isHidden())
520 slotFocusOnMe();
521 else if(e->type() == QEvent::ShortcutOverride) {
522 QKeyEvent *ke = static_cast<QKeyEvent*>(e);
523 if(ke->key() == Qt::Key_Escape && ke->modifiers() == Qt::NoModifier) {
524 // if the cancel refresh action has no shortcut assigned,
525 // we need this event ourselves to cancel refresh
526 if(_actions->actCancelRefresh->shortcut().isEmpty()) {
527 e->accept();
528 return true;
529 }
530 }
531 }
532 }
533 // handle URL navigator key events
534 else if(urlNavigator && watched == urlNavigator->editor()) {
535 // override default shortcut for panel focus
536 if(e->type() == QEvent::ShortcutOverride) {
537 QKeyEvent *ke = static_cast<QKeyEvent *>(e);
538 if ((ke->key() == Qt::Key_Escape) && (ke->modifiers() == Qt::NoModifier)) {
539 e->accept(); // we will get the key press event now
540 return true;
541 }
542 } else if(e->type() == QEvent::KeyPress) {
543 QKeyEvent *ke = static_cast<QKeyEvent *>(e);
544 if ((ke->key() == Qt::Key_Down) && (ke->modifiers() == Qt::ControlModifier)) {
545 slotFocusOnMe();
546 return true;
547 } else if ((ke->key() == Qt::Key_Escape) && (ke->modifiers() == Qt::NoModifier)) {
548 // reset navigator
549 urlNavigator->editor()->setUrl(urlNavigator->locationUrl());
550 slotFocusOnMe();
551 return true;
552 }
553 }
554 }
555 return false;
556 }
557
toggleSidebar()558 void ListPanel::toggleSidebar()
559 {
560 if(!sidebar) {
561 sidebar = new Sidebar(sidebarSplitter);
562 // fix vertical grow of splitter (and entire window) if its content
563 // demands more space
564 QSizePolicy sizePolicy = sidebar->sizePolicy();
565 sizePolicy.setVerticalPolicy(QSizePolicy::Ignored);
566 sidebar->setSizePolicy(sizePolicy);
567 connect(this, &ListPanel::pathChanged, sidebar, &Sidebar::onPanelPathChange);
568 connect(sidebar, &Sidebar::urlActivated, SLOTS, &KRslots::refresh);
569 sidebarSplitter->insertWidget(0, sidebar);
570 }
571
572 if (sidebar->isHidden()) {
573 if (sidebarSplitterSizes.count() > 0) {
574 sidebarSplitter->setSizes(sidebarSplitterSizes);
575 } else { // on the first time, resize to 50%
576 QList<int> lst;
577 lst << height() / 2 << height() / 2;
578 sidebarSplitter->setSizes(lst);
579 }
580
581 sidebar->show();
582 sidebarButton->setIcon(Icon("arrow-down"));
583 sidebarButton->setToolTip(i18n("Close the Sidebar"));
584 sidebarPositionButton->show();
585 } else {
586 sidebarSplitterSizes.clear();
587 sidebarSplitterSizes = sidebarSplitter->sizes();
588 sidebar->hide();
589 sidebarButton->setIcon(Icon("arrow-up"));
590 sidebarButton->setToolTip(i18n("Open the Sidebar"));
591 sidebarPositionButton->hide();
592
593 QList<int> lst;
594 lst << height() << 0;
595 sidebarSplitter->setSizes(lst);
596 if (ACTIVE_PANEL)
597 ACTIVE_PANEL->gui->slotFocusOnMe();
598 }
599 }
600
lastLocalPath() const601 QString ListPanel::lastLocalPath() const
602 {
603 return _lastLocalPath;
604 }
605
setButtons()606 void ListPanel::setButtons()
607 {
608 KConfigGroup group(krConfig, "Look&Feel");
609
610 mediaButton->setVisible(group.readEntry("Media Button Visible", true));
611 backButton->setVisible(group.readEntry("Back Button Visible", false));
612 forwardButton->setVisible(group.readEntry("Forward Button Visible", false));
613 historyButton->setVisible(group.readEntry("History Button Visible", true));
614 bookmarksButton->setVisible(group.readEntry("Bookmarks Button Visible", true));
615
616 if (group.readEntry("Panel Toolbar visible", _PanelToolBar)) {
617 cdRootButton->setVisible(group.readEntry("Root Button Visible", _cdRoot));
618 cdHomeButton->setVisible(group.readEntry("Home Button Visible", _cdHome));
619 cdUpButton->setVisible(group.readEntry("Up Button Visible", _cdUp));
620 cdOtherButton->setVisible(group.readEntry("Equal Button Visible", _cdOther));
621 syncBrowseButton->setVisible(group.readEntry("SyncBrowse Button Visible", _syncBrowseButton));
622 } else {
623 cdRootButton->hide();
624 cdHomeButton->hide();
625 cdUpButton->hide();
626 cdOtherButton->hide();
627 syncBrowseButton->hide();
628 }
629 }
630
slotUpdateTotals()631 void ListPanel::slotUpdateTotals()
632 {
633 totals->setText(view->statistics());
634 }
635
compareDirs(bool otherPanelToo)636 void ListPanel::compareDirs(bool otherPanelToo)
637 {
638 // Performs a check in order to avoid that the next code is executed twice
639 if (otherPanelToo == true) {
640 // If both panels are showing the same directory
641 if (_manager->currentPanel()->virtualPath() == otherPanel()->virtualPath()) {
642 if (KMessageBox::warningContinueCancel(this,
643 i18n("Warning: The left and the right side are showing the same folder.")) != KMessageBox::Continue) {
644 return;
645 }
646 }
647 }
648
649 KConfigGroup pg(krConfig, "Private");
650 int compareMode = pg.readEntry("Compare Mode", 0);
651 KConfigGroup group(krConfig, "Look&Feel");
652 bool selectDirs = group.readEntry("Mark Dirs", false);
653
654 KrViewItem *item, *otherItem;
655
656 for (item = view->getFirst(); item != 0; item = view->getNext(item)) {
657 if (item->name() == "..")
658 continue;
659
660 for (otherItem = otherPanel()->view->getFirst(); otherItem != 0 && otherItem->name() != item->name();
661 otherItem = otherPanel()->view->getNext(otherItem));
662
663 bool isSingle = (otherItem == 0), isDifferent = false, isNewer = false;
664
665 if (func->getFileItem(item)->isDir() && !selectDirs) {
666 item->setSelected(false);
667 continue;
668 }
669
670 if (otherItem) {
671 if (!func->getFileItem(item)->isDir())
672 isDifferent = otherPanel()->func->getFileItem(otherItem)->getSize() != func->getFileItem(item)->getSize();
673 isNewer = func->getFileItem(item)->getModificationTime() > otherPanel()->func->getFileItem(otherItem)->getModificationTime();
674 }
675
676 switch (compareMode) {
677 case 0:
678 item->setSelected(isNewer || isSingle);
679 break;
680 case 1:
681 item->setSelected(isNewer);
682 break;
683 case 2:
684 item->setSelected(isSingle);
685 break;
686 case 3:
687 item->setSelected(isDifferent || isSingle);
688 break;
689 case 4:
690 item->setSelected(isDifferent);
691 break;
692 }
693 }
694
695 view->updateView();
696
697 if (otherPanelToo)
698 otherPanel()->gui->compareDirs(false);
699 }
700
refreshColors()701 void ListPanel::refreshColors()
702 {
703 view->refreshColors();
704 emit refreshColors(this == ACTIVE_PANEL);
705 }
706
slotFocusOnMe(bool focus)707 void ListPanel::slotFocusOnMe(bool focus)
708 {
709 if (focus && _manager->currentPanel() != this) {
710 // ignore focus request if this panel is not shown
711 return;
712 }
713
714 krApp->setUpdatesEnabled(false);
715
716 if(focus) {
717 emit activate();
718 _actions->activePanelChanged();
719 func->refreshActions();
720 slotCurrentChanged(view->getCurrentKrViewItem());
721 view->prepareForActive();
722 otherPanel()->gui->slotFocusOnMe(false);
723 } else {
724 // in case a new url was entered but not refreshed to,
725 // reset url navigator to the current url
726 setNavigatorUrl(virtualPath());
727 view->prepareForPassive();
728 }
729
730 urlNavigator->setActive(focus);
731 refreshColors();
732
733 krApp->setUpdatesEnabled(true);
734 }
735
736 // this is used to start the panel
737 //////////////////////////////////////////////////////////////////
start(const QUrl & url)738 void ListPanel::start(const QUrl &url)
739 {
740 QUrl startUrl(url);
741
742 if (!startUrl.isValid())
743 startUrl = QUrl::fromLocalFile(ROOT_DIR);
744
745 _lastLocalPath = startUrl.isLocalFile() ? startUrl.path() : ROOT_DIR;
746
747
748 func->openUrl(startUrl);
749
750 setJumpBack(startUrl);
751 }
752
slotStartUpdate(bool directoryChange)753 void ListPanel::slotStartUpdate(bool directoryChange)
754 {
755 if (inlineRefreshJob)
756 inlineRefreshListResult(0);
757
758 setCursor(Qt::BusyCursor);
759
760 const QUrl currentUrl = virtualPath();
761 if (directoryChange) {
762
763 if (this == ACTIVE_PANEL) {
764 slotFocusOnMe();
765 }
766
767 if (currentUrl.isLocalFile())
768 _lastLocalPath = currentUrl.path();
769
770 setNavigatorUrl(currentUrl);
771
772 emit pathChanged(currentUrl);
773
774 krApp->popularUrls()->addUrl(currentUrl);
775
776 searchBar->hideBar();
777 }
778
779 if (compareMode)
780 otherPanel()->view->refresh();
781
782 // return cursor to normal arrow
783 setCursor(Qt::ArrowCursor);
784
785 slotUpdateTotals();
786 }
787
updateFilesystemStats(const QString & metaInfo,const QString & fsType,KIO::filesize_t total,KIO::filesize_t free)788 void ListPanel::updateFilesystemStats(const QString &metaInfo, const QString &fsType,
789 KIO::filesize_t total, KIO::filesize_t free)
790 {
791 QString statusText, mountPoint, freeSpaceText;
792
793 if (!metaInfo.isEmpty()) {
794 statusText = metaInfo;
795 mountPoint = freeSpaceText = "";
796 } else {
797 const int perc = total == 0 ? 0 : (int)(((float)free / (float)total) * 100.0);
798 mountPoint = func->files()->mountPoint();
799 statusText = i18nc("%1=free space,%2=total space,%3=percentage of usage, "
800 "%4=mountpoint,%5=filesystem type",
801 "%1 free out of %2 (%3%) on %4 [(%5)]", KIO::convertSize(free),
802 KIO::convertSize(total), perc, mountPoint, fsType);
803
804 freeSpaceText = " " + i18n("%1 free", KIO::convertSize(free));
805 }
806
807 status->setText(statusText);
808 freeSpace->setText(freeSpaceText);
809 mediaButton->updateIcon(mountPoint);
810 }
811
handleDrop(QDropEvent * event,bool onView)812 void ListPanel::handleDrop(QDropEvent *event, bool onView)
813 {
814 // check what was dropped
815 const QList<QUrl> urls = KUrlMimeData::urlsFromMimeData(event->mimeData());
816 if (urls.isEmpty()) {
817 event->ignore(); // not for us to handle!
818 return;
819 }
820
821 // find dropping destination
822 QString destinationDir = "";
823 const bool dragFromThisPanel = event->source() == this;
824 const KrViewItem *item = onView ? view->getKrViewItemAt(event->pos()) : 0;
825 if (item) {
826 const FileItem *file = item->getFileItem();
827 if (file && !file->isDir() && dragFromThisPanel) {
828 event->ignore(); // dragging on files in same panel, ignore
829 return;
830 } else if (!file || file->isDir()) { // item is ".." dummy or a directory
831 destinationDir = item->name();
832 }
833 } else if (dragFromThisPanel) {
834 event->ignore(); // dragged from this panel onto an empty spot in this panel, ignore
835 return;
836 }
837
838 QUrl destination = QUrl(virtualPath());
839 destination.setPath(destination.path() + '/' + destinationDir);
840
841 func->files()->dropFiles(destination, event);
842
843 if(KConfigGroup(krConfig, "Look&Feel").readEntry("UnselectBeforeOperation",
844 _UnselectBeforeOperation)) {
845 KrPanel *p = dragFromThisPanel ? this : otherPanel();
846 p->view->saveSelection();
847 p->view->unselectAll();
848 }
849 }
850
handleDrop(const QUrl & destination,QDropEvent * event)851 void ListPanel::handleDrop(const QUrl &destination, QDropEvent *event)
852 {
853 func->files()->dropFiles(destination, event);
854 }
855
startDragging(QStringList names,QPixmap px)856 void ListPanel::startDragging(QStringList names, QPixmap px)
857 {
858 if (names.isEmpty()) { // avoid dragging empty urls
859 return;
860 }
861
862 QList<QUrl> urls = func->files()->getUrls(names);
863
864 QDrag *drag = new QDrag(this);
865 QMimeData *mimeData = new QMimeData;
866 drag->setPixmap(px);
867 mimeData->setUrls(urls);
868 drag->setMimeData(mimeData);
869
870 drag->start(Qt::MoveAction | Qt::CopyAction | Qt::LinkAction);
871 }
872
873 // pops a right-click menu for items
popRightClickMenu(const QPoint & loc)874 void ListPanel::popRightClickMenu(const QPoint &loc)
875 {
876 // run it, on the mouse location
877 int j = QFontMetrics(font()).height() * 2;
878 PanelContextMenu::run(QPoint(loc.x() + 5, loc.y() + j), this);
879 }
880
popEmptyRightClickMenu(const QPoint & loc)881 void ListPanel::popEmptyRightClickMenu(const QPoint &loc)
882 {
883 PanelContextMenu::run(loc, this);
884 }
885
getCurrentName() const886 QString ListPanel::getCurrentName() const
887 {
888 const QString name = view->getCurrentItem();
889 return name == ".." ? QString() : name;
890 }
891
getSelectedNames()892 QStringList ListPanel::getSelectedNames()
893 {
894 QStringList fileNames;
895 view->getSelectedItems(&fileNames);
896 return fileNames;
897 }
898
prepareToDelete()899 void ListPanel::prepareToDelete()
900 {
901 const bool skipCurrent = (view->numSelected() == 0);
902 view->setNameToMakeCurrent(view->firstUnmarkedBelowCurrent(skipCurrent));
903 }
904
keyPressEvent(QKeyEvent * e)905 void ListPanel::keyPressEvent(QKeyEvent *e)
906 {
907 switch (e->key()) {
908 case Qt::Key_Enter :
909 case Qt::Key_Return :
910 if (e->modifiers() & Qt::ControlModifier) {
911 if (e->modifiers() & Qt::AltModifier) {
912 FileItem *fileitem =
913 func->files()->getFileItem(view->getCurrentKrViewItem()->name());
914 if (fileitem && fileitem->isDir())
915 newTab(fileitem->getUrl(), true);
916 } else {
917 SLOTS->insertFileName((e->modifiers() & Qt::ShiftModifier) != 0);
918 }
919 } else {
920 e->ignore();
921 }
922 break;
923 case Qt::Key_Right :
924 case Qt::Key_Left :
925 if (e->modifiers() == Qt::ControlModifier) {
926 // user pressed CTRL+Right/Left - refresh other panel to the selected path if it's a
927 // directory otherwise as this one
928 if ((isLeft() && e->key() == Qt::Key_Right) || (!isLeft() && e->key() == Qt::Key_Left)) {
929 QUrl newPath;
930 KrViewItem *it = view->getCurrentKrViewItem();
931
932 if (it->name() == "..") {
933 newPath = KIO::upUrl(virtualPath());
934 } else {
935 FileItem *v = func->getFileItem(it);
936 // If it's a directory different from ".."
937 if (v && v->isDir() && v->getName() != "..") {
938 newPath = v->getUrl();
939 } else {
940 // If it's a supported compressed file
941 if (v && KRarcHandler::arcSupported(v->getMime())) {
942 newPath = func->browsableArchivePath(v->getUrl().fileName());
943 } else {
944 newPath = virtualPath();
945 }
946 }
947 }
948 otherPanel()->func->openUrl(newPath);
949 } else {
950 func->openUrl(otherPanel()->virtualPath());
951 }
952 return;
953 } else
954 e->ignore();
955 break;
956 case Qt::Key_Down :
957 if (e->modifiers() == Qt::ControlModifier) { // give the keyboard focus to the command line
958 if (MAIN_VIEW->cmdLine()->isVisible())
959 MAIN_VIEW->cmdLineFocus();
960 else
961 MAIN_VIEW->focusTerminalEmulator();
962 return;
963 } else if (e->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { // give the keyboard focus to TE
964 MAIN_VIEW->focusTerminalEmulator();
965 } else
966 e->ignore();
967 break;
968
969 case Qt::Key_Up :
970 if (e->modifiers() == Qt::ControlModifier) { // give the keyboard focus to the url navigator
971 editLocation();
972 return;
973 } else
974 e->ignore();
975 break;
976
977 case Qt::Key_Escape:
978 cancelProgress();
979 break;
980
981 default:
982 // if we got this, it means that the view is not doing
983 // the quick search thing, so send the characters to the commandline, if normal key
984 if (e->modifiers() == Qt::NoModifier)
985 MAIN_VIEW->cmdLine()->addText(e->text());
986
987 //e->ignore();
988 }
989 }
990
showEvent(QShowEvent * e)991 void ListPanel::showEvent(QShowEvent *e)
992 {
993 panelVisible();
994 QWidget::showEvent(e);
995 }
996
hideEvent(QHideEvent * e)997 void ListPanel::hideEvent(QHideEvent *e)
998 {
999 panelHidden();
1000 QWidget::hideEvent(e);
1001 }
1002
panelVisible()1003 void ListPanel::panelVisible()
1004 {
1005 func->setPaused(false);
1006 }
1007
panelHidden()1008 void ListPanel::panelHidden()
1009 {
1010 func->setPaused(true);
1011 }
1012
slotPreviewJobStarted(KJob * job)1013 void ListPanel::slotPreviewJobStarted(KJob *job)
1014 {
1015 previewJob = job;
1016 connect(job, SIGNAL(percent(KJob*,ulong)), SLOT(slotPreviewJobPercent(KJob*,ulong)));
1017 connect(job, &KJob::result, this, &ListPanel::slotPreviewJobResult);
1018 cancelProgressButton->setMaximumHeight(sidebarButton->height());
1019 cancelProgressButton->show();
1020 previewProgress->setValue(0);
1021 previewProgress->setFormat(i18n("loading previews: %p%"));
1022 previewProgress->setMaximumHeight(cancelProgressButton->height());
1023 previewProgress->show();
1024 }
1025
slotPreviewJobPercent(KJob *,unsigned long percent)1026 void ListPanel::slotPreviewJobPercent(KJob* /*job*/, unsigned long percent)
1027 {
1028 previewProgress->setValue(percent);
1029 }
1030
slotPreviewJobResult(KJob *)1031 void ListPanel::slotPreviewJobResult(KJob* /*job*/)
1032 {
1033 previewJob = 0;
1034 previewProgress->hide();
1035 if(!inlineRefreshJob)
1036 cancelProgressButton->hide();
1037 }
1038
slotRefreshJobStarted(KIO::Job * job)1039 void ListPanel::slotRefreshJobStarted(KIO::Job* job)
1040 {
1041 // disable the parts of the panel we don't want touched
1042 status->setEnabled(false);
1043 urlNavigator->setEnabled(false);
1044 cdRootButton->setEnabled(false);
1045 cdHomeButton->setEnabled(false);
1046 cdUpButton->setEnabled(false);
1047 cdOtherButton->setEnabled(false);
1048 sidebarButton->setEnabled(false);
1049 if(sidebar)
1050 sidebar->setEnabled(false);
1051 bookmarksButton->setEnabled(false);
1052 historyButton->setEnabled(false);
1053 syncBrowseButton->setEnabled(false);
1054
1055 // connect to the job interface to provide in-panel refresh notification
1056 connect(job, SIGNAL(infoMessage(KJob*,QString)),
1057 SLOT(inlineRefreshInfoMessage(KJob*,QString)));
1058 connect(job, SIGNAL(percent(KJob*,ulong)),
1059 SLOT(inlineRefreshPercent(KJob*,ulong)));
1060 connect(job, SIGNAL(result(KJob*)),
1061 this, SLOT(inlineRefreshListResult(KJob*)));
1062
1063 inlineRefreshJob = job;
1064
1065 totals->setText(i18n(">> Reading..."));
1066 cancelProgressButton->show();
1067 }
1068
cancelProgress()1069 void ListPanel::cancelProgress()
1070 {
1071 if (inlineRefreshJob) {
1072 disconnect(inlineRefreshJob, 0, this, 0);
1073 inlineRefreshJob->kill(KJob::EmitResult);
1074 inlineRefreshListResult(0);
1075 }
1076 if(previewJob) {
1077 disconnect(previewJob, 0, this, 0);
1078 previewJob->kill(KJob::EmitResult);
1079 slotPreviewJobResult(0);
1080 }
1081 }
1082
setNavigatorUrl(const QUrl & url)1083 void ListPanel::setNavigatorUrl(const QUrl &url)
1084 {
1085 _navigatorUrl = url;
1086 urlNavigator->setLocationUrl(url);
1087 }
1088
inlineRefreshPercent(KJob *,unsigned long perc)1089 void ListPanel::inlineRefreshPercent(KJob*, unsigned long perc)
1090 {
1091 QString msg = i18n(">> Reading: %1 % complete...", perc);
1092 totals->setText(msg);
1093 }
1094
inlineRefreshInfoMessage(KJob *,const QString & msg)1095 void ListPanel::inlineRefreshInfoMessage(KJob*, const QString &msg)
1096 {
1097 totals->setText(i18n(">> Reading: %1", msg));
1098 }
1099
inlineRefreshListResult(KJob *)1100 void ListPanel::inlineRefreshListResult(KJob*)
1101 {
1102 if(inlineRefreshJob)
1103 disconnect(inlineRefreshJob, 0, this, 0);
1104 inlineRefreshJob = 0;
1105 // reenable everything
1106 status->setEnabled(true);
1107 urlNavigator->setEnabled(true);
1108 cdRootButton->setEnabled(true);
1109 cdHomeButton->setEnabled(true);
1110 cdUpButton->setEnabled(true);
1111 cdOtherButton->setEnabled(true);
1112 sidebarButton->setEnabled(true);
1113 if(sidebar)
1114 sidebar->setEnabled(true);
1115 bookmarksButton->setEnabled(true);
1116 historyButton->setEnabled(true);
1117 syncBrowseButton->setEnabled(true);
1118
1119 if(!previewJob)
1120 cancelProgressButton->hide();
1121 }
1122
jumpBack()1123 void ListPanel::jumpBack()
1124 {
1125 func->openUrl(_jumpBackURL);
1126 }
1127
setJumpBack(QUrl url)1128 void ListPanel::setJumpBack(QUrl url)
1129 {
1130 _jumpBackURL = url;
1131 }
1132
slotFilesystemError(QString msg)1133 void ListPanel::slotFilesystemError(QString msg)
1134 {
1135 refreshColors();
1136 fileSystemError->setText(i18n("Error: %1", msg));
1137 fileSystemError->show();
1138 }
1139
showButtonMenu(QToolButton * b)1140 void ListPanel::showButtonMenu(QToolButton *b)
1141 {
1142 if(this != ACTIVE_PANEL)
1143 slotFocusOnMe();
1144
1145 if(b->isHidden())
1146 b->menu()->exec(mapToGlobal(clientArea->pos()));
1147 else
1148 b->click();
1149 }
1150
openBookmarks()1151 void ListPanel::openBookmarks()
1152 {
1153 showButtonMenu(bookmarksButton);
1154 }
1155
openHistory()1156 void ListPanel::openHistory()
1157 {
1158 showButtonMenu(historyButton);
1159 }
1160
openMedia()1161 void ListPanel::openMedia()
1162 {
1163 showButtonMenu(mediaButton);
1164 }
1165
rightclickMenu()1166 void ListPanel::rightclickMenu()
1167 {
1168 if (view->getCurrentKrViewItem())
1169 popRightClickMenu(mapToGlobal(view->getCurrentKrViewItem()->itemRect().topLeft()));
1170 }
1171
toggleSyncBrowse()1172 void ListPanel::toggleSyncBrowse()
1173 {
1174 syncBrowseButton->toggle();
1175 }
1176
editLocation()1177 void ListPanel::editLocation()
1178 {
1179 urlNavigator->setUrlEditable(true);
1180 urlNavigator->setFocus();
1181 urlNavigator->editor()->lineEdit()->selectAll();
1182 }
1183
showSearchBar()1184 void ListPanel::showSearchBar()
1185 {
1186 searchBar->showBar(KrSearchBar::MODE_SEARCH);
1187 }
1188
showSearchBarSelection()1189 void ListPanel::showSearchBarSelection()
1190 {
1191 searchBar->showBar(KrSearchBar::MODE_SELECT);
1192 }
1193
showSearchBarFilter()1194 void ListPanel::showSearchBarFilter()
1195 {
1196 searchBar->showBar(KrSearchBar::MODE_FILTER);
1197 }
1198
saveSettings(KConfigGroup cfg,bool saveHistory)1199 void ListPanel::saveSettings(KConfigGroup cfg, bool saveHistory)
1200 {
1201 QUrl url = virtualPath();
1202 url.setPassword(QString()); // make sure no password is saved
1203 cfg.writeEntry("Url", url.toString());
1204 cfg.writeEntry("Type", getType());
1205 cfg.writeEntry("Properties", getProperties());
1206 cfg.writeEntry("PinnedUrl", pinnedUrl().toString());
1207 if(saveHistory)
1208 func->history->save(KConfigGroup(&cfg, "History"));
1209 view->saveSettings(KConfigGroup(&cfg, "View"));
1210
1211 // splitter/sidebar state
1212 if (sidebar && !sidebar->isHidden()) {
1213 sidebar->saveSettings(KConfigGroup(&cfg, "PanelPopup"));
1214 cfg.writeEntry("PopupPosition", sidebarPosition());
1215 cfg.writeEntry("SplitterSizes", sidebarSplitter->saveState());
1216 cfg.writeEntry("PopupPage", sidebar->currentPage());
1217 } else {
1218 cfg.deleteEntry("PopupPosition");
1219 cfg.deleteEntry("SplitterSizes");
1220 cfg.deleteEntry("PopupPage");
1221 }
1222 }
1223
restoreSettings(KConfigGroup cfg)1224 void ListPanel::restoreSettings(KConfigGroup cfg)
1225 {
1226 changeType(cfg.readEntry("Type", defaultPanelType()));
1227 view->restoreSettings(KConfigGroup(&cfg, "View"));
1228
1229 // "locked" property must be set after URL path is restored!
1230 // This panel can be reused when loading a profile,
1231 // so we reset its properties before calling openUrl().
1232 setProperties(0);
1233
1234 _lastLocalPath = ROOT_DIR;
1235 if(func->history->restore(KConfigGroup(&cfg, "History"))) {
1236 func->refresh();
1237 } else {
1238 QUrl url(cfg.readEntry("Url", "invalid"));
1239 if (!url.isValid())
1240 url = QUrl::fromLocalFile(ROOT_DIR);
1241 func->openUrl(url);
1242 }
1243
1244 setJumpBack(func->history->currentUrl());
1245
1246 setProperties(cfg.readEntry("Properties", 0));
1247
1248 if (isPinned()) {
1249 QUrl pinnedUrl(cfg.readEntry("PinnedUrl", "invalid"));
1250 if (!pinnedUrl.isValid()) {
1251 pinnedUrl = func->history->currentUrl();
1252 }
1253 func->openUrl(pinnedUrl);
1254 setPinnedUrl(pinnedUrl);
1255 }
1256
1257 if (cfg.hasKey("PopupPosition")) { // sidebar was visible, restore
1258 toggleSidebar(); // create and show
1259 sidebar->restoreSettings(KConfigGroup(&cfg, "PanelPopup"));
1260 setSidebarPosition(cfg.readEntry("PopupPosition", 42 /* dummy */));
1261 sidebarSplitter->restoreState(cfg.readEntry("SplitterSizes", QByteArray()));
1262 sidebar->setCurrentPage(cfg.readEntry("PopupPage", 0));
1263 }
1264 }
1265
slotCurrentChanged(KrViewItem * item)1266 void ListPanel::slotCurrentChanged(KrViewItem *item)
1267 {
1268 // update status bar
1269 if (item)
1270 krApp->statusBarUpdate(item->description());
1271
1272 // update sidebar; which panel to display on?
1273 Sidebar *p;
1274 if (sidebar && !sidebar->isHidden()) {
1275 p = sidebar;
1276 } else if(otherPanel()->gui->sidebar && !otherPanel()->gui->sidebar->isHidden()) {
1277 p = otherPanel()->gui->sidebar;
1278 } else {
1279 return;
1280 }
1281
1282 p->update(item ? func->files()->getFileItem(item->name()) : nullptr);
1283 }
1284
otherPanelChanged()1285 void ListPanel::otherPanelChanged()
1286 {
1287 func->syncURL = QUrl();
1288 }
1289
getFocusCandidates(QVector<QWidget * > & widgets)1290 void ListPanel::getFocusCandidates(QVector<QWidget*> &widgets)
1291 {
1292 if(urlNavigator->editor()->isVisible())
1293 widgets << urlNavigator->editor();
1294 if(view->widget()->isVisible())
1295 widgets << view->widget();
1296 if(sidebar && sidebar->isVisible())
1297 widgets << sidebar;
1298 }
1299
updateButtons()1300 void ListPanel::updateButtons()
1301 {
1302 backButton->setEnabled(func->history->canGoBack());
1303 forwardButton->setEnabled(func->history->canGoForward());
1304 historyButton->setEnabled(func->history->count() > 1);
1305 cdRootButton->setEnabled(!virtualPath().matches(QUrl::fromLocalFile(ROOT_DIR),
1306 QUrl::StripTrailingSlash));
1307 cdUpButton->setEnabled(!func->files()->isRoot());
1308 cdHomeButton->setEnabled(!func->atHome());
1309 }
1310
newTab(KrViewItem * it)1311 void ListPanel::newTab(KrViewItem *it)
1312 {
1313 if (!it)
1314 return;
1315 else if (it->name() == "..") {
1316 newTab(KIO::upUrl(virtualPath()), true);
1317 } else if (func->getFileItem(it)->isDir()) {
1318 QUrl url = virtualPath();
1319 url = url.adjusted(QUrl::StripTrailingSlash);
1320 url.setPath(url.path() + '/' + (it->name()));
1321 newTab(url, true);
1322 }
1323 }
1324
newTab(const QUrl & url,bool nextToThis)1325 void ListPanel::newTab(const QUrl &url, bool nextToThis)
1326 {
1327 _manager->newTab(url, nextToThis ? this : 0);
1328 }
1329
slotNavigatorUrlChanged(const QUrl & url)1330 void ListPanel::slotNavigatorUrlChanged(const QUrl &url)
1331 {
1332 if (url == _navigatorUrl)
1333 return; // this is the URL we just set ourself
1334
1335 if (!isNavigatorEditModeSet()) {
1336 urlNavigator->setUrlEditable(false);
1337 }
1338
1339 func->openUrl(KrServices::escapeFileUrl(url), QString(), true);
1340 }
1341
resetNavigatorMode()1342 void ListPanel::resetNavigatorMode()
1343 {
1344 if (isNavigatorEditModeSet())
1345 return;
1346
1347 // set to "navigate" mode if url wasn't changed
1348 if (urlNavigator->uncommittedUrl().matches(virtualPath(), QUrl::StripTrailingSlash)) {
1349 // NOTE: this also sets focus to the navigator
1350 urlNavigator->setUrlEditable(false);
1351 slotFocusOnMe();
1352 }
1353 }
1354
sidebarPosition() const1355 int ListPanel::sidebarPosition() const
1356 {
1357 int pos = sidebarSplitter->orientation() == Qt::Vertical ? 1 : 0;
1358 return pos + (qobject_cast<Sidebar*>(sidebarSplitter->widget(0)) == NULL ? 2 : 0);
1359 }
1360
setSidebarPosition(int pos)1361 void ListPanel::setSidebarPosition(int pos)
1362 {
1363 sidebarSplitter->setOrientation(pos % 2 == 0 ? Qt::Horizontal : Qt::Vertical);
1364 if ((pos < 2) != (qobject_cast<Sidebar*>(sidebarSplitter->widget(0)) != NULL)) {
1365 sidebarSplitter->insertWidget(0, sidebarSplitter->widget(1)); // swapping widgets in splitter
1366 }
1367 }
1368
connectQuickSizeCalculator(SizeCalculator * sizeCalculator)1369 void ListPanel::connectQuickSizeCalculator(SizeCalculator *sizeCalculator)
1370 {
1371 connect(sizeCalculator, &SizeCalculator::started, this, [=]() {
1372 quickSizeCalcProgress->reset();
1373 quickSizeCalcProgress->show();
1374 cancelQuickSizeCalcButton->show();
1375 });
1376 connect(cancelQuickSizeCalcButton, &QToolButton::clicked, sizeCalculator, &SizeCalculator::cancel);
1377 connect(sizeCalculator, &SizeCalculator::progressChanged, quickSizeCalcProgress, &QProgressBar::setValue);
1378 connect(sizeCalculator, &SizeCalculator::finished, this, [=]() {
1379 cancelQuickSizeCalcButton->hide();
1380 quickSizeCalcProgress->hide();
1381 });
1382 }
1383