| /**************************************************************************** |
| ** |
| ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). |
| ** All rights reserved. |
| ** Contact: Nokia Corporation (qt-info@nokia.com) |
| ** |
| ** This file is part of the tools applications of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** GNU Lesser General Public License Usage |
| ** This file may be used under the terms of the GNU Lesser General Public |
| ** License version 2.1 as published by the Free Software Foundation and |
| ** appearing in the file LICENSE.LGPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU Lesser |
| ** General Public License version 2.1 requirements will be met: |
| ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| ** |
| ** In addition, as a special exception, Nokia gives you certain additional |
| ** rights. These rights are described in the Nokia Qt LGPL Exception |
| ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU General |
| ** Public License version 3.0 as published by the Free Software Foundation |
| ** and appearing in the file LICENSE.GPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU General |
| ** Public License version 3.0 requirements will be met: |
| ** http://www.gnu.org/copyleft/gpl.html. |
| ** |
| ** Other Usage |
| ** Alternatively, this file may be used in accordance with the terms and |
| ** conditions contained in a signed written agreement between you and Nokia. |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| /*! \class AbstractFindWidget |
| |
| \brief A search bar that is commonly added below a searchable widget. |
| |
| \internal |
| |
| This widget implements a search bar which becomes visible when the user |
| wants to start searching. It is a modern replacement for the commonly used |
| search dialog. It is usually placed below the target widget using a QVBoxLayout. |
| |
| The search is incremental and can be set to case sensitive or whole words |
| using buttons available on the search bar. |
| */ |
| |
| #include "abstractfindwidget.h" |
| |
| #include <QtCore/QEvent> |
| #include <QtCore/QFile> |
| #include <QtCore/QTimer> |
| |
| #include <QtGui/QCheckBox> |
| #include <QtGui/QKeyEvent> |
| #include <QtGui/QLabel> |
| #include <QtGui/QLayout> |
| #include <QtGui/QLineEdit> |
| #include <QtGui/QSpacerItem> |
| #include <QtGui/QToolButton> |
| |
| QT_BEGIN_NAMESPACE |
| |
| static QIcon createIconSet(const QString &name) |
| { |
| QStringList candidates = QStringList() |
| << (QString::fromUtf8(":/trolltech/shared/images/") + name) |
| #ifdef Q_WS_MAC |
| << (QString::fromUtf8(":/trolltech/shared/images/mac/") + name); |
| #else |
| << (QString::fromUtf8(":/trolltech/shared/images/win/") + name); |
| #endif |
| |
| foreach (const QString &f, candidates) { |
| if (QFile::exists(f)) |
| return QIcon(f); |
| } |
| |
| return QIcon(); |
| } |
| |
| /*! |
| Constructs an AbstractFindWidget. |
| |
| \a flags can change the layout and turn off certain features. |
| \a parent is passed to the QWidget constructor. |
| */ |
| AbstractFindWidget::AbstractFindWidget(FindFlags flags, QWidget *parent) |
| : QWidget(parent) |
| { |
| QBoxLayout *topLayOut; |
| QBoxLayout *layOut; |
| if (flags & NarrowLayout) { |
| topLayOut = new QVBoxLayout(this); |
| layOut = new QHBoxLayout; |
| topLayOut->addLayout(layOut); |
| } else { |
| topLayOut = layOut = new QHBoxLayout(this); |
| } |
| #ifndef Q_OS_MAC |
| topLayOut->setSpacing(6); |
| topLayOut->setMargin(0); |
| #endif |
| |
| m_toolClose = new QToolButton(this); |
| m_toolClose->setIcon(createIconSet(QLatin1String("closetab.png"))); |
| m_toolClose->setAutoRaise(true); |
| layOut->addWidget(m_toolClose); |
| connect(m_toolClose, SIGNAL(clicked()), SLOT(deactivate())); |
| |
| m_editFind = new QLineEdit(this); |
| layOut->addWidget(m_editFind); |
| connect(m_editFind, SIGNAL(returnPressed()), SLOT(findNext())); |
| connect(m_editFind, SIGNAL(textChanged(QString)), SLOT(findCurrentText())); |
| connect(m_editFind, SIGNAL(textChanged(QString)), SLOT(updateButtons())); |
| |
| m_toolPrevious = new QToolButton(this); |
| m_toolPrevious->setAutoRaise(true); |
| m_toolPrevious->setText(tr("&Previous")); |
| m_toolPrevious->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); |
| m_toolPrevious->setIcon(createIconSet(QLatin1String("previous.png"))); |
| layOut->addWidget(m_toolPrevious); |
| connect(m_toolPrevious, SIGNAL(clicked()), SLOT(findPrevious())); |
| |
| m_toolNext = new QToolButton(this); |
| m_toolNext->setAutoRaise(true); |
| m_toolNext->setText(tr("&Next")); |
| m_toolNext->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); |
| m_toolNext->setIcon(createIconSet(QLatin1String("next.png"))); |
| layOut->addWidget(m_toolNext); |
| connect(m_toolNext, SIGNAL(clicked()), SLOT(findNext())); |
| |
| if (flags & NarrowLayout) { |
| QSizePolicy sp(QSizePolicy::Preferred, QSizePolicy::Fixed); |
| m_toolPrevious->setSizePolicy(sp); |
| m_toolPrevious->setMinimumWidth(m_toolPrevious->minimumSizeHint().height()); |
| m_toolNext->setSizePolicy(sp); |
| m_toolNext->setMinimumWidth(m_toolNext->minimumSizeHint().height()); |
| |
| QSpacerItem *spacerItem = |
| new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum); |
| layOut->addItem(spacerItem); |
| |
| layOut = new QHBoxLayout; |
| topLayOut->addLayout(layOut); |
| } else { |
| m_editFind->setMinimumWidth(150); |
| } |
| |
| if (!(flags & NoCaseSensitive)) { |
| m_checkCase = new QCheckBox(tr("&Case sensitive"), this); |
| layOut->addWidget(m_checkCase); |
| connect(m_checkCase, SIGNAL(toggled(bool)), SLOT(findCurrentText())); |
| } else { |
| m_checkCase = 0; |
| } |
| |
| if (!(flags & NoWholeWords)) { |
| m_checkWholeWords = new QCheckBox(tr("Whole &words"), this); |
| layOut->addWidget(m_checkWholeWords); |
| connect(m_checkWholeWords, SIGNAL(toggled(bool)), SLOT(findCurrentText())); |
| } else { |
| m_checkWholeWords = 0; |
| } |
| |
| m_labelWrapped = new QLabel(this); |
| m_labelWrapped->setTextFormat(Qt::RichText); |
| m_labelWrapped->setAlignment( |
| Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); |
| m_labelWrapped->setText( |
| tr("<img src=\":/trolltech/shared/images/wrap.png\">" |
| " Search wrapped")); |
| m_labelWrapped->hide(); |
| layOut->addWidget(m_labelWrapped); |
| |
| QSpacerItem *spacerItem = |
| new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum); |
| layOut->addItem(spacerItem); |
| |
| setMinimumWidth(minimumSizeHint().width()); |
| |
| updateButtons(); |
| hide(); |
| } |
| |
| /*! |
| Destroys the AbstractFindWidget. |
| */ |
| AbstractFindWidget::~AbstractFindWidget() |
| { |
| } |
| |
| /*! |
| Returns the icon set to be used for the action that initiates a search. |
| */ |
| QIcon AbstractFindWidget::findIconSet() |
| { |
| return createIconSet(QLatin1String("searchfind.png")); |
| } |
| |
| /*! |
| Activates the find widget, making it visible and having focus on its input |
| field. |
| */ |
| void AbstractFindWidget::activate() |
| { |
| show(); |
| m_editFind->selectAll(); |
| m_editFind->setFocus(Qt::ShortcutFocusReason); |
| } |
| |
| /*! |
| Deactivates the find widget, making it invisible and handing focus to any |
| associated QTextEdit. |
| */ |
| void AbstractFindWidget::deactivate() |
| { |
| hide(); |
| } |
| |
| void AbstractFindWidget::findNext() |
| { |
| findInternal(m_editFind->text(), true, false); |
| } |
| |
| void AbstractFindWidget::findPrevious() |
| { |
| findInternal(m_editFind->text(), true, true); |
| } |
| |
| void AbstractFindWidget::findCurrentText() |
| { |
| findInternal(m_editFind->text(), false, false); |
| } |
| |
| void AbstractFindWidget::keyPressEvent(QKeyEvent *event) |
| { |
| if (event->key() == Qt::Key_Escape) { |
| deactivate(); |
| return; |
| } |
| |
| QWidget::keyPressEvent(event); |
| } |
| |
| void AbstractFindWidget::updateButtons() |
| { |
| const bool en = !m_editFind->text().isEmpty(); |
| m_toolPrevious->setEnabled(en); |
| m_toolNext->setEnabled(en); |
| } |
| |
| void AbstractFindWidget::findInternal(const QString &ttf, bool skipCurrent, bool backward) |
| { |
| bool found = false; |
| bool wrapped = false; |
| find(ttf, skipCurrent, backward, &found, &wrapped); |
| QPalette p; |
| p.setColor(QPalette::Active, QPalette::Base, found ? Qt::white : QColor(255, 102, 102)); |
| m_editFind->setPalette(p); |
| m_labelWrapped->setVisible(wrapped); |
| } |
| |
| bool AbstractFindWidget::caseSensitive() const |
| { |
| return m_checkCase && m_checkCase->isChecked(); |
| } |
| |
| bool AbstractFindWidget::wholeWords() const |
| { |
| return m_checkWholeWords && m_checkWholeWords->isChecked(); |
| } |
| |
| bool AbstractFindWidget::eventFilter(QObject *object, QEvent *e) |
| { |
| if (isVisible() && e->type() == QEvent::KeyPress) { |
| QKeyEvent *ke = static_cast<QKeyEvent*>(e); |
| if (ke->key() == Qt::Key_Escape) { |
| hide(); |
| return true; |
| } |
| } |
| |
| return QWidget::eventFilter(object, e); |
| } |
| |
| QT_END_NAMESPACE |