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