00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "kurlnavigator.h"
00023
00024 #include "kfileplacesselector_p.h"
00025 #include "kprotocolcombo_p.h"
00026 #include "kurldropdownbutton_p.h"
00027 #include "kurlnavigatorbutton_p.h"
00028 #include "kurltogglebutton_p.h"
00029
00030 #include <kfileitem.h>
00031 #include <kfileplacesmodel.h>
00032 #include <kglobalsettings.h>
00033 #include <kicon.h>
00034 #include <klineedit.h>
00035 #include <klocale.h>
00036 #include <kmenu.h>
00037 #include <kprotocolinfo.h>
00038 #include <kurlcombobox.h>
00039 #include <kurlcompletion.h>
00040
00041 #include <QtCore/QDir>
00042 #include <QtCore/QLinkedList>
00043 #include <QtCore/QTimer>
00044 #include <QtGui/QApplication>
00045 #include <QtGui/QBoxLayout>
00046 #include <QtGui/QClipboard>
00047 #include <QtGui/QDropEvent>
00048 #include <QtGui/QKeyEvent>
00049 #include <QtGui/QLabel>
00050 #include <QtGui/QPainter>
00051 #include <QtGui/QStyleOption>
00052
00053 #include <fixx11h.h>
00054
00061 class HistoryElem
00062 {
00063 public:
00064 HistoryElem();
00065 HistoryElem(const KUrl& url);
00066 ~HistoryElem();
00067
00068 const KUrl& url() const;
00069
00070 void setRootUrl(const KUrl& url);
00071 const KUrl& rootUrl() const;
00072
00073 void setContentsX(int x);
00074 int contentsX() const;
00075
00076 void setContentsY(int y);
00077 int contentsY() const;
00078
00079 private:
00080 KUrl m_url;
00081 KUrl m_rootUrl;
00082 int m_contentsX;
00083 int m_contentsY;
00084 };
00085
00086 HistoryElem::HistoryElem() :
00087 m_url(),
00088 m_rootUrl(),
00089 m_contentsX(0),
00090 m_contentsY(0)
00091 {
00092 }
00093
00094 HistoryElem::HistoryElem(const KUrl& url) :
00095 m_url(url),
00096 m_rootUrl(),
00097 m_contentsX(0),
00098 m_contentsY(0)
00099 {
00100 }
00101
00102 HistoryElem::~HistoryElem()
00103 {
00104 }
00105
00106 inline const KUrl& HistoryElem::url() const
00107 {
00108 return m_url;
00109 }
00110
00111 inline void HistoryElem::setRootUrl(const KUrl& url)
00112 {
00113 m_rootUrl = url;
00114 }
00115
00116 inline const KUrl& HistoryElem::rootUrl() const
00117 {
00118 return m_rootUrl;
00119 }
00120
00121 inline void HistoryElem::setContentsX(int x)
00122 {
00123 m_contentsX = x;
00124 }
00125
00126 inline int HistoryElem::contentsX() const
00127 {
00128 return m_contentsX;
00129 }
00130
00131 inline void HistoryElem::setContentsY(int y)
00132 {
00133 m_contentsY = y;
00134 }
00135
00136 inline int HistoryElem::contentsY() const
00137 {
00138 return m_contentsY;
00139 }
00140
00142
00143 class KUrlNavigator::Private
00144 {
00145 public:
00146 Private(KUrlNavigator* q, KFilePlacesModel* placesModel);
00147
00148 void slotReturnPressed();
00149 void slotRemoteHostActivated();
00150 void slotProtocolChanged(const QString&);
00151 void openPathSelectorMenu();
00152
00158 void appendWidget(QWidget* widget, int stretch = 0);
00159
00165 void switchView();
00166
00168 void dropUrls(const KUrl& destination, QDropEvent* event);
00169
00170 void updateContent();
00171
00180 void updateButtons(const QString& path, int startIndex);
00181
00187 void updateButtonVisibility();
00188
00189 void switchToBreadcrumbMode();
00190
00195 void deleteButtons();
00196
00204 QString retrievePlacePath() const;
00205
00210 bool isCompressedPath(const KUrl& path) const;
00211
00212 void removeTrailingSlash(QString& url) const;
00213
00214 bool m_editable : 1;
00215 bool m_active : 1;
00216 bool m_showPlacesSelector : 1;
00217 bool m_showFullPath : 1;
00218 int m_historyIndex;
00219
00220 QHBoxLayout* m_layout;
00221
00222 QList<HistoryElem> m_history;
00223 KFilePlacesSelector* m_placesSelector;
00224 KUrlComboBox* m_pathBox;
00225 KProtocolCombo* m_protocols;
00226 KLineEdit* m_host;
00227 KUrlDropDownButton* m_dropDownButton;
00228 QLinkedList<KUrlNavigatorButton*> m_navButtons;
00229 KUrlButton* m_toggleEditableMode;
00230 QString m_homeUrl;
00231 QStringList m_customProtocols;
00232 KUrlNavigator* q;
00233 };
00234
00235
00236 KUrlNavigator::Private::Private(KUrlNavigator* q, KFilePlacesModel* placesModel) :
00237 m_editable(false),
00238 m_active(true),
00239 m_showPlacesSelector(placesModel != 0),
00240 m_showFullPath(false),
00241 m_historyIndex(0),
00242 m_layout(new QHBoxLayout),
00243 m_placesSelector(0),
00244 m_pathBox(0),
00245 m_protocols(0),
00246 m_host(0),
00247 m_dropDownButton(0),
00248 m_toggleEditableMode(0),
00249 m_customProtocols(QStringList()),
00250 q(q)
00251 {
00252 m_layout->setSpacing(0);
00253 m_layout->setMargin(0);
00254
00255
00256 q->setAutoFillBackground(false);
00257
00258 if (placesModel != 0) {
00259 m_placesSelector = new KFilePlacesSelector(q, placesModel);
00260 connect(m_placesSelector, SIGNAL(placeActivated(const KUrl&)),
00261 q, SLOT(setUrl(const KUrl&)));
00262
00263 connect(placesModel, SIGNAL(rowsInserted(QModelIndex, int, int)),
00264 q, SLOT(updateContent()));
00265 connect(placesModel, SIGNAL(rowsRemoved(QModelIndex, int, int)),
00266 q, SLOT(updateContent()));
00267 connect(placesModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)),
00268 q, SLOT(updateContent()));
00269 }
00270
00271
00272 m_protocols = new KProtocolCombo(QString(), q);
00273 connect(m_protocols, SIGNAL(activated(QString)),
00274 q, SLOT(slotProtocolChanged(QString)));
00275
00276
00277 m_host = new KLineEdit(QString(), q);
00278 m_host->setClearButtonShown(true);
00279 connect(m_host, SIGNAL(editingFinished()),
00280 q, SLOT(slotRemoteHostActivated()));
00281 connect(m_host, SIGNAL(returnPressed()),
00282 q, SIGNAL(returnPressed()));
00283
00284
00285 m_dropDownButton = new KUrlDropDownButton(q);
00286 connect(m_dropDownButton, SIGNAL(clicked()),
00287 q, SLOT(openPathSelectorMenu()));
00288
00289
00290 m_pathBox = new KUrlComboBox(KUrlComboBox::Both, true, q);
00291 m_pathBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
00292 m_pathBox->installEventFilter(q);
00293
00294 KUrlCompletion* kurlCompletion = new KUrlCompletion(KUrlCompletion::DirCompletion);
00295 m_pathBox->setCompletionObject(kurlCompletion);
00296 m_pathBox->setAutoDeleteCompletionObject(true);
00297
00298 connect(m_pathBox, SIGNAL(returnPressed()),
00299 q, SLOT(slotReturnPressed()));
00300 connect(m_pathBox, SIGNAL(urlActivated(KUrl)),
00301 q, SLOT(setUrl(KUrl)));
00302
00303
00304
00305 m_toggleEditableMode = new KUrlToggleButton(q);
00306 m_toggleEditableMode->setMinimumWidth(20);
00307 connect(m_toggleEditableMode, SIGNAL(clicked()),
00308 q, SLOT(switchView()));
00309
00310 if (m_placesSelector != 0) {
00311 m_layout->addWidget(m_placesSelector);
00312 }
00313 m_layout->addWidget(m_protocols);
00314 m_layout->addWidget(m_dropDownButton);
00315 m_layout->addWidget(m_host);
00316 m_layout->setStretchFactor(m_host, 1);
00317 m_layout->addWidget(m_pathBox, 1);
00318 m_layout->addWidget(m_toggleEditableMode);
00319 }
00320
00321 void KUrlNavigator::Private::appendWidget(QWidget* widget, int stretch)
00322 {
00323 m_layout->insertWidget(m_layout->count() - 1, widget, stretch);
00324 }
00325
00326 void KUrlNavigator::Private::slotReturnPressed()
00327 {
00328
00329
00330
00331
00332
00333
00334
00335 const KUrl typedUrl = q->uncommittedUrl();
00336 QStringList urls = m_pathBox->urls();
00337 urls.removeAll(typedUrl.url());
00338 urls.prepend(typedUrl.url());
00339 m_pathBox->setUrls(urls, KUrlComboBox::RemoveBottom);
00340
00341 q->setUrl(typedUrl);
00342
00343
00344 m_pathBox->setUrl(q->url());
00345
00346 emit q->returnPressed();
00347
00348 if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
00349
00350
00351
00352 QMetaObject::invokeMethod(q, "switchToBreadcrumbMode", Qt::QueuedConnection);
00353 }
00354 }
00355
00356 void KUrlNavigator::Private::slotRemoteHostActivated()
00357 {
00358 KUrl u = q->url();
00359
00360 KUrl n(m_protocols->currentProtocol() + "://" + m_host->text());
00361
00362 if (n.scheme() != u.scheme() ||
00363 n.host() != u.host() ||
00364 n.user() != u.user() ||
00365 n.port() != u.port()) {
00366 u.setScheme(n.scheme());
00367 u.setHost(n.host());
00368 u.setUser(n.user());
00369 u.setPort(n.port());
00370
00371
00372 if (u.scheme() == "file") {
00373 u.setHost("");
00374 if (u.path().isEmpty()) {
00375 u.setPath("/");
00376 }
00377 }
00378
00379 q->setUrl(u);
00380 }
00381 }
00382
00383 void KUrlNavigator::Private::slotProtocolChanged(const QString& protocol)
00384 {
00385 KUrl url;
00386 url.setScheme(protocol);
00387 url.setPath("/");
00388 QLinkedList<KUrlNavigatorButton*>::const_iterator it = m_navButtons.begin();
00389 const QLinkedList<KUrlNavigatorButton*>::const_iterator itEnd = m_navButtons.end();
00390 while (it != itEnd) {
00391 (*it)->hide();
00392 (*it)->deleteLater();
00393 ++it;
00394 }
00395 m_navButtons.clear();
00396
00397 if (KProtocolInfo::protocolClass(protocol) == ":local") {
00398 q->setUrl(url);
00399 } else {
00400 m_host->setText(QString());
00401 m_host->show();
00402 m_host->setFocus();
00403 }
00404 }
00405
00406 void KUrlNavigator::Private::openPathSelectorMenu()
00407 {
00408 if (m_navButtons.count() <= 0) {
00409 return;
00410 }
00411
00412 const KUrl firstVisibleUrl = q->url(m_navButtons.first()->index());
00413
00414 QString spacer;
00415 KMenu* popup = new KMenu(q);
00416 popup->setLayoutDirection(Qt::LeftToRight);
00417
00418 const QString placePath = retrievePlacePath();
00419 int idx = placePath.count('/');
00420
00421
00422 const QString path = q->url().pathOrUrl();
00423 QString dirName = path.section('/', idx, idx);
00424 if (dirName.isEmpty()) {
00425 dirName = QChar('/');
00426 }
00427 do {
00428 const QString text = spacer + dirName;
00429
00430 QAction* action = new QAction(text, popup);
00431 const KUrl currentUrl = q->url(idx);
00432 if (currentUrl == firstVisibleUrl) {
00433 popup->addSeparator();
00434 }
00435 action->setData(QVariant(currentUrl.prettyUrl()));
00436 popup->addAction(action);
00437
00438 ++idx;
00439 spacer.append(" ");
00440 dirName = path.section('/', idx, idx);
00441 } while (!dirName.isEmpty());
00442
00443 const QPoint pos = q->mapToGlobal(m_dropDownButton->geometry().bottomRight());
00444 const QAction* activatedAction = popup->exec(pos);
00445 if (activatedAction != 0) {
00446 const KUrl url = KUrl(activatedAction->data().toString());
00447 q->setUrl(url);
00448 }
00449
00450 popup->deleteLater();
00451 }
00452
00453 void KUrlNavigator::Private::switchView()
00454 {
00455 m_toggleEditableMode->setFocus();
00456 m_editable = !m_editable;
00457 m_toggleEditableMode->setChecked(m_editable);
00458 updateContent();
00459 if (q->isUrlEditable()) {
00460 m_pathBox->setFocus();
00461 }
00462
00463 emit q->requestActivation();
00464 emit q->editableStateChanged(m_editable);
00465 }
00466
00467 void KUrlNavigator::Private::dropUrls(const KUrl& destination, QDropEvent* event)
00468 {
00469 const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
00470 if (!urls.isEmpty()) {
00471 emit q->urlsDropped(destination, event);
00472
00473
00474
00475 emit q->urlsDropped(urls, destination);
00476 }
00477 }
00478
00479 void KUrlNavigator::Private::updateContent()
00480 {
00481 if (m_placesSelector != 0) {
00482 m_placesSelector->updateSelection(q->url());
00483 }
00484
00485 if (m_editable) {
00486 m_protocols->hide();
00487 m_host->hide();
00488 m_dropDownButton->hide();
00489
00490 deleteButtons();
00491 m_toggleEditableMode->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
00492 q->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
00493
00494 m_pathBox->show();
00495 m_pathBox->setUrl(q->url());
00496 } else {
00497 m_dropDownButton->setVisible(!m_showFullPath);
00498 m_pathBox->hide();
00499
00500 const KUrl currentUrl = q->url();
00501 QString path = currentUrl.pathOrUrl();
00502 removeTrailingSlash(path);
00503
00504 m_toggleEditableMode->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
00505 q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
00506
00507
00508
00509
00510
00511
00512
00513 KUrl placeUrl;
00514 if ((m_placesSelector != 0) && !m_showFullPath) {
00515 placeUrl = m_placesSelector->selectedPlaceUrl();
00516 }
00517
00518 QString placePath = placeUrl.isValid() ? placeUrl.pathOrUrl() : retrievePlacePath();
00519 removeTrailingSlash(placePath);
00520
00521
00522 const QString protocol = currentUrl.scheme();
00523 m_protocols->setProtocol(protocol);
00524
00525
00526 QString hostText = currentUrl.host();
00527 if (!currentUrl.user().isEmpty()) {
00528 hostText = currentUrl.user() + '@' + hostText;
00529 }
00530 if (currentUrl.port() != -1) {
00531 hostText = hostText + ':' + QString::number(currentUrl.port());
00532 }
00533 m_host->setText(hostText);
00534
00535
00536 const bool hasPlaceItem = currentUrl.isLocalFile() || placeUrl.isValid();
00537 const bool isVisible = !hasPlaceItem &&
00538 (placePath == path) &&
00539 (KProtocolInfo::protocolClass(protocol) != ":local");
00540
00541 m_host->setVisible(isVisible);
00542 m_protocols->setVisible(isVisible);
00543
00544
00545
00546 int startIndex = placePath.count('/');
00547 if (!isVisible && !hasPlaceItem && hostText.isEmpty()) {
00548 --startIndex;
00549 }
00550 updateButtons(path, startIndex);
00551 }
00552 }
00553
00554 void KUrlNavigator::Private::updateButtons(const QString& path, int startIndex)
00555 {
00556 QLinkedList<KUrlNavigatorButton*>::iterator it = m_navButtons.begin();
00557 const QLinkedList<KUrlNavigatorButton*>::const_iterator itEnd = m_navButtons.end();
00558 bool createButton = false;
00559 const KUrl currentUrl = q->url();
00560
00561 int idx = startIndex;
00562 bool hasNext = true;
00563 do {
00564 createButton = (it == itEnd);
00565
00566 const QString dirName = path.section('/', idx, idx);
00567 const bool isFirstButton = (idx == startIndex);
00568 hasNext = isFirstButton || !dirName.isEmpty();
00569 if (hasNext) {
00570 QString text;
00571 if (isFirstButton) {
00572
00573
00574 if ((m_placesSelector != 0) && !m_showFullPath) {
00575 const KUrl placeUrl = m_placesSelector->selectedPlaceUrl();
00576 text = m_placesSelector->selectedPlaceText();
00577 }
00578 if (text.isEmpty()) {
00579 if (currentUrl.isLocalFile()) {
00580 text = m_showFullPath ? "/" : i18n("Custom Path");
00581 } else if (!m_host->isVisible() && !m_host->text().isEmpty()) {
00582 text = m_host->text();
00583 } else {
00584
00585
00586 ++idx;
00587 continue;
00588 }
00589 }
00590 }
00591
00592 KUrlNavigatorButton* button = 0;
00593 if (createButton) {
00594 button = new KUrlNavigatorButton(idx, q);
00595 connect(button, SIGNAL(urlsDropped(const KUrl&, QDropEvent*)),
00596 q, SLOT(dropUrls(const KUrl&, QDropEvent*)));
00597 appendWidget(button);
00598 } else {
00599 button = *it;
00600 button->setIndex(idx);
00601 }
00602
00603 if (isFirstButton) {
00604 button->setText(text);
00605 }
00606
00607 if (createButton) {
00608 m_navButtons.append(button);
00609 } else {
00610 ++it;
00611 }
00612 ++idx;
00613 }
00614 } while (hasNext);
00615
00616
00617 QLinkedList<KUrlNavigatorButton*>::iterator itBegin = it;
00618 while (it != itEnd) {
00619 (*it)->hide();
00620 (*it)->deleteLater();
00621 ++it;
00622 }
00623 m_navButtons.erase(itBegin, m_navButtons.end());
00624
00625 updateButtonVisibility();
00626 }
00627
00628 void KUrlNavigator::Private::updateButtonVisibility()
00629 {
00630 if (m_editable) {
00631 return;
00632 }
00633
00634 const int buttonsCount = m_navButtons.count();
00635 if (buttonsCount == 0) {
00636 m_dropDownButton->hide();
00637 return;
00638 }
00639
00640
00641 int availableWidth = q->width() - m_toggleEditableMode->minimumWidth();
00642
00643 if ((m_placesSelector != 0) && m_placesSelector->isVisible()) {
00644 availableWidth -= m_placesSelector->width();
00645 }
00646
00647 if ((m_protocols != 0) && m_protocols->isVisible()) {
00648 availableWidth -= m_protocols->width();
00649 }
00650
00651 if (m_host->isVisible()) {
00652 availableWidth -= m_host->width();
00653 }
00654
00655
00656 int requiredButtonWidth = 0;
00657 foreach (KUrlNavigatorButton* button, m_navButtons) {
00658 requiredButtonWidth += button->minimumWidth();
00659 }
00660 if (requiredButtonWidth > availableWidth) {
00661
00662
00663
00664 availableWidth -= m_dropDownButton->width();
00665 }
00666
00667
00668 QLinkedList<KUrlNavigatorButton*>::iterator it = m_navButtons.end();
00669 const QLinkedList<KUrlNavigatorButton*>::const_iterator itBegin = m_navButtons.begin();
00670 bool isLastButton = true;
00671 bool hasHiddenButtons = false;
00672
00673 QLinkedList<KUrlNavigatorButton*> buttonsToShow;
00674 while (it != itBegin) {
00675 --it;
00676 KUrlNavigatorButton* button = (*it);
00677 availableWidth -= button->minimumWidth();
00678 if ((availableWidth <= 0) && !isLastButton) {
00679 button->hide();
00680 hasHiddenButtons = true;
00681 }
00682 else {
00683 button->setActive(isLastButton);
00684
00685
00686
00687
00688
00689 buttonsToShow.append(button);
00690 }
00691 isLastButton = false;
00692 }
00693
00694
00695
00696 foreach (KUrlNavigatorButton* button, buttonsToShow) {
00697 button->show();
00698 }
00699
00700 const int startIndex = retrievePlacePath().count('/');
00701 const bool showDropDownButton = hasHiddenButtons ||
00702 (!hasHiddenButtons && (m_navButtons.front()->index() > startIndex));
00703 m_dropDownButton->setVisible(showDropDownButton);
00704 }
00705
00706 void KUrlNavigator::Private::switchToBreadcrumbMode()
00707 {
00708 q->setUrlEditable(false);
00709 }
00710
00711 void KUrlNavigator::Private::deleteButtons()
00712 {
00713 foreach (KUrlNavigatorButton* button, m_navButtons) {
00714 button->hide();
00715 button->deleteLater();
00716 }
00717 m_navButtons.clear();
00718 }
00719
00720 QString KUrlNavigator::Private::retrievePlacePath() const
00721 {
00722 const QString path = q->url().pathOrUrl();
00723 int idx = path.indexOf(QLatin1String("///"));
00724 if (idx >= 0) {
00725 idx += 3;
00726 } else {
00727 idx = path.indexOf(QLatin1String("//"));
00728 idx = path.indexOf(QLatin1Char('/'), (idx < 0) ? 0 : idx + 2);
00729 }
00730
00731 QString placePath = (idx < 0) ? path : path.left(idx);
00732 removeTrailingSlash(placePath);
00733 return placePath;
00734 }
00735
00736 bool KUrlNavigator::Private::isCompressedPath(const KUrl& url) const
00737 {
00738 const KMimeType::Ptr mime = KMimeType::findByPath(url.path(KUrl::RemoveTrailingSlash));
00739
00740 return mime->is("application/x-compressed-tar") ||
00741 mime->is("application/x-bzip-compressed-tar") ||
00742 mime->is("application/x-lzma-compressed-tar") ||
00743 mime->is("application/x-xz-compressed-tar") ||
00744 mime->is("application/x-tar") ||
00745 mime->is("application/x-tarz") ||
00746 mime->is("application/x-tzo") ||
00747 mime->is("application/zip") ||
00748 mime->is("application/x-archive");
00749 }
00750
00751 void KUrlNavigator::Private::removeTrailingSlash(QString& url) const
00752 {
00753 const int length = url.length();
00754 if ((length > 0) && (url.at(length - 1) == QChar('/'))) {
00755 url.remove(length -1, 1);
00756 }
00757 }
00758
00760
00761 KUrlNavigator::KUrlNavigator(KFilePlacesModel* placesModel,
00762 const KUrl& url,
00763 QWidget* parent) :
00764 QWidget(parent),
00765 d(new Private(this, placesModel))
00766 {
00767 d->m_history.prepend(HistoryElem(url));
00768 setLayoutDirection(Qt::LeftToRight);
00769
00770 const QFont font = KGlobalSettings::generalFont();
00771 setFont(font);
00772
00773 const int minHeight = d->m_pathBox->sizeHint().height();
00774 setMinimumHeight(minHeight);
00775
00776 setLayout(d->m_layout);
00777 setMinimumWidth(100);
00778
00779 d->updateContent();
00780 }
00781
00782 KUrlNavigator::~KUrlNavigator()
00783 {
00784 delete d;
00785 }
00786
00787 const KUrl& KUrlNavigator::url() const
00788 {
00789 Q_ASSERT(!d->m_history.empty());
00790 return d->m_history[d->m_historyIndex].url();
00791 }
00792
00793 KUrl KUrlNavigator::uncommittedUrl() const
00794 {
00795 if (isUrlEditable()) {
00796 return KUrl(d->m_pathBox->currentText().trimmed());
00797 } else {
00798 return KUrl(d->m_protocols->currentProtocol() + "://" + d->m_host->text());
00799 }
00800 }
00801
00802 KUrl KUrlNavigator::url(int index) const
00803 {
00804 if (index < 0) {
00805 index = 0;
00806 }
00807
00808
00809
00810 KUrl newUrl = url();
00811 newUrl.setPath(QString());
00812
00813 QString pathOrUrl = url().pathOrUrl();
00814 if (!pathOrUrl.isEmpty()) {
00815 if (index == 0) {
00816
00817
00818 #ifdef Q_OS_WIN
00819 pathOrUrl = pathOrUrl.length() > 2 ? pathOrUrl.left(3) : QDir::rootPath();
00820 #else
00821 pathOrUrl = QLatin1String("/");
00822 #endif
00823 } else {
00824 pathOrUrl = pathOrUrl.section('/', 0, index);
00825 }
00826 }
00827
00828 newUrl.setPath(KUrl(pathOrUrl).path());
00829 return newUrl;
00830 }
00831
00832 bool KUrlNavigator::goBack()
00833 {
00834 const int count = d->m_history.count();
00835 if (d->m_historyIndex < count - 1) {
00836 ++d->m_historyIndex;
00837 d->updateContent();
00838 emit historyChanged();
00839 emit urlChanged(url());
00840 return true;
00841 }
00842
00843 return false;
00844 }
00845
00846 bool KUrlNavigator::goForward()
00847 {
00848 if (d->m_historyIndex > 0) {
00849 --d->m_historyIndex;
00850 d->updateContent();
00851 emit historyChanged();
00852 emit urlChanged(url());
00853 return true;
00854 }
00855
00856 return false;
00857 }
00858
00859 bool KUrlNavigator::goUp()
00860 {
00861 const KUrl& currentUrl = url();
00862 const KUrl upUrl = currentUrl.upUrl();
00863 if (upUrl != currentUrl) {
00864 setUrl(upUrl);
00865 return true;
00866 }
00867
00868 return false;
00869 }
00870
00871 void KUrlNavigator::goHome()
00872 {
00873 if (d->m_homeUrl.isEmpty()) {
00874 setUrl(QDir::homePath());
00875 } else {
00876 setUrl(d->m_homeUrl);
00877 }
00878 }
00879
00880 void KUrlNavigator::setHomeUrl(const QString& homeUrl)
00881 {
00882 d->m_homeUrl = homeUrl;
00883 }
00884
00885 void KUrlNavigator::setUrlEditable(bool editable)
00886 {
00887 if (d->m_editable != editable) {
00888 d->switchView();
00889 }
00890 }
00891
00892 bool KUrlNavigator::isUrlEditable() const
00893 {
00894 return d->m_editable;
00895 }
00896
00897 void KUrlNavigator::setShowFullPath(bool show)
00898 {
00899 if (d->m_showFullPath != show) {
00900 d->m_showFullPath = show;
00901 d->updateContent();
00902 }
00903 }
00904
00905 bool KUrlNavigator::showFullPath() const
00906 {
00907 return d->m_showFullPath;
00908 }
00909
00910
00911 void KUrlNavigator::setActive(bool active)
00912 {
00913 if (active != d->m_active) {
00914 d->m_active = active;
00915 update();
00916 if (active) {
00917 emit activated();
00918 }
00919 }
00920 }
00921
00922 bool KUrlNavigator::isActive() const
00923 {
00924 return d->m_active;
00925 }
00926
00927 void KUrlNavigator::setPlacesSelectorVisible(bool visible)
00928 {
00929 if (visible == d->m_showPlacesSelector) {
00930 return;
00931 }
00932
00933 if (visible && (d->m_placesSelector == 0)) {
00934
00935
00936 return;
00937 }
00938
00939 d->m_showPlacesSelector = visible;
00940 d->m_placesSelector->setVisible(visible);
00941 }
00942
00943 bool KUrlNavigator::isPlacesSelectorVisible() const
00944 {
00945 return d->m_showPlacesSelector;
00946 }
00947
00948 void KUrlNavigator::setUrl(const KUrl& newUrl)
00949 {
00950 if (newUrl == url()) {
00951 return;
00952 }
00953
00954 KUrl url = newUrl;
00955 url.cleanPath();
00956
00957 QString urlStr = KUrlCompletion::replacedPath(url.url(), true, true);
00958 if ((urlStr.length() > 0) && (urlStr.at(0) == '~')) {
00959
00960 urlStr.remove(0, 1);
00961 urlStr.insert(0, QDir::homePath());
00962 }
00963
00964 if ((url.protocol() == "tar") || (url.protocol() == "zip")) {
00965
00966
00967
00968 bool insideCompressedPath = d->isCompressedPath(url);
00969 if (!insideCompressedPath) {
00970 KUrl prevUrl = url;
00971 KUrl parentUrl = url.upUrl();
00972 while (parentUrl != prevUrl) {
00973 if (d->isCompressedPath(parentUrl)) {
00974 insideCompressedPath = true;
00975 break;
00976 }
00977 prevUrl = parentUrl;
00978 parentUrl = parentUrl.upUrl();
00979 }
00980 }
00981 if (!insideCompressedPath) {
00982
00983
00984 urlStr = url.path();
00985 }
00986 }
00987
00988 const KUrl transformedUrl(urlStr);
00989
00990
00991
00992 const HistoryElem& historyElem = d->m_history[d->m_historyIndex];
00993 const bool isUrlEqual = transformedUrl.equals(historyElem.url(), KUrl::CompareWithoutTrailingSlash) ||
00994 (!transformedUrl.isValid() && (urlStr == historyElem.url().url()));
00995 if (isUrlEqual) {
00996 return;
00997 }
00998
00999 if (d->m_historyIndex > 0) {
01000
01001
01002
01003 QList<HistoryElem>::iterator begin = d->m_history.begin();
01004 QList<HistoryElem>::iterator end = begin + d->m_historyIndex;
01005 d->m_history.erase(begin, end);
01006 d->m_historyIndex = 0;
01007 }
01008
01009 Q_ASSERT(d->m_historyIndex == 0);
01010 d->m_history.insert(0, HistoryElem(transformedUrl));
01011
01012
01013
01014 const int historyMax = 100;
01015 if (d->m_history.size() > historyMax) {
01016 QList<HistoryElem>::iterator begin = d->m_history.begin() + historyMax;
01017 QList<HistoryElem>::iterator end = d->m_history.end();
01018 d->m_history.erase(begin, end);
01019 }
01020
01021 emit historyChanged();
01022 emit urlChanged(transformedUrl);
01023
01024 d->updateContent();
01025
01026 requestActivation();
01027 }
01028
01029 void KUrlNavigator::requestActivation()
01030 {
01031 setActive(true);
01032 }
01033
01034 void KUrlNavigator::saveRootUrl(const KUrl& url)
01035 {
01036 HistoryElem& hist = d->m_history[d->m_historyIndex];
01037 hist.setRootUrl(url);
01038 }
01039
01040 void KUrlNavigator::savePosition(int x, int y)
01041 {
01042 HistoryElem& hist = d->m_history[d->m_historyIndex];
01043 hist.setContentsX(x);
01044 hist.setContentsY(y);
01045 }
01046
01047 void KUrlNavigator::keyReleaseEvent(QKeyEvent* event)
01048 {
01049 QWidget::keyReleaseEvent(event);
01050 if (isUrlEditable() && (event->key() == Qt::Key_Escape)) {
01051 setUrlEditable(false);
01052 }
01053 }
01054
01055 void KUrlNavigator::mouseReleaseEvent(QMouseEvent* event)
01056 {
01057 if (event->button() == Qt::MidButton) {
01058 QClipboard* clipboard = QApplication::clipboard();
01059 const QMimeData* mimeData = clipboard->mimeData();
01060 if (mimeData->hasText()) {
01061 const QString text = mimeData->text();
01062 setUrl(KUrl(text));
01063 }
01064 }
01065 QWidget::mouseReleaseEvent(event);
01066 }
01067
01068 void KUrlNavigator::resizeEvent(QResizeEvent* event)
01069 {
01070 QTimer::singleShot(0, this, SLOT(updateButtonVisibility()));
01071 QWidget::resizeEvent(event);
01072 }
01073
01074 bool KUrlNavigator::eventFilter(QObject* watched, QEvent* event)
01075 {
01076 if ((watched == d->m_pathBox) && (event->type() == QEvent::FocusIn)) {
01077 requestActivation();
01078 setFocus();
01079 }
01080
01081 return QWidget::eventFilter(watched, event);
01082 }
01083
01084 int KUrlNavigator::historySize() const
01085 {
01086 return d->m_history.count();
01087 }
01088
01089 int KUrlNavigator::historyIndex() const
01090 {
01091 return d->m_historyIndex;
01092 }
01093
01094 KUrl KUrlNavigator::historyUrl(int historyIndex) const
01095 {
01096 Q_ASSERT(historyIndex >= 0);
01097 Q_ASSERT(historyIndex < historySize());
01098 return d->m_history[historyIndex].url();
01099 }
01100
01101 const KUrl& KUrlNavigator::savedRootUrl() const
01102 {
01103 const HistoryElem& histElem = d->m_history[d->m_historyIndex];
01104 return histElem.rootUrl();
01105 }
01106
01107 QPoint KUrlNavigator::savedPosition() const
01108 {
01109 const HistoryElem& histElem = d->m_history[d->m_historyIndex];
01110 return QPoint(histElem.contentsX(), histElem.contentsY());
01111 }
01112
01113 KUrlComboBox* KUrlNavigator::editor() const
01114 {
01115 return d->m_pathBox;
01116 }
01117
01118 void KUrlNavigator::setCustomProtocols(const QStringList &protocols)
01119 {
01120 d->m_customProtocols = protocols;
01121 d->m_protocols->setCustomProtocols(d->m_customProtocols);
01122 }
01123
01124 QStringList KUrlNavigator::customProtocols() const
01125 {
01126 return d->m_customProtocols;
01127 }
01128
01129 void KUrlNavigator::setFocus()
01130 {
01131 if (isUrlEditable()) {
01132 d->m_pathBox->setFocus();
01133 } else if (d->m_host) {
01134 d->m_host->setFocus();
01135 } else {
01136 QWidget::setFocus();
01137 }
01138 }
01139
01140 #include "kurlnavigator.moc"