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