33#include <QtCore/QTimer>
34#include <QtGui/QPainter>
35#include <QtGui/QKeyEvent>
36#include <QtGui/QStyleOption>
41QPointer<KUrlNavigatorMenu> KUrlNavigatorButton::m_subDirsMenu;
46 m_pendingTextChange(false),
47 m_replaceButton(false),
48 m_showMnemonic(false),
52 m_openSubDirsTimer(0),
57 setMouseTracking(
true);
59 m_openSubDirsTimer =
new QTimer(
this);
60 m_openSubDirsTimer->setSingleShot(
true);
61 m_openSubDirsTimer->setInterval(300);
62 connect(m_openSubDirsTimer, SIGNAL(
timeout()),
this, SLOT(startSubDirsJob()));
64 connect(
this, SIGNAL(pressed()),
this, SLOT(requestSubDirs()));
76 if (startTextResolving) {
82 if (protocols.isEmpty()) {
83 protocols <<
"fish" <<
"ftp" <<
"nfs" <<
"sftp" <<
"smb" <<
"webdav";
85 startTextResolving = !protocols.contains(m_url.
protocol());
88 if (startTextResolving) {
89 m_pendingTextChange =
true;
91 connect(job, SIGNAL(result(
KJob*)),
92 this, SLOT(statFinished(
KJob*)));
106 QString adjustedText = text;
107 if (adjustedText.isEmpty()) {
111 adjustedText.remove(QLatin1Char(
'\n'));
113 KUrlNavigatorButtonBase::setText(adjustedText);
114 updateMinimumWidth();
118 m_pendingTextChange =
false;
137 QFont adjustedFont(font());
138 adjustedFont.setBold(m_subDir.isEmpty());
141 const int width = QFontMetrics(adjustedFont).width(plainText()) + arrowWidth() + 4 *
BorderWidth;
142 return QSize(width, KUrlNavigatorButtonBase::sizeHint().height());
147 if (m_showMnemonic != show) {
148 m_showMnemonic = show;
155 return m_showMnemonic;
162 QPainter painter(
this);
164 QFont adjustedFont(font());
165 adjustedFont.setBold(m_subDir.isEmpty());
166 painter.setFont(adjustedFont);
168 int buttonWidth = width();
169 int preferredWidth =
sizeHint().width();
170 if (preferredWidth < minimumWidth()) {
171 preferredWidth = minimumWidth();
173 if (buttonWidth > preferredWidth) {
174 buttonWidth = preferredWidth;
176 const int buttonHeight = height();
182 int textWidth = buttonWidth;
184 const bool leftToRight = (layoutDirection() == Qt::LeftToRight);
186 if (!m_subDir.isEmpty()) {
188 const int arrowSize = arrowWidth();
190 const int arrowY = (buttonHeight - arrowSize) / 2;
193 option.initFrom(
this);
194 option.rect = QRect(arrowX, arrowY, arrowSize, arrowSize);
195 option.palette = palette();
196 option.palette.setColor(QPalette::Text, fgColor);
197 option.palette.setColor(QPalette::WindowText, fgColor);
198 option.palette.setColor(QPalette::ButtonText, fgColor);
203 QColor hoverColor = palette().color(QPalette::HighlightedText);
204 hoverColor.setAlpha(96);
205 painter.setPen(Qt::NoPen);
206 painter.setBrush(hoverColor);
212 painter.drawRect(QRect(hoverX, 0, arrowSize +
BorderWidth, buttonHeight));
216 style()->drawPrimitive(QStyle::PE_IndicatorArrowRight, &option, &painter,
this);
218 style()->drawPrimitive(QStyle::PE_IndicatorArrowLeft, &option, &painter,
this);
225 painter.setPen(fgColor);
226 const bool clipped = isTextClipped();
227 const QRect textRect(textLeft, 0, textWidth, buttonHeight);
229 QColor bgColor = fgColor;
231 QLinearGradient gradient(textRect.topLeft(), textRect.topRight());
233 gradient.setColorAt(0.8, fgColor);
234 gradient.setColorAt(1.0, bgColor);
236 gradient.setColorAt(0.0, bgColor);
237 gradient.setColorAt(0.2, fgColor);
241 pen.setBrush(QBrush(gradient));
245 int textFlags = clipped ? Qt::AlignVCenter : Qt::AlignCenter;
246 if (m_showMnemonic) {
247 textFlags |= Qt::TextShowMnemonic;
248 painter.drawText(textRect, textFlags, text());
250 painter.drawText(textRect, textFlags, plainText());
260 if (isTextClipped()) {
261 setToolTip(plainText());
268 setToolTip(QString());
271 m_hoverArrow =
false;
278 switch (event->key()) {
281 emit
clicked(m_url, Qt::LeftButton);
288 KUrlNavigatorButtonBase::keyPressEvent(event);
295 if (!urls.isEmpty()) {
307 if (event->mimeData()->hasUrls()) {
309 event->acceptProposedAction();
317 QRect rect =
event->answerRect();
318 if (isAboveArrow(rect.center().x())) {
322 if (m_subDirsMenu == 0) {
324 }
else if (m_subDirsMenu->parent() !=
this) {
325 m_subDirsMenu->close();
326 m_subDirsMenu->deleteLater();
332 if (m_openSubDirsTimer->isActive()) {
333 cancelSubDirsRequest();
335 delete m_subDirsMenu;
337 m_hoverArrow =
false;
344 KUrlNavigatorButtonBase::dragLeaveEvent(event);
346 m_hoverArrow =
false;
353 if (isAboveArrow(event->x()) && (event->button() == Qt::LeftButton)) {
357 KUrlNavigatorButtonBase::mousePressEvent(event);
362 if (!isAboveArrow(event->x()) || (event->button() != Qt::LeftButton)) {
365 emit
clicked(m_url, event->button());
366 cancelSubDirsRequest();
368 KUrlNavigatorButtonBase::mouseReleaseEvent(event);
373 KUrlNavigatorButtonBase::mouseMoveEvent(event);
375 const bool hoverArrow = isAboveArrow(event->x());
376 if (hoverArrow != m_hoverArrow) {
377 m_hoverArrow = hoverArrow;
384 if (event->orientation() == Qt::Vertical) {
385 m_wheelSteps =
event->delta() / 120;
386 m_replaceButton =
true;
390 KUrlNavigatorButtonBase::wheelEvent(event);
393void KUrlNavigatorButton::requestSubDirs()
395 if (!m_openSubDirsTimer->isActive() && (m_subDirsJob == 0)) {
396 m_openSubDirsTimer->start();
400void KUrlNavigatorButton::startSubDirsJob()
402 if (m_subDirsJob != 0) {
406 const KUrl url = m_replaceButton ? m_url.
upUrl() : m_url;
413 if (m_replaceButton) {
414 connect(m_subDirsJob, SIGNAL(result(
KJob*)),
this, SLOT(replaceButton(
KJob*)));
416 connect(m_subDirsJob, SIGNAL(result(
KJob*)),
this, SLOT(openSubDirsMenu(
KJob*)));
422 Q_ASSERT(job == m_subDirsJob);
429 if (displayName.isEmpty()) {
432 if ((name != QLatin1String(
".")) && (name != QLatin1String(
".."))) {
433 m_subDirs.append(qMakePair(name, displayName));
441 const int result = action->data().toInt();
447void KUrlNavigatorButton::slotMenuActionClicked(
QAction* action)
449 const int result = action->data().toInt();
455void KUrlNavigatorButton::statFinished(
KJob* job)
457 if (m_pendingTextChange) {
458 m_pendingTextChange =
false;
462 if (
name.isEmpty()) {
479void KUrlNavigatorButton::openSubDirsMenu(
KJob* job)
481 Q_ASSERT(job == m_subDirsJob);
484 if (job->
error() || m_subDirs.isEmpty()) {
493 if (m_subDirsMenu != 0) {
494 m_subDirsMenu->close();
495 m_subDirsMenu->deleteLater();
499 m_subDirsMenu =
new KUrlNavigatorMenu(
this);
500 initMenu(m_subDirsMenu, 0);
502 const bool leftToRight = (layoutDirection() == Qt::LeftToRight);
503 const int popupX = leftToRight ? width() - arrowWidth() -
BorderWidth : 0;
504 const QPoint popupPos = parentWidget()->mapToGlobal(geometry().bottomLeft() + QPoint(popupX, 0));
506 QPointer<QObject> guard(
this);
508 const QAction* action = m_subDirsMenu->exec(popupPos);
517 const int result = action->data().toInt();
524 delete m_subDirsMenu;
530void KUrlNavigatorButton::replaceButton(
KJob* job)
532 Q_ASSERT(job == m_subDirsJob);
534 m_replaceButton =
false;
536 if (job->
error() || m_subDirs.isEmpty()) {
543 const QString currentDir = m_url.
fileName();
544 int currentIndex = 0;
545 const int subDirsCount = m_subDirs.count();
546 while (currentIndex < subDirsCount) {
547 if (m_subDirs[currentIndex].first == currentDir) {
555 int targetIndex = currentIndex - m_wheelSteps;
556 if (targetIndex < 0) {
558 }
else if (targetIndex >= subDirsCount) {
559 targetIndex = subDirsCount - 1;
570void KUrlNavigatorButton::cancelSubDirsRequest()
572 m_openSubDirsTimer->stop();
573 if (m_subDirsJob != 0) {
574 m_subDirsJob->
kill();
579QString KUrlNavigatorButton::plainText()
const
583 const QString source = text();
584 const int sourceLength = source.length();
587 dest.reserve(sourceLength);
591 while (sourceIndex < sourceLength) {
592 if (source.at(sourceIndex) == QLatin1Char(
'&')) {
594 if (sourceIndex >= sourceLength) {
598 dest[destIndex] = source.at(sourceIndex);
606int KUrlNavigatorButton::arrowWidth()
const
610 if (!m_subDir.isEmpty()) {
611 width = height() / 2;
620bool KUrlNavigatorButton::isAboveArrow(
int x)
const
622 const bool leftToRight = (layoutDirection() == Qt::LeftToRight);
623 return leftToRight ? (x >= width() - arrowWidth()) : (x < arrowWidth());
626bool KUrlNavigatorButton::isTextClipped()
const
629 if (!m_subDir.isEmpty()) {
633 QFont adjustedFont(font());
634 adjustedFont.setBold(m_subDir.isEmpty());
635 return QFontMetrics(adjustedFont).width(plainText()) >= availableWidth;
638void KUrlNavigatorButton::updateMinimumWidth()
640 const int oldMinWidth = minimumWidth();
646 else if (minWidth > 150) {
650 if (oldMinWidth != minWidth) {
651 setMinimumWidth(minWidth);
655void KUrlNavigatorButton::initMenu(KUrlNavigatorMenu* menu,
int startIndex)
657 connect(menu, SIGNAL(middleMouseButtonClicked(
QAction*)),
658 this, SLOT(slotMenuActionClicked(
QAction*)));
662 menu->setLayoutDirection(Qt::LeftToRight);
664 const int maxIndex = startIndex + 30;
665 const int lastIndex = qMin(m_subDirs.count() - 1, maxIndex);
666 for (
int i = startIndex; i <= lastIndex; ++i) {
667 const QString subDirName = m_subDirs[i].first;
668 const QString subDirDisplayName = m_subDirs[i].second;
670 text.replace(QLatin1Char(
'&'), QLatin1String(
"&&"));
672 if (m_subDir == subDirName) {
673 QFont font(action->font());
675 action->setFont(font);
678 menu->addAction(action);
680 if (m_subDirs.count() > maxIndex) {
682 menu->addSeparator();
683 KUrlNavigatorMenu* subDirsMenu =
new KUrlNavigatorMenu(menu);
684 subDirsMenu->setTitle(
i18nc(
"@action:inmenu",
"More"));
685 initMenu(subDirsMenu, maxIndex);
686 menu->addMenu(subDirsMenu);
692#include "kurlnavigatorbutton_p.moc"
QString stringValue(uint field) const
bool kill(KillVerbosity verbosity=Quietly)
static KUrl::List fromMimeData(const QMimeData *mimeData, DecodeOptions decodeOptions, KUrl::MetaDataMap *metaData=0)
QString fileName(const DirectoryOptions &options=IgnoreTrailingSlash) const
void addPath(const QString &txt)
QString i18nc(const char *ctxt, const char *text)
static bool naturalLessThan(const QPair< QString, QString > &s1, const QPair< QString, QString > &s2)
Helper function for openSubDirsMenu.
ListJob * listDir(const KUrl &url, JobFlags flags=DefaultFlags, bool includeHidden=true)
StatJob * stat(const KUrl &url, bool sideIsSource, short int details, JobFlags flags=DefaultFlags)
const char * name(StandardAction id)
int naturalCompare(const QString &a, const QString &b, Qt::CaseSensitivity caseSensitivity=Qt::CaseSensitive)
QString csqueeze(const QString &str, int maxlen=40)