1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt Assistant of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 
29 #include "indexwindow.h"
30 
31 #include "centralwidget.h"
32 #include "helpenginewrapper.h"
33 #include "helpviewer.h"
34 #include "openpagesmanager.h"
35 #include "topicchooser.h"
36 #include "tracer.h"
37 
38 #include <QtWidgets/QLayout>
39 #include <QtWidgets/QLabel>
40 #include <QtWidgets/QLineEdit>
41 #include <QtGui/QKeyEvent>
42 #include <QtWidgets/QMenu>
43 #include <QtGui/QContextMenuEvent>
44 #include <QtWidgets/QListWidgetItem>
45 
46 #include <QtHelp/QHelpIndexWidget>
47 #include <QtHelp/QHelpEngineCore>
48 #include <QtHelp/QHelpLink>
49 
50 QT_BEGIN_NAMESPACE
51 
IndexWindow(QWidget * parent)52 IndexWindow::IndexWindow(QWidget *parent)
53     : QWidget(parent)
54     , m_searchLineEdit(new QLineEdit)
55     , m_indexWidget(HelpEngineWrapper::instance().indexWidget())
56 {
57     TRACE_OBJ
58     QVBoxLayout *layout = new QVBoxLayout(this);
59     QLabel *l = new QLabel(tr("&Look for:"));
60     layout->addWidget(l);
61 
62     l->setBuddy(m_searchLineEdit);
63     m_searchLineEdit->setClearButtonEnabled(true);
64     connect(m_searchLineEdit, &QLineEdit::textChanged,
65             this, &IndexWindow::filterIndices);
66     m_searchLineEdit->installEventFilter(this);
67     layout->setContentsMargins(4, 4, 4, 4);
68     layout->addWidget(m_searchLineEdit);
69 
70     HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance();
71     m_indexWidget->installEventFilter(this);
72     connect(helpEngine.indexModel(), &QHelpIndexModel::indexCreationStarted,
73             this, &IndexWindow::disableSearchLineEdit);
74     connect(helpEngine.indexModel(), &QHelpIndexModel::indexCreated,
75             this, &IndexWindow::enableSearchLineEdit);
76     connect(m_indexWidget, &QHelpIndexWidget::documentActivated,
77             this, [this](const QHelpLink &link) {
78         emit linkActivated(link.url);
79     });
80     connect(m_indexWidget, &QHelpIndexWidget::documentsActivated,
81             this, &IndexWindow::documentsActivated);
82     connect(m_searchLineEdit, &QLineEdit::returnPressed,
83             m_indexWidget, &QHelpIndexWidget::activateCurrentItem);
84     layout->addWidget(m_indexWidget);
85 
86     m_indexWidget->viewport()->installEventFilter(this);
87 }
88 
~IndexWindow()89 IndexWindow::~IndexWindow()
90 {
91     TRACE_OBJ
92 }
93 
filterIndices(const QString & filter)94 void IndexWindow::filterIndices(const QString &filter)
95 {
96     TRACE_OBJ
97     if (filter.contains(QLatin1Char('*')))
98         m_indexWidget->filterIndices(filter, filter);
99     else
100         m_indexWidget->filterIndices(filter, QString());
101 }
102 
eventFilter(QObject * obj,QEvent * e)103 bool IndexWindow::eventFilter(QObject *obj, QEvent *e)
104 {
105     TRACE_OBJ
106     if (obj == m_searchLineEdit && e->type() == QEvent::KeyPress) {
107         QKeyEvent *ke = static_cast<QKeyEvent*>(e);
108         QModelIndex idx = m_indexWidget->currentIndex();
109         switch (ke->key()) {
110         case Qt::Key_Up:
111             idx = m_indexWidget->model()->index(idx.row()-1,
112                 idx.column(), idx.parent());
113             if (idx.isValid()) {
114                 m_indexWidget->setCurrentIndex(idx);
115                 return true;
116             }
117             break;
118         case Qt::Key_Down:
119             idx = m_indexWidget->model()->index(idx.row() + 1,
120                 idx.column(), idx.parent());
121             if (idx.isValid()) {
122                 m_indexWidget->setCurrentIndex(idx);
123                 return true;
124             }
125             break;
126         case Qt::Key_Escape:
127             emit escapePressed();
128             return true;
129         default: ; // stop complaining
130         }
131     } else if (obj == m_indexWidget && e->type() == QEvent::ContextMenu) {
132         QContextMenuEvent *ctxtEvent = static_cast<QContextMenuEvent*>(e);
133         QModelIndex idx = m_indexWidget->indexAt(ctxtEvent->pos());
134         if (idx.isValid()) {
135             QMenu menu;
136             QAction *curTab = menu.addAction(tr("Open Link"));
137             QAction *newTab = menu.addAction(tr("Open Link in New Tab"));
138             menu.move(m_indexWidget->mapToGlobal(ctxtEvent->pos()));
139 
140             QAction *action = menu.exec();
141             if (curTab == action)
142                 m_indexWidget->activateCurrentItem();
143             else if (newTab == action) {
144                 open(m_indexWidget, idx);
145             }
146         }
147     } else if (m_indexWidget && obj == m_indexWidget->viewport()
148         && e->type() == QEvent::MouseButtonRelease) {
149         QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(e);
150         QModelIndex idx = m_indexWidget->indexAt(mouseEvent->pos());
151         if (idx.isValid()) {
152             Qt::MouseButtons button = mouseEvent->button();
153             if (((button == Qt::LeftButton) && (mouseEvent->modifiers() & Qt::ControlModifier))
154                 || (button == Qt::MiddleButton)) {
155                 open(m_indexWidget, idx);
156             }
157         }
158     }
159 #ifdef Q_OS_MAC
160     else if (obj == m_indexWidget && e->type() == QEvent::KeyPress) {
161         QKeyEvent *ke = static_cast<QKeyEvent*>(e);
162         if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter)
163            m_indexWidget->activateCurrentItem();
164     }
165 #endif
166     return QWidget::eventFilter(obj, e);
167 }
168 
enableSearchLineEdit()169 void IndexWindow::enableSearchLineEdit()
170 {
171     TRACE_OBJ
172     m_searchLineEdit->setDisabled(false);
173     filterIndices(m_searchLineEdit->text());
174 }
175 
disableSearchLineEdit()176 void IndexWindow::disableSearchLineEdit()
177 {
178     TRACE_OBJ
179     m_searchLineEdit->setDisabled(true);
180 }
181 
setSearchLineEditText(const QString & text)182 void IndexWindow::setSearchLineEditText(const QString &text)
183 {
184     TRACE_OBJ
185     m_searchLineEdit->setText(text);
186 }
187 
focusInEvent(QFocusEvent * e)188 void IndexWindow::focusInEvent(QFocusEvent *e)
189 {
190     TRACE_OBJ
191     if (e->reason() != Qt::MouseFocusReason) {
192         m_searchLineEdit->selectAll();
193         m_searchLineEdit->setFocus();
194     }
195 }
196 
open(QHelpIndexWidget * indexWidget,const QModelIndex & index)197 void IndexWindow::open(QHelpIndexWidget* indexWidget, const QModelIndex &index)
198 {
199     TRACE_OBJ
200     QHelpIndexModel *model = qobject_cast<QHelpIndexModel*>(indexWidget->model());
201     if (model) {
202         const QString keyword = model->data(index, Qt::DisplayRole).toString();
203         const QList<QHelpLink> docs = model->helpEngine()->documentsForKeyword(keyword);
204 
205         QUrl url;
206         if (docs.count() > 1) {
207             TopicChooser tc(this, keyword, docs);
208             if (tc.exec() == QDialog::Accepted)
209                 url = tc.link();
210         } else if (!docs.isEmpty()) {
211             url = docs.first().url;
212         } else {
213             return;
214         }
215 
216         if (!HelpViewer::canOpenPage(url.path()))
217             CentralWidget::instance()->setSource(url);
218         else
219             OpenPagesManager::instance()->createPage(url);
220     }
221 }
222 
223 QT_END_NAMESPACE
224