1 //=============================================================================
2 //
3 //   File : HelpWindow.cpp
4 //   Creation date : Tue Aug 11 2000 18:08:22 by Szymon Stefanek
5 //
6 //   This file is part of the KVIrc IRC client distribution
7 //   Copyright (C) 2000-2010 Szymon Stefanek (pragma at kvirc dot net)
8 //
9 //   This program is FREE software. You can redistribute it and/or
10 //   modify it under the m_terms of the GNU General Public License
11 //   as published by the Free Software Foundation; either version 2
12 //   of the License, or (at your option) any later version.
13 //
14 //   This program is distributed in the HOPE that it will be USEFUL,
15 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 //   See the GNU General Public License for more details.
18 //
19 //   You should have received a copy of the GNU General Public License
20 //   along with this program. If not, write to the Free Software Foundation,
21 //   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 //=============================================================================
24 
25 #include "HelpWindow.h"
26 #include "HelpWidget.h"
27 
28 #include "kvi_settings.h"
29 #include "KviApplication.h"
30 #include "KviIconManager.h"
31 #include "KviOptions.h"
32 #include "KviLocale.h"
33 #include "KviModule.h"
34 #include "KviConfigurationFile.h"
35 #include "kvi_sourcesdate.h"
36 
37 #include <QList>
38 #include <QFileInfo>
39 #include <QLineEdit>
40 #include <QMessageBox>
41 #include <QPushButton>
42 #include <QRegExp>
43 #include <QToolTip>
44 #include <QTimer>
45 
46 extern HelpIndex * g_pDocIndex;
47 extern KviPointerList<HelpWindow> * g_pHelpWindowList;
48 extern KviPointerList<HelpWidget> * g_pHelpWidgetList;
49 
50 //bool g_bIndexingDone = false;
HelpWindow(const char * name)51 HelpWindow::HelpWindow(const char * name)
52     : KviWindow(KviWindow::Help, name)
53 {
54 	g_pHelpWindowList->append(this);
55 	m_pSplitter = new KviTalSplitter(Qt::Horizontal, this);
56 	m_pSplitter->setObjectName("main_splitter");
57 	m_pSplitter->setChildrenCollapsible(false);
58 
59 	m_pHelpWidget = new HelpWidget(m_pSplitter);
60 
61 	m_pToolBar = new KviTalVBox(m_pSplitter);
62 	m_pTabWidget = new QTabWidget(m_pToolBar);
63 
64 	m_pBottomLayout = new KviTalHBox(m_pToolBar);
65 	m_pProgressBar = new QProgressBar(m_pBottomLayout);
66 	m_pCancelButton = new QPushButton(m_pBottomLayout);
67 	m_pCancelButton->setText(__tr2qs_ctx("Cancel", "logview"));
68 	connect(m_pCancelButton, SIGNAL(clicked()), g_pDocIndex, SLOT(setLastWinClosed()));
69 	m_pBottomLayout->setVisible(false);
70 
71 	m_pIndexTab = new KviTalVBox(m_pTabWidget);
72 	m_pTabWidget->addTab(m_pIndexTab, __tr2qs("Help Index"));
73 
74 	KviTalHBox * pSearchBox = new KviTalHBox(m_pIndexTab);
75 	m_pIndexSearch = new QLineEdit(pSearchBox);
76 	connect(m_pIndexSearch, SIGNAL(textChanged(const QString &)), this, SLOT(searchInIndex(const QString &)));
77 	connect(m_pIndexSearch, SIGNAL(returnPressed()), this, SLOT(showIndexTopic()));
78 
79 	m_pBtnRefreshIndex = new QPushButton(pSearchBox);
80 	m_pBtnRefreshIndex->setIcon(*g_pIconManager->getBigIcon(KVI_REFRESH_IMAGE_NAME));
81 	connect(m_pBtnRefreshIndex, SIGNAL(clicked()), this, SLOT(refreshIndex()));
82 	m_pBtnRefreshIndex->setToolTip(__tr2qs("Refresh index"));
83 
84 	m_pIndexListWidget = new KviTalListWidget(m_pIndexTab);
85 	connect(m_pIndexListWidget, SIGNAL(itemActivated(QListWidgetItem *)), this, SLOT(indexSelected(QListWidgetItem *)));
86 
87 	m_pSearchTab = new KviTalVBox(m_pTabWidget);
88 	m_pTabWidget->addTab(m_pSearchTab, __tr2qs("Search"));
89 
90 	m_pTermsEdit = new QLineEdit(m_pSearchTab);
91 
92 	connect(m_pTermsEdit, SIGNAL(returnPressed()), this, SLOT(startSearch()));
93 
94 	m_pResultBox = new KviTalListWidget(m_pSearchTab);
95 	connect(m_pResultBox, SIGNAL(itemActivated(QListWidgetItem *)), this, SLOT(searchSelected(QListWidgetItem *)));
96 
97 	QList<int> li;
98 	li.append(width() - 80);
99 	li.append(80);
100 	m_pSplitter->setSizes(li);
101 
102 	connect(g_pDocIndex, SIGNAL(indexingStart(int)), this, SLOT(indexingStart(int)));
103 	connect(g_pDocIndex, SIGNAL(indexingProgress(int)), this, SLOT(indexingProgress(int)));
104 	connect(g_pDocIndex, SIGNAL(indexingEnd()), this, SLOT(indexingEnd()));
105 
106 	QTimer::singleShot(0, this, SLOT(initialSetup()));
107 }
108 
~HelpWindow()109 HelpWindow::~HelpWindow()
110 {
111 	g_pHelpWindowList->removeRef(this);
112 }
113 
initialSetup()114 void HelpWindow::initialSetup()
115 {
116 	m_pIndexSearch->setFocus();
117 
118 	QString szDoclist, szDict;
119 
120 	g_pApp->getLocalKvircDirectory(szDoclist, KviApplication::Help, "help.doclist." KVI_SOURCES_DATE);
121 	g_pApp->getLocalKvircDirectory(szDict, KviApplication::Help, "help.dict." KVI_SOURCES_DATE);
122 
123 	if(QFileInfo(szDoclist).exists() && QFileInfo(szDict).exists())
124 	{
125 		g_pDocIndex->readDict();
126 		m_pIndexListWidget->clear();
127 		QStringList docList = g_pDocIndex->titlesList();
128 		m_pIndexListWidget->addItems(docList);
129 		m_pIndexListWidget->sortItems();
130 		m_pBtnRefreshIndex->setEnabled(true);
131 	}
132 	else
133 		g_pDocIndex->makeIndex();
134 }
135 
indexingStart(int iNum)136 void HelpWindow::indexingStart(int iNum)
137 {
138 	m_pBtnRefreshIndex->setEnabled(false);
139 	m_pBottomLayout->setVisible(true);
140 	m_pProgressBar->setRange(0, iNum);
141 	m_pProgressBar->setValue(0);
142 }
143 
indexingProgress(int iNum)144 void HelpWindow::indexingProgress(int iNum)
145 {
146 	m_pProgressBar->setValue(iNum);
147 }
148 
indexingEnd()149 void HelpWindow::indexingEnd()
150 {
151 	m_pProgressBar->setValue(0);
152 	m_pBottomLayout->setVisible(false);
153 	g_pDocIndex->writeDict();
154 	m_pIndexListWidget->clear();
155 	QStringList docList = g_pDocIndex->titlesList();
156 	m_pIndexListWidget->addItems(docList);
157 	m_pIndexListWidget->sortItems();
158 	m_pBtnRefreshIndex->setEnabled(true);
159 }
160 
saveProperties(KviConfigurationFile * cfg)161 void HelpWindow::saveProperties(KviConfigurationFile * cfg)
162 {
163 	KviWindow::saveProperties(cfg);
164 	cfg->writeEntry("Splitter", m_pSplitter->sizes());
165 }
166 
loadProperties(KviConfigurationFile * cfg)167 void HelpWindow::loadProperties(KviConfigurationFile * cfg)
168 {
169 	QList<int> def;
170 	int w = width();
171 	def.append((w * 82) / 100);
172 	def.append((w * 18) / 100);
173 	m_pSplitter->setSizes(cfg->readIntListEntry("Splitter", def));
174 	KviWindow::loadProperties(cfg);
175 }
176 
refreshIndex()177 void HelpWindow::refreshIndex()
178 {
179 	g_pDocIndex->makeIndex();
180 }
181 
startSearch()182 void HelpWindow::startSearch()
183 {
184 	QString str = m_pTermsEdit->text();
185 	str = str.replace("\'", "\"");
186 	str = str.replace("`", "\"");
187 	QString buf = str;
188 	str = str.replace("-", " ");
189 	str = str.replace(QRegExp(R"(\s[\S]?\s)"), " ");
190 	m_terms = str.split(" ", QString::SkipEmptyParts);
191 	QStringList termSeq;
192 	QStringList seqWords;
193 	QStringList::iterator it = m_terms.begin();
194 	for(; it != m_terms.end(); ++it)
195 	{
196 		(*it) = (*it).simplified();
197 		(*it) = (*it).toLower();
198 		(*it) = (*it).replace("\"", "");
199 	}
200 	if(str.contains('\"'))
201 	{
202 		if((str.count('\"')) % 2 == 0)
203 		{
204 			int beg = 0;
205 			int end = 0;
206 			QString s;
207 			beg = str.indexOf('\"', beg);
208 			while(beg != -1)
209 			{
210 				beg++;
211 				end = str.indexOf('\"', beg);
212 				s = str.mid(beg, end - beg);
213 				s = s.toLower();
214 				s = s.simplified();
215 				if(s.contains('*'))
216 				{
217 					QMessageBox::warning(this, __tr2qs("Full Text Search - KVIrc"),
218 					    __tr2qs("Using a wildcard within phrases is not allowed."));
219 					return;
220 				}
221 				seqWords += s.split(' ', QString::SkipEmptyParts);
222 				termSeq << s;
223 				beg = str.indexOf('\"', end + 1);
224 			}
225 		}
226 		else
227 		{
228 			QMessageBox::warning(this, __tr2qs("Full Text Search - KVIrc"),
229 			    __tr2qs("The closing quotation mark is missing."));
230 			return;
231 		}
232 	}
233 	setCursor(Qt::WaitCursor);
234 	m_foundDocs.clear();
235 	m_foundDocs = g_pDocIndex->query(m_terms, termSeq, seqWords);
236 
237 	m_pResultBox->clear();
238 	for(it = m_foundDocs.begin(); it != m_foundDocs.end(); ++it)
239 		m_pResultBox->addItem(g_pDocIndex->getDocumentTitle(*it));
240 
241 	m_terms.clear();
242 	bool isPhrase = false;
243 	QString s = "";
244 	for(const auto & i : buf)
245 	{
246 		if(i == '\"')
247 		{
248 			isPhrase = !isPhrase;
249 			s = s.simplified();
250 			if(!s.isEmpty())
251 				m_terms << s;
252 			s = "";
253 		}
254 		else if(i == ' ' && !isPhrase)
255 		{
256 			s = s.simplified();
257 			if(!s.isEmpty())
258 				m_terms << s;
259 			s = "";
260 		}
261 		else
262 			s += i;
263 	}
264 	if(!s.isEmpty())
265 		m_terms << s;
266 
267 	setCursor(Qt::ArrowCursor);
268 }
269 
270 #ifdef COMPILE_WEBKIT_SUPPORT
textBrowser()271 QWebView * HelpWindow::textBrowser()
272 #else
273 QTextBrowser * HelpWindow::textBrowser()
274 #endif
275 {
276 	return m_pHelpWidget->textBrowser();
277 }
278 
showIndexTopic()279 void HelpWindow::showIndexTopic()
280 {
281 	if(m_pIndexSearch->text().isEmpty() || !m_pIndexListWidget->selectedItems().count())
282 		return;
283 	int i = g_pDocIndex->titlesList().indexOf(m_pIndexListWidget->selectedItems().at(0)->text());
284 #ifdef COMPILE_WEBKIT_SUPPORT
285 	textBrowser()->load(QUrl(g_pDocIndex->documentList()[i]));
286 #else
287 	textBrowser()->setSource(QUrl(g_pDocIndex->documentList()[i]));
288 #endif
289 }
290 
searchInIndex(const QString & s)291 void HelpWindow::searchInIndex(const QString & s)
292 {
293 	QListWidgetItem * item;
294 	QString sl = s.toLower();
295 	for(int i = 0; i < m_pIndexListWidget->count(); i++)
296 	{
297 		item = m_pIndexListWidget->item(i);
298 		QString t = item->text();
299 		if(t.length() >= sl.length() && item->text().left(s.length()).toLower() == sl)
300 		{
301 			m_pIndexListWidget->setCurrentItem(item);
302 			m_pIndexListWidget->scrollToItem(item, QAbstractItemView::PositionAtTop);
303 			break;
304 		}
305 	}
306 }
307 
indexSelected(QListWidgetItem * item)308 void HelpWindow::indexSelected(QListWidgetItem * item)
309 {
310 	if(!item)
311 		return;
312 	int i = g_pDocIndex->titlesList().indexOf(item->text());
313 #ifdef COMPILE_WEBKIT_SUPPORT
314 	textBrowser()->load(QUrl(g_pDocIndex->documentList()[i]));
315 #else
316 	textBrowser()->setSource(QUrl(g_pDocIndex->documentList()[i]));
317 #endif
318 }
319 
searchSelected(QListWidgetItem * item)320 void HelpWindow::searchSelected(QListWidgetItem * item)
321 {
322 	if(!item)
323 		return;
324 	int i = g_pDocIndex->titlesList().indexOf(item->text());
325 #ifdef COMPILE_WEBKIT_SUPPORT
326 	textBrowser()->load(QUrl(g_pDocIndex->documentList()[i]));
327 #else
328 	textBrowser()->setSource(QUrl(g_pDocIndex->documentList()[i]));
329 #endif
330 }
331 
myIconPtr()332 QPixmap * HelpWindow::myIconPtr()
333 {
334 	return g_pIconManager->getSmallIcon(KviIconManager::QuestionMark);
335 }
336 
resizeEvent(QResizeEvent *)337 void HelpWindow::resizeEvent(QResizeEvent *)
338 {
339 	m_pSplitter->setGeometry(0, 0, width(), height());
340 }
341 
fillCaptionBuffers()342 void HelpWindow::fillCaptionBuffers()
343 {
344 	m_szPlainTextCaption = __tr2qs("Help Browser");
345 }
346