┌   ┐
54
└   ┘

summaryrefslogtreecommitdiff
path: root/src/kurlnavigatorbutton.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/kurlnavigatorbutton.cpp')
-rw-r--r--src/kurlnavigatorbutton.cpp361
1 files changed, 361 insertions, 0 deletions
diff --git a/src/kurlnavigatorbutton.cpp b/src/kurlnavigatorbutton.cpp
new file mode 100644
index 000000000..2e8f5fe0b
--- /dev/null
+++ b/src/kurlnavigatorbutton.cpp
@@ -0,0 +1,361 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz ([email protected]) *
+ * Copyright (C) 2006 by Aaron J. Seigo (<[email protected]>) *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
+ ***************************************************************************/
+
+#include "kurlnavigatorbutton_p.h"
+
+#include <assert.h>
+
+#include "kurlnavigator.h"
+
+#include <kio/job.h>
+#include <kio/jobclasses.h>
+#include <kglobalsettings.h>
+#include <kmenu.h>
+
+#include <QPainter>
+#include <QPaintEvent>
+#include <QTimer>
+
+KUrlNavigatorButton::KUrlNavigatorButton(int index, KUrlNavigator* parent) :
+ KUrlButton(parent),
+ m_index(-1),
+ m_popupDelay(0),
+ m_listJob(0)
+{
+ setAcceptDrops(true);
+ setMinimumWidth(arrowWidth());
+ setIndex(index);
+ connect(this, SIGNAL(clicked()), this, SLOT(updateNavigatorUrl()));
+
+ m_popupDelay = new QTimer(this);
+ m_popupDelay->setSingleShot(true);
+ connect(m_popupDelay, SIGNAL(timeout()), this, SLOT(startListJob()));
+ connect(this, SIGNAL(pressed()), this, SLOT(startPopupDelay()));
+}
+
+KUrlNavigatorButton::~KUrlNavigatorButton()
+{
+}
+
+void KUrlNavigatorButton::setIndex(int index)
+{
+ m_index = index;
+
+ if (m_index < 0) {
+ return;
+ }
+
+ QString path(urlNavigator()->url().pathOrUrl());
+ setText(path.section('/', index, index));
+
+ // Check whether the button indicates the full path of the Url. If
+ // this is the case, the button is marked as 'active'.
+ ++index;
+ QFont adjustedFont(font());
+ if (path.section('/', index, index).isEmpty()) {
+ setDisplayHintEnabled(ActivatedHint, true);
+ adjustedFont.setBold(true);
+ }
+ else {
+ setDisplayHintEnabled(ActivatedHint, false);
+ adjustedFont.setBold(false);
+ }
+
+ setFont(adjustedFont);
+ update();
+}
+
+QSize KUrlNavigatorButton::sizeHint() const
+{
+ const int width = fontMetrics().width(text()) + (arrowWidth() * 4);
+ return QSize(width, KUrlButton::sizeHint().height());
+}
+
+void KUrlNavigatorButton::paintEvent(QPaintEvent* event)
+{
+ QPainter painter(this);
+ painter.setClipRect(event->rect());
+ const int buttonWidth = width();
+ const int buttonHeight = height();
+
+ QColor backgroundColor;
+ QColor foregroundColor;
+ const bool isHighlighted = isDisplayHintEnabled(EnteredHint) ||
+ isDisplayHintEnabled(DraggedHint) ||
+ isDisplayHintEnabled(PopupActiveHint);
+ if (isHighlighted) {
+ backgroundColor = KGlobalSettings::highlightColor();
+ foregroundColor = KGlobalSettings::highlightedTextColor();
+ }
+ else {
+ backgroundColor = palette().brush(QPalette::Background).color();
+ foregroundColor = KGlobalSettings::buttonTextColor();
+ }
+
+ // dimm the colors if the parent view does not have the focus
+ const bool isActive = urlNavigator()->isActive();
+ if (!isActive) {
+ QColor dimmColor(palette().brush(QPalette::Background).color());
+ foregroundColor = mixColors(foregroundColor, dimmColor);
+ if (isHighlighted) {
+ backgroundColor = mixColors(backgroundColor, dimmColor);
+ }
+ }
+
+ // draw button background
+ painter.setPen(Qt::NoPen);
+ painter.setBrush(backgroundColor);
+ painter.drawRect(0, 0, buttonWidth, buttonHeight);
+
+ int textWidth = buttonWidth;
+ if (isDisplayHintEnabled(ActivatedHint) && isActive || isHighlighted) {
+ painter.setPen(foregroundColor);
+ }
+ else {
+ // dimm the foreground color by mixing it with the background
+ foregroundColor = mixColors(foregroundColor, backgroundColor);
+ painter.setPen(foregroundColor);
+ }
+
+ if (!isDisplayHintEnabled(ActivatedHint)) {
+ // draw arrow
+ const int border = 2; // horizontal border
+ const int middleY = height() / 2;
+ const int width = arrowWidth();
+ const int startX = (buttonWidth - width) - (2 * border);
+ const int startTopY = middleY - (width - 1);
+ const int startBottomY = middleY + (width - 1);
+ for (int i = 0; i < width; ++i) {
+ painter.drawLine(startX, startTopY + i, startX + i, startTopY + i);
+ painter.drawLine(startX, startBottomY - i, startX + i, startBottomY - i);
+ }
+
+ textWidth = startX - border;
+ }
+
+ const bool clipped = isTextClipped();
+ const int align = clipped ? Qt::AlignVCenter : Qt::AlignCenter;
+ const QRect textRect(0, 0, textWidth, buttonHeight);
+ if (clipped) {
+ QLinearGradient gradient(textRect.topLeft(), textRect.topRight());
+ gradient.setColorAt(0.8, foregroundColor);
+ gradient.setColorAt(1.0, backgroundColor);
+
+ QPen pen;
+ pen.setBrush(QBrush(gradient));
+ painter.setPen(pen);
+ painter.drawText(textRect, align, text());
+ }
+ else {
+ painter.drawText(textRect, align, text());
+ }
+}
+
+void KUrlNavigatorButton::enterEvent(QEvent* event)
+{
+ KUrlButton::enterEvent(event);
+
+ // if the text is clipped due to a small window width, the text should
+ // be shown as tooltip
+ if (isTextClipped()) {
+ setToolTip(text());
+ }
+}
+
+void KUrlNavigatorButton::leaveEvent(QEvent* event)
+{
+ KUrlButton::leaveEvent(event);
+ setToolTip(QString());
+}
+
+void KUrlNavigatorButton::dropEvent(QDropEvent* event)
+{
+ if (m_index < 0) {
+ return;
+ }
+
+ const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
+ if (!urls.isEmpty()) {
+ event->acceptProposedAction();
+
+ setDisplayHintEnabled(DraggedHint, true);
+
+ QString path(urlNavigator()->url().prettyUrl());
+ path = path.section('/', 0, m_index + 2);
+
+ urlNavigator()->dropUrls(urls, KUrl(path));
+
+ setDisplayHintEnabled(DraggedHint, false);
+ update();
+ }
+}
+
+void KUrlNavigatorButton::dragEnterEvent(QDragEnterEvent* event)
+{
+ if (event->mimeData()->hasUrls()) {
+ setDisplayHintEnabled(DraggedHint, true);
+ event->acceptProposedAction();
+
+ update();
+ }
+}
+
+void KUrlNavigatorButton::dragLeaveEvent(QDragLeaveEvent* event)
+{
+ KUrlButton::dragLeaveEvent(event);
+
+ setDisplayHintEnabled(DraggedHint, false);
+ update();
+}
+
+
+void KUrlNavigatorButton::updateNavigatorUrl()
+{
+ stopPopupDelay();
+
+ if (m_index < 0) {
+ return;
+ }
+
+ urlNavigator()->setUrl(urlNavigator()->url(m_index));
+}
+
+void KUrlNavigatorButton::startPopupDelay()
+{
+ if (m_popupDelay->isActive() || (m_listJob != 0) || (m_index < 0)) {
+ return;
+ }
+
+ m_popupDelay->start(300);
+}
+
+void KUrlNavigatorButton::stopPopupDelay()
+{
+ m_popupDelay->stop();
+ if (m_listJob != 0) {
+ m_listJob->kill();
+ m_listJob = 0;
+ }
+}
+
+void KUrlNavigatorButton::startListJob()
+{
+ if (m_listJob != 0) {
+ return;
+ }
+
+ const KUrl& url = urlNavigator()->url(m_index);
+ m_listJob = KIO::listDir(url, false, urlNavigator()->showHiddenFiles());
+ m_subdirs.clear(); // just to be ++safe
+
+ connect(m_listJob, SIGNAL(entries(KIO::Job*, const KIO::UDSEntryList &)),
+ this, SLOT(entriesList(KIO::Job*, const KIO::UDSEntryList&)));
+ connect(m_listJob, SIGNAL(result(KJob*)), this, SLOT(listJobFinished(KJob*)));
+}
+
+void KUrlNavigatorButton::entriesList(KIO::Job* job, const KIO::UDSEntryList& entries)
+{
+ if (job != m_listJob) {
+ return;
+ }
+
+ KIO::UDSEntryList::const_iterator it = entries.constBegin();
+ KIO::UDSEntryList::const_iterator itEnd = entries.constEnd();
+
+ bool showHidden = urlNavigator()->showHiddenFiles();
+ while (it != itEnd) {
+ const KIO::UDSEntry entry = *it;
+ if (entry.isDir()) {
+ QString name = entry.stringValue(KIO::UDS_NAME);
+
+ if (!showHidden || (name != "." && name != "..")) {
+ m_subdirs.append(name);
+ }
+ }
+
+ ++it;
+ }
+
+ m_subdirs.sort();
+}
+
+void KUrlNavigatorButton::listJobFinished(KJob* job)
+{
+ if (job != m_listJob) {
+ return;
+ }
+
+ if (job->error() || m_subdirs.isEmpty()) {
+ // clear listing
+ return;
+ }
+
+ setDisplayHintEnabled(PopupActiveHint, true);
+ update(); // ensure the button is drawn highlighted
+
+ KMenu* dirsMenu = new KMenu(this);
+ QStringList::const_iterator it = m_subdirs.constBegin();
+ QStringList::const_iterator itEnd = m_subdirs.constEnd();
+ int i = 0;
+ while (it != itEnd) {
+ QAction* action = new QAction(*it, this);
+ action->setData(i);
+ dirsMenu->addAction(action);
+ ++it;
+ ++i;
+ }
+
+ const QAction* action = dirsMenu->exec(urlNavigator()->mapToGlobal(geometry().bottomLeft()));
+ if (action != 0) {
+ const int result = action->data().toInt();
+ KUrl url = urlNavigator()->url(m_index);
+ url.addPath(m_subdirs[result]);
+ urlNavigator()->setUrl(url);
+ }
+
+ m_listJob = 0;
+ m_subdirs.clear();
+ delete dirsMenu;
+ dirsMenu = 0;
+
+ setDisplayHintEnabled(PopupActiveHint, false);
+}
+
+int KUrlNavigatorButton::arrowWidth() const
+{
+ int width = (height() / 2) - 7;
+ if (width < 4) {
+ width = 4;
+ }
+ return width;
+}
+
+bool KUrlNavigatorButton::isTextClipped() const
+{
+ int availableWidth = width();
+ if (!isDisplayHintEnabled(ActivatedHint)) {
+ availableWidth -= arrowWidth() + 1;
+ }
+
+ QFontMetrics fontMetrics(font());
+ return fontMetrics.width(text()) >= availableWidth;
+}
+
+#include "kurlnavigatorbutton_p.moc"