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
00348 KUrlCompletion* kurlCompletion = new KUrlCompletion(KUrlCompletion::DirCompletion);
00349 m_pathBox->setCompletionObject(kurlCompletion);
00350 m_pathBox->setAutoDeleteCompletionObject(true);
00351
00352 connect(m_pathBox, SIGNAL(returnPressed(QString)),
00353 q, SLOT(slotReturnPressed(QString)));
00354 connect(m_pathBox, SIGNAL(returnPressed()),
00355 q, SLOT(slotReturnPressed()));
00356 connect(m_pathBox, SIGNAL(urlActivated(KUrl)),
00357 q, SLOT(setUrl(KUrl)));
00358
00359 m_toggleEditableMode = new KUrlToggleButton(q);
00360 m_toggleEditableMode->setMinimumWidth(20);
00361 connect(m_toggleEditableMode, SIGNAL(clicked()),
00362 q, SLOT(switchView()));
00363
00364 if (m_placesSelector != 0) {
00365 m_layout->addWidget(m_placesSelector);
00366 }
00367 m_layout->addWidget(m_dropDownButton);
00368 m_layout->addWidget(m_pathBox, 1);
00369 m_layout->addWidget(m_toggleEditableMode);
00370 }
00371
00372 void KUrlNavigator::Private::appendWidget(QWidget* widget, int stretch)
00373 {
00374 m_layout->insertWidget(m_layout->count() - 1, widget, stretch);
00375 }
00376
00377 void KUrlNavigator::Private::slotReturnPressed(const QString& text)
00378 {
00379
00380
00381
00382
00383
00384
00385
00386 KUrl typedUrl(text);
00387 if (typedUrl.hasPass()) {
00388 typedUrl.setPass(QString());
00389 }
00390
00391 QStringList urls = m_pathBox->urls();
00392 urls.removeAll(typedUrl.url());
00393 urls.prepend(typedUrl.url());
00394 m_pathBox->setUrls(urls, KUrlComboBox::RemoveBottom);
00395
00396 q->setUrl(typedUrl);
00397
00398
00399 m_pathBox->setUrl(q->url());
00400
00401 emit q->returnPressed();
00402
00403 if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
00404
00405
00406
00407 QMetaObject::invokeMethod(q, "switchToBreadcrumbMode", Qt::QueuedConnection);
00408 }
00409 }
00410
00411 void KUrlNavigator::Private::slotReturnPressed()
00412 {
00413 const QString text = q->uncommittedUrl().prettyUrl();
00414 slotReturnPressed(text);
00415 }
00416
00417 void KUrlNavigator::Private::slotRemoteHostActivated()
00418 {
00419 KUrl u = q->url();
00420
00421 KUrl n(m_protocols->currentProtocol() + "://" + m_host->text());
00422
00423 if (n.scheme() != u.scheme() ||
00424 n.host() != u.host() ||
00425 n.user() != u.user() ||
00426 n.port() != u.port()) {
00427 u.setScheme(n.scheme());
00428 u.setHost(n.host());
00429 u.setUser(n.user());
00430 u.setPort(n.port());
00431
00432
00433 if (u.scheme() == "file") {
00434 u.setHost("");
00435 if (u.path().isEmpty()) {
00436 u.setPath("/");
00437 }
00438 }
00439
00440 q->setUrl(u);
00441 }
00442 }
00443
00444 void KUrlNavigator::Private::slotProtocolChanged(const QString& protocol)
00445 {
00446 KUrl url;
00447 url.setScheme(protocol);
00448 url.setPath("/");
00449 QLinkedList<KUrlNavigatorButton*>::const_iterator it = m_navButtons.begin();
00450 const QLinkedList<KUrlNavigatorButton*>::const_iterator itEnd = m_navButtons.end();
00451 while (it != itEnd) {
00452 (*it)->hide();
00453 (*it)->deleteLater();
00454 ++it;
00455 }
00456 m_navButtons.clear();
00457
00458 if (KProtocolInfo::protocolClass(protocol) == ":local") {
00459 q->setUrl(url);
00460 } else {
00461 if (m_host == 0) {
00462 createHostLineEdit("");
00463 } else {
00464 m_host->setText("");
00465 }
00466 m_host->show();
00467 m_host->setFocus();
00468 }
00469 }
00470
00471 void KUrlNavigator::Private::openPathSelectorMenu()
00472 {
00473 KMenu* popup = new KMenu(q);
00474
00475 QString spacer;
00476 QLinkedList<KUrlNavigatorButton*>::iterator it = m_navButtons.begin();
00477 const QLinkedList<KUrlNavigatorButton*>::const_iterator itEnd = m_navButtons.end();
00478 while (it != itEnd) {
00479 const QString text = spacer + (*it)->text();
00480 spacer.append(" ");
00481
00482 QAction* action = new QAction(text, popup);
00483 action->setData(QVariant((*it)->index()));
00484 popup->addAction(action);
00485
00486 ++it;
00487 }
00488
00489 const QAction* activatedAction = popup->exec(QCursor::pos());
00490 if (activatedAction != 0) {
00491 const int index = activatedAction->data().toInt();
00492 q->setUrl(q->url(index));
00493 }
00494
00495 popup->deleteLater();
00496 }
00497
00498 void KUrlNavigator::Private::switchView()
00499 {
00500 m_toggleEditableMode->setFocus();
00501 m_editable = !m_editable;
00502 m_toggleEditableMode->setChecked(m_editable);
00503 updateContent();
00504 if (q->isUrlEditable()) {
00505 m_pathBox->setFocus();
00506 }
00507
00508 emit q->requestActivation();
00509 emit q->editableStateChanged(m_editable);
00510 }
00511
00512 void KUrlNavigator::Private::dropUrls(const KUrl::List& urls,
00513 const KUrl& destination)
00514 {
00515 emit q->urlsDropped(urls, destination);
00516 }
00517
00518 void KUrlNavigator::Private::updateContent()
00519 {
00520 if (m_placesSelector != 0) {
00521 m_placesSelector->updateSelection(q->url());
00522 }
00523
00524 if (m_editable) {
00525 delete m_protocols;
00526 m_protocols = 0;
00527 delete m_host;
00528 m_host = 0;
00529
00530 m_dropDownButton->hide();
00531 deleteButtons();
00532 m_toggleEditableMode->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
00533
00534 q->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
00535 m_pathBox->show();
00536 m_pathBox->setUrl(q->url());
00537 } else {
00538 const QString path = q->url().pathOrUrl();
00539
00540 q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
00541 m_pathBox->hide();
00542 m_toggleEditableMode->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
00543
00544
00545 KUrl placeUrl = KUrl();
00546 if (m_placesSelector != 0) {
00547 placeUrl = m_placesSelector->selectedPlaceUrl();
00548 }
00549
00550 const QString placePath = placeUrl.isValid() ? placeUrl.pathOrUrl() : retrievePlacePath(path);
00551 const uint len = placePath.length();
00552
00553
00554
00555 int slashCount = 0;
00556 for (uint i = 0; i < len; ++i) {
00557 if (placePath.at(i) == QChar('/')) {
00558 ++slashCount;
00559 }
00560 }
00561 if ((len > 0) && placePath.at(len - 1) == QChar('/')) {
00562 Q_ASSERT(slashCount > 0);
00563 --slashCount;
00564 }
00565
00566 const KUrl currentUrl = q->url();
00567 if (!currentUrl.isLocalFile() && !placeUrl.isValid()) {
00568 QString protocol = currentUrl.scheme();
00569 if (m_protocols == 0) {
00570 deleteButtons();
00571
00572 m_protocols = new KProtocolCombo(protocol, q);
00573 const int index = m_layout->indexOf(m_dropDownButton);
00574 m_layout->insertWidget(index, m_protocols);
00575
00576 if (!m_customProtocols.isEmpty()) {
00577 m_protocols->setCustomProtocols(m_customProtocols);
00578 }
00579 connect(m_protocols, SIGNAL(activated(QString)),
00580 q, SLOT(slotProtocolChanged(QString)));
00581 } else {
00582 m_protocols->setProtocol(protocol);
00583 }
00584 m_protocols->show();
00585
00586 if (KProtocolInfo::protocolClass(protocol) != ":local") {
00587 QString hostText = currentUrl.host();
00588
00589 if (!currentUrl.user().isEmpty()) {
00590 hostText = currentUrl.user() + '@' + hostText;
00591 }
00592
00593 if (currentUrl.port() != -1) {
00594 hostText = hostText + ':' + QString::number(currentUrl.port());
00595 }
00596
00597 if (m_host == 0) {
00598 createHostLineEdit(hostText);
00599 } else {
00600 m_host->setText(hostText);
00601 }
00602 m_host->show();
00603 } else {
00604 delete m_host;
00605 m_host = 0;
00606 }
00607 } else if (m_protocols != 0) {
00608 m_protocols->hide();
00609 if (m_host != 0) {
00610 m_host->hide();
00611 }
00612 }
00613
00614 updateButtons(path, slashCount);
00615 }
00616 }
00617
00618 void KUrlNavigator::Private::updateButtons(const QString& path, int startIndex)
00619 {
00620 QLinkedList<KUrlNavigatorButton*>::iterator it = m_navButtons.begin();
00621 const QLinkedList<KUrlNavigatorButton*>::const_iterator itEnd = m_navButtons.end();
00622 bool createButton = false;
00623 const KUrl currentUrl = q->url();
00624
00625 int idx = startIndex;
00626 bool hasNext = true;
00627 do {
00628 createButton = (it == itEnd);
00629
00630 const QString dirName = path.section('/', idx, idx);
00631 const bool isFirstButton = (idx == startIndex);
00632 hasNext = isFirstButton || !dirName.isEmpty();
00633 if (hasNext) {
00634 QString text;
00635 if (isFirstButton) {
00636
00637
00638 if (m_placesSelector != 0) {
00639 const KUrl placeUrl = m_placesSelector->selectedPlaceUrl();
00640 text = m_placesSelector->selectedPlaceText();
00641 }
00642 if (text.isEmpty()) {
00643 if (currentUrl.isLocalFile()) {
00644 text = i18n("Custom Path");
00645 } else {
00646 ++idx;
00647 continue;
00648 }
00649 }
00650 }
00651
00652 KUrlNavigatorButton* button = 0;
00653 if (createButton) {
00654 button = new KUrlNavigatorButton(idx, q);
00655 connect(button, SIGNAL(urlsDropped(const KUrl::List&, const KUrl&)),
00656 q, SLOT(dropUrls(const KUrl::List&, const KUrl&)));
00657 appendWidget(button);
00658 } else {
00659 button = *it;
00660 button->setIndex(idx);
00661 }
00662
00663 if (isFirstButton) {
00664 button->setText(text);
00665 button->updateMinimumWidth();
00666 }
00667
00668 if (createButton) {
00669 m_navButtons.append(button);
00670 } else {
00671 ++it;
00672 }
00673 ++idx;
00674 }
00675 } while (hasNext);
00676
00677
00678 QLinkedList<KUrlNavigatorButton*>::iterator itBegin = it;
00679 while (it != itEnd) {
00680 (*it)->hide();
00681 (*it)->deleteLater();
00682 ++it;
00683 }
00684 m_navButtons.erase(itBegin, m_navButtons.end());
00685
00686 updateButtonVisibility();
00687 }
00688
00689 void KUrlNavigator::Private::updateButtonVisibility()
00690 {
00691 if (m_editable) {
00692 return;
00693 }
00694
00695 const int buttonsCount = m_navButtons.count();
00696 if (m_host != 0) {
00697 const bool optimize = (buttonsCount != 0);
00698 m_host->setOptimizeWidth(optimize);
00699 if (optimize) {
00700 m_host->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
00701 m_layout->setStretchFactor(m_host, 0);
00702 } else {
00703 m_host->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
00704 m_layout->setStretchFactor(m_host, 1);
00705 }
00706 }
00707
00708 if (buttonsCount == 0) {
00709 m_dropDownButton->hide();
00710 return;
00711 }
00712
00713 int hiddenButtonsCount = 0;
00714
00715
00716 int availableWidth = q->width() - m_toggleEditableMode->minimumWidth();
00717
00718 if ((m_placesSelector != 0) && m_placesSelector->isVisible()) {
00719 availableWidth -= m_placesSelector->width();
00720 }
00721
00722 if ((m_protocols != 0) && m_protocols->isVisible()) {
00723 availableWidth -= m_protocols->width();
00724 }
00725
00726 if ((m_host != 0) && m_host->isVisible()) {
00727 availableWidth -= m_host->width();
00728 }
00729
00730
00731 int requiredButtonWidth = 0;
00732 foreach (KUrlNavigatorButton* button, m_navButtons) {
00733 requiredButtonWidth += button->minimumWidth();
00734 }
00735 if (requiredButtonWidth > availableWidth) {
00736
00737
00738
00739 availableWidth -= m_dropDownButton->width();
00740 }
00741
00742
00743 QLinkedList<KUrlNavigatorButton*>::iterator it = m_navButtons.end();
00744 const QLinkedList<KUrlNavigatorButton*>::const_iterator itBegin = m_navButtons.begin();
00745 while (it != itBegin) {
00746 --it;
00747 KUrlNavigatorButton* button = (*it);
00748 availableWidth -= button->minimumWidth();
00749 if (availableWidth <= 0) {
00750 button->hide();
00751 ++hiddenButtonsCount;
00752 }
00753 else {
00754 button->show();
00755 }
00756 }
00757
00758 Q_ASSERT(hiddenButtonsCount <= buttonsCount);
00759 if (hiddenButtonsCount == buttonsCount) {
00760
00761 hiddenButtonsCount = buttonsCount - 1;
00762 }
00763
00764 int index = 0;
00765 it = m_navButtons.begin();
00766 const QLinkedList<KUrlNavigatorButton*>::const_iterator itEnd = m_navButtons.end();
00767 while (it != itEnd) {
00768 (*it)->setVisible(index >= hiddenButtonsCount);
00769 ++it;
00770 ++index;
00771 }
00772
00773 m_dropDownButton->setVisible(hiddenButtonsCount != 0);
00774 }
00775
00776 void KUrlNavigator::Private::switchToBreadcrumbMode()
00777 {
00778 q->setUrlEditable(false);
00779 }
00780
00781 void KUrlNavigator::Private::deleteButtons()
00782 {
00783 foreach (KUrlNavigatorButton* button, m_navButtons) {
00784 button->hide();
00785 button->deleteLater();
00786 }
00787 m_navButtons.clear();
00788 }
00789
00790 QString KUrlNavigator::Private::retrievePlacePath(const QString& path) const
00791 {
00792 int idx = path.indexOf(QLatin1String("///"));
00793 if (idx >= 0) {
00794 idx += 3;
00795 } else {
00796 idx = path.indexOf(QLatin1String("//"));
00797 idx = path.indexOf(QLatin1Char('/'), (idx < 0) ? 0 : idx + 2);
00798 }
00799 return (idx < 0) ? path : path.left(idx);
00800 }
00801
00802 bool KUrlNavigator::Private::isCompressedPath(const KUrl& url) const
00803 {
00804 const KMimeType::Ptr mime = KMimeType::findByPath(url.path(KUrl::RemoveTrailingSlash));
00805
00806 return mime->is("application/x-compressed-tar") ||
00807 mime->is("application/x-bzip-compressed-tar") ||
00808 mime->is("application/x-tar") ||
00809 mime->is("application/x-tarz") ||
00810 mime->is("application/x-tzo") ||
00811 mime->is("application/zip") ||
00812 mime->is("application/x-archive");
00813 }
00814
00815 void KUrlNavigator::Private::createHostLineEdit(const QString& text)
00816 {
00817 Q_ASSERT(m_host == 0);
00818
00819 m_host = new HostLineEdit(text, q);
00820 m_host->setClearButtonShown(true);
00821
00822 const int index = m_layout->indexOf(m_dropDownButton);
00823 m_layout->insertWidget(index, m_host);
00824
00825 connect(m_host, SIGNAL(editingFinished()),
00826 q, SLOT(slotRemoteHostActivated()));
00827 connect(m_host, SIGNAL(returnPressed()),
00828 q, SIGNAL(returnPressed()));
00829 }
00830
00832
00833 KUrlNavigator::KUrlNavigator(KFilePlacesModel* placesModel,
00834 const KUrl& url,
00835 QWidget* parent) :
00836 QWidget(parent),
00837 d(new Private(this, placesModel))
00838 {
00839 d->m_history.prepend(HistoryElem(url));
00840
00841 const QFont font = KGlobalSettings::generalFont();
00842 setFont(font);
00843
00844 const int minHeight = d->m_pathBox->sizeHint().height();
00845 setMinimumHeight(minHeight);
00846
00847 setLayout(d->m_layout);
00848 setMinimumWidth(100);
00849
00850 d->updateContent();
00851 }
00852
00853 KUrlNavigator::~KUrlNavigator()
00854 {
00855 delete d;
00856 }
00857
00858 const KUrl& KUrlNavigator::url() const
00859 {
00860 Q_ASSERT(!d->m_history.empty());
00861 return d->m_history[d->m_historyIndex].url();
00862 }
00863
00864 KUrl KUrlNavigator::uncommittedUrl() const
00865 {
00866 if (isUrlEditable()) {
00867 return KUrl(d->m_pathBox->currentText());
00868 } else {
00869 return KUrl(d->m_protocols->currentProtocol() + "://" + d->m_host->text());
00870 }
00871 }
00872
00873 KUrl KUrlNavigator::url(int index) const
00874 {
00875 if (index < 0) {
00876 index = 0;
00877 }
00878
00879
00880
00881 KUrl newUrl = url();
00882 newUrl.setPath(QString());
00883
00884 QString pathOrUrl = url().pathOrUrl();
00885 if (!pathOrUrl.isEmpty()) {
00886 if (index == 0) {
00887
00888
00889 #ifdef Q_OS_WIN
00890 pathOrUrl = pathOrUrl.length() > 2 ? pathOrUrl.left(3) : QDir::rootPath();
00891 #else
00892 pathOrUrl = QLatin1String("/");
00893 #endif
00894 } else {
00895 pathOrUrl = pathOrUrl.section('/', 0, index);
00896 }
00897 }
00898
00899 newUrl.setPath(KUrl(pathOrUrl).path());
00900 return newUrl;
00901 }
00902
00903 bool KUrlNavigator::goBack()
00904 {
00905 const int count = d->m_history.count();
00906 if (d->m_historyIndex < count - 1) {
00907 ++d->m_historyIndex;
00908 d->updateContent();
00909 emit historyChanged();
00910 emit urlChanged(url());
00911 return true;
00912 }
00913
00914 return false;
00915 }
00916
00917 bool KUrlNavigator::goForward()
00918 {
00919 if (d->m_historyIndex > 0) {
00920 --d->m_historyIndex;
00921 d->updateContent();
00922 emit historyChanged();
00923 emit urlChanged(url());
00924 return true;
00925 }
00926
00927 return false;
00928 }
00929
00930 bool KUrlNavigator::goUp()
00931 {
00932 const KUrl& currentUrl = url();
00933 const KUrl upUrl = currentUrl.upUrl();
00934 if (upUrl != currentUrl) {
00935 setUrl(upUrl);
00936 return true;
00937 }
00938
00939 return false;
00940 }
00941
00942 void KUrlNavigator::goHome()
00943 {
00944 if (d->m_homeUrl.isEmpty()) {
00945 setUrl(QDir::homePath());
00946 } else {
00947 setUrl(d->m_homeUrl);
00948 }
00949 }
00950
00951 void KUrlNavigator::setHomeUrl(const QString& homeUrl)
00952 {
00953 d->m_homeUrl = homeUrl;
00954 }
00955
00956 void KUrlNavigator::setUrlEditable(bool editable)
00957 {
00958 if (d->m_editable != editable) {
00959 d->switchView();
00960 }
00961 }
00962
00963 bool KUrlNavigator::isUrlEditable() const
00964 {
00965 return d->m_editable;
00966 }
00967
00968 void KUrlNavigator::setActive(bool active)
00969 {
00970 if (active != d->m_active) {
00971 d->m_active = active;
00972 update();
00973 if (active) {
00974 emit activated();
00975 }
00976 }
00977 }
00978
00979 bool KUrlNavigator::isActive() const
00980 {
00981 return d->m_active;
00982 }
00983
00984 void KUrlNavigator::setPlacesSelectorVisible(bool visible)
00985 {
00986 if (visible == d->m_showPlacesSelector) {
00987 return;
00988 }
00989
00990 if (visible && (d->m_placesSelector == 0)) {
00991
00992
00993 return;
00994 }
00995
00996 d->m_showPlacesSelector = visible;
00997 d->m_placesSelector->setVisible(visible);
00998 }
00999
01000 bool KUrlNavigator::isPlacesSelectorVisible() const
01001 {
01002 return d->m_showPlacesSelector;
01003 }
01004
01005 void KUrlNavigator::setUrl(const KUrl& url)
01006 {
01007 QString urlStr(KUrlCompletion::replacedPath(url.pathOrUrl(), true, true));
01008
01009 if (urlStr.length() > 0 && urlStr.at(0) == '~') {
01010
01011 urlStr.remove(0, 1);
01012 urlStr.insert(0, QDir::homePath());
01013 }
01014
01015 if ((url.protocol() == "tar") || (url.protocol() == "zip")) {
01016
01017
01018
01019 bool insideCompressedPath = d->isCompressedPath(url);
01020 if (!insideCompressedPath) {
01021 KUrl prevUrl = url;
01022 KUrl parentUrl = url.upUrl();
01023 while (parentUrl != prevUrl) {
01024 if (d->isCompressedPath(parentUrl)) {
01025 insideCompressedPath = true;
01026 break;
01027 }
01028 prevUrl = parentUrl;
01029 parentUrl = parentUrl.upUrl();
01030 }
01031 }
01032 if (!insideCompressedPath) {
01033
01034
01035 urlStr = url.path();
01036 }
01037 }
01038
01039 const KUrl transformedUrl(urlStr);
01040
01041
01042
01043 const HistoryElem& historyElem = d->m_history[d->m_historyIndex];
01044 const bool isUrlEqual = transformedUrl.equals(historyElem.url(), KUrl::CompareWithoutTrailingSlash) ||
01045 !transformedUrl.isValid() && (urlStr == historyElem.url().url());
01046 if (isUrlEqual) {
01047 return;
01048 }
01049
01050 if (d->m_historyIndex > 0) {
01051
01052
01053
01054 QList<HistoryElem>::iterator begin = d->m_history.begin();
01055 QList<HistoryElem>::iterator end = begin + d->m_historyIndex;
01056 d->m_history.erase(begin, end);
01057 d->m_historyIndex = 0;
01058 }
01059
01060 Q_ASSERT(d->m_historyIndex == 0);
01061 d->m_history.insert(0, HistoryElem(transformedUrl));
01062
01063
01064
01065 const int historyMax = 100;
01066 if (d->m_history.size() > historyMax) {
01067 QList<HistoryElem>::iterator begin = d->m_history.begin() + historyMax;
01068 QList<HistoryElem>::iterator end = d->m_history.end();
01069 d->m_history.erase(begin, end);
01070 }
01071
01072 emit historyChanged();
01073 emit urlChanged(transformedUrl);
01074
01075 d->updateContent();
01076
01077 requestActivation();
01078 }
01079
01080 void KUrlNavigator::requestActivation()
01081 {
01082 setActive(true);
01083 }
01084
01085 void KUrlNavigator::saveRootUrl(const KUrl& url)
01086 {
01087 HistoryElem& hist = d->m_history[d->m_historyIndex];
01088 hist.setRootUrl(url);
01089 }
01090
01091 void KUrlNavigator::savePosition(int x, int y)
01092 {
01093 HistoryElem& hist = d->m_history[d->m_historyIndex];
01094 hist.setContentsX(x);
01095 hist.setContentsY(y);
01096 }
01097
01098 void KUrlNavigator::keyReleaseEvent(QKeyEvent* event)
01099 {
01100 QWidget::keyReleaseEvent(event);
01101 if (isUrlEditable() && (event->key() == Qt::Key_Escape)) {
01102 setUrlEditable(false);
01103 }
01104 }
01105
01106 void KUrlNavigator::mouseReleaseEvent(QMouseEvent* event)
01107 {
01108 if (event->button() == Qt::MidButton) {
01109 QClipboard* clipboard = QApplication::clipboard();
01110 const QMimeData* mimeData = clipboard->mimeData();
01111 if (mimeData->hasText()) {
01112 const QString text = mimeData->text();
01113 setUrl(KUrl(text));
01114 }
01115 }
01116 QWidget::mouseReleaseEvent(event);
01117 }
01118
01119 void KUrlNavigator::resizeEvent(QResizeEvent* event)
01120 {
01121 QTimer::singleShot(0, this, SLOT(updateButtonVisibility()));
01122 QWidget::resizeEvent(event);
01123 }
01124
01125 int KUrlNavigator::historySize() const
01126 {
01127 return d->m_history.count();
01128 }
01129
01130 int KUrlNavigator::historyIndex() const
01131 {
01132 return d->m_historyIndex;
01133 }
01134
01135 const KUrl& KUrlNavigator::savedRootUrl() const
01136 {
01137 const HistoryElem& histElem = d->m_history[d->m_historyIndex];
01138 return histElem.rootUrl();
01139 }
01140
01141 QPoint KUrlNavigator::savedPosition() const
01142 {
01143 const HistoryElem& histElem = d->m_history[d->m_historyIndex];
01144 return QPoint(histElem.contentsX(), histElem.contentsY());
01145 }
01146
01147 KUrlComboBox* KUrlNavigator::editor() const
01148 {
01149 return d->m_pathBox;
01150 }
01151
01152 void KUrlNavigator::setCustomProtocols(const QStringList &protocols)
01153 {
01154 d->m_customProtocols = protocols;
01155
01156 d->m_protocols->setCustomProtocols(d->m_customProtocols);
01157 }
01158
01159 QStringList KUrlNavigator::customProtocols() const
01160 {
01161 return d->m_customProtocols;
01162 }
01163
01164 void KUrlNavigator::setFocus()
01165 {
01166 if (isUrlEditable()) {
01167 d->m_pathBox->setFocus();
01168 } else if (d->m_host) {
01169 d->m_host->setFocus();
01170 } else {
01171 QWidget::setFocus();
01172 }
01173 }
01174
01175 #include "kurlnavigator.moc"