1 /*
2 * Copyright 2005-2021 Fabrice Colin
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #include <iostream>
20 #include <glibmm/ustring.h>
21 #include <glibmm/convert.h>
22 #include <gtkmm/menu.h>
23
24 #include "config.h"
25 #include "NLS.h"
26 #include "Languages.h"
27 #include "TimeConverter.h"
28 #include "PinotUtils.h"
29 #include "QueryDialog.h"
30
31 using namespace std;
32 using namespace Glib;
33 using namespace Gtk;
34
QueryDialog(GtkDialog * & pParent,RefPtr<Builder> & refBuilder)35 QueryDialog::QueryDialog(GtkDialog *&pParent, RefPtr<Builder>& refBuilder) :
36 Dialog(pParent),
37 queryCancelButton(NULL),
38 queryOkButton(NULL),
39 addFilterButton(NULL),
40 nameEntry(NULL),
41 filterCombobox(NULL),
42 queryTextview(NULL),
43 indexCheckbutton(NULL),
44 labelNameCombobox(NULL),
45 resultsCountSpinbutton(NULL),
46 sortOrderCombobox(NULL),
47 stemmingCombobox(NULL),
48 indexNewCheckbutton(NULL),
49 m_name(""),
50 m_badName(true)
51 {
52 refBuilder->get_widget("queryCancelButton", queryCancelButton);
53 refBuilder->get_widget("queryOkButton", queryOkButton);
54 refBuilder->get_widget("addFilterButton", addFilterButton);
55 refBuilder->get_widget("queryNameEntry", nameEntry);
56 refBuilder->get_widget("filterCombobox", filterCombobox);
57 refBuilder->get_widget("queryTextview", queryTextview);
58 refBuilder->get_widget("indexCheckbutton", indexCheckbutton);
59 refBuilder->get_widget("labelNameCombobox", labelNameCombobox);
60 refBuilder->get_widget("resultsCountSpinbutton", resultsCountSpinbutton);
61 refBuilder->get_widget("sortOrderCombobox", sortOrderCombobox);
62 refBuilder->get_widget("stemmingCombobox", stemmingCombobox);
63 refBuilder->get_widget("indexNewCheckbutton", indexNewCheckbutton);
64
65 queryCancelButton->signal_clicked().connect(sigc::mem_fun(*this, &QueryDialog::on_queryCancelButton_clicked), false);
66 queryOkButton->signal_clicked().connect(sigc::mem_fun(*this, &QueryDialog::on_queryOkButton_clicked), false);
67 nameEntry->signal_changed().connect(sigc::mem_fun(*this, &QueryDialog::on_nameEntry_changed), false);
68 addFilterButton->signal_clicked().connect(sigc::mem_fun(*this, &QueryDialog::on_addFilterButton_clicked), false);
69 indexCheckbutton->signal_toggled().connect(sigc::mem_fun(*this, &QueryDialog::on_indexCheckbutton_toggled), false);
70 }
71
~QueryDialog()72 QueryDialog::~QueryDialog()
73 {
74 }
75
setQueryProperties(const QueryProperties & properties)76 void QueryDialog::setQueryProperties(const QueryProperties &properties)
77 {
78 m_name = properties.getName();
79 m_properties = properties;
80 #ifdef DEBUG
81 clog << "QueryDialog::setQueryProperties: editing " << m_properties.getName() << endl;
82 #endif
83
84 // Name
85 if (m_name.empty() == true)
86 {
87 nameEntry->set_text("");
88 queryOkButton->set_sensitive(false);
89 }
90 else
91 {
92 nameEntry->set_text(m_name);
93 }
94 // Query text
95 RefPtr<TextBuffer> refBuffer = queryTextview->get_buffer();
96 if (refBuffer)
97 {
98 refBuffer->set_text(m_properties.getFreeQuery());
99 }
100 // Maximum number of results
101 resultsCountSpinbutton->set_value((double)m_properties.getMaximumResultsCount());
102 // Index results
103 QueryProperties::IndexWhat indexResults = m_properties.getIndexResults();
104 if (indexResults == QueryProperties::NEW_RESULTS)
105 {
106 indexCheckbutton->set_active(true);
107 indexNewCheckbutton->set_active(true);
108 }
109 else if (indexResults == QueryProperties::ALL_RESULTS)
110 {
111 indexCheckbutton->set_active(true);
112 indexNewCheckbutton->set_active(false);
113 }
114 else
115 {
116 indexCheckbutton->set_active(false);
117 indexNewCheckbutton->set_active(false);
118 indexNewCheckbutton->set_sensitive(false);
119 }
120
121 // Populate
122 populate_comboboxes();
123 }
124
is_separator(const RefPtr<TreeModel> & model,const TreeModel::iterator & iter)125 bool QueryDialog::is_separator(const RefPtr<TreeModel>& model, const TreeModel::iterator& iter)
126 {
127 if (iter)
128 {
129 const TreeModel::Path queryPath = model->get_path(iter);
130 string rowPath(from_utf8(queryPath.to_string()));
131 unsigned int rowPos = 0;
132
133 // FIXME: this is extremely hacky !
134 if ((sscanf(rowPath.c_str(), "%u", &rowPos) == 1) &&
135 (rowPos == 12))
136 {
137 return true;
138 }
139 }
140
141 return false;
142 }
143
populate_comboboxes()144 void QueryDialog::populate_comboboxes()
145 {
146 unsigned int labelNum = 1;
147
148 // All supported filters
149 filterCombobox->set_row_separator_func(sigc::mem_fun(*this, &QueryDialog::is_separator));
150 filterCombobox->append(_("Host name"));
151 filterCombobox->append(_("File name"));
152 filterCombobox->append(_("File extension"));
153 filterCombobox->append(_("Title"));
154 filterCombobox->append(_("URL"));
155 filterCombobox->append(_("Directory"));
156 filterCombobox->append(_("In URL"));
157 filterCombobox->append(_("Path"));
158 filterCombobox->append(_("Language code"));
159 filterCombobox->append(_("MIME type"));
160 filterCombobox->append(_("MIME class"));
161 filterCombobox->append(_("Label"));
162 // And separate numerical ranges
163 filterCombobox->append("===");
164 filterCombobox->append(_("Date"));
165 filterCombobox->append(_("Time"));
166 filterCombobox->append(_("Size"));
167 filterCombobox->set_active(0);
168
169 // Sort order
170 sortOrderCombobox->append(_("By relevance"));
171 sortOrderCombobox->append(_("By date"));
172 sortOrderCombobox->append(_("By size"));
173 if (m_properties.getSortOrder() == QueryProperties::DATE_DESC)
174 {
175 sortOrderCombobox->set_active(1);
176 }
177 else if (m_properties.getSortOrder() == QueryProperties::SIZE_DESC)
178 {
179 sortOrderCombobox->set_active(2);
180 }
181 else
182 {
183 sortOrderCombobox->set_active(0);
184 }
185
186 // Stemming language
187 stemmingCombobox->append(_("None"));
188 stemmingCombobox->set_active(0);
189 string language(m_properties.getStemmingLanguage());
190 for (unsigned int languageNum = 1; languageNum < Languages::m_count; ++languageNum)
191 {
192 ustring languageName(Languages::getIntlName(languageNum));
193
194 stemmingCombobox->append(languageName);
195 // Is this the language we are looking for ?
196 if (language == languageName)
197 {
198 stemmingCombobox->set_active(languageNum);
199 }
200 }
201
202 // Labels
203 labelNameCombobox->append(_("None"));
204 labelNameCombobox->set_active(0);
205 // Add all labels to the label combo and select the one defined for the query
206 set<string> &labels = PinotSettings::getInstance().m_labels;
207 for (set<string>::const_iterator labelIter = labels.begin(); labelIter != labels.end(); ++labelIter)
208 {
209 string labelName(*labelIter);
210
211 labelNameCombobox->append(to_utf8(labelName));
212 if (labelName == m_properties.getLabelName())
213 {
214 labelNameCombobox->set_active(labelNum);
215 }
216
217 ++labelNum;
218 }
219 }
220
getQueryProperties(void) const221 const QueryProperties &QueryDialog::getQueryProperties(void) const
222 {
223 return m_properties;
224 }
225
badName(void) const226 bool QueryDialog::badName(void) const
227 {
228 return m_badName;
229 }
230
on_queryCancelButton_clicked()231 void QueryDialog::on_queryCancelButton_clicked()
232 {
233 #ifdef DEBUG
234 clog << "QueryDialog::on_queryCancelButton_clicked: called" << endl;
235 #endif
236 close();
237 }
238
on_queryOkButton_clicked()239 void QueryDialog::on_queryOkButton_clicked()
240 {
241 ustring newName(nameEntry->get_text());
242 #ifdef DEBUG
243 clog << "QueryDialog::on_queryOkButton_clicked: called" << endl;
244 #endif
245
246 // Name
247 m_properties.setName(newName);
248 m_badName = false;
249 // Did the name change ?
250 if (m_name != newName)
251 {
252 const std::map<string, QueryProperties> &queries = PinotSettings::getInstance().getQueries();
253
254 // Is it already used ?
255 std::map<string, QueryProperties>::const_iterator queryIter = queries.find(newName);
256 if (queryIter != queries.end())
257 {
258 // Yes, it is
259 m_badName = true;
260 #ifdef DEBUG
261 clog << "QueryDialog::on_queryOkButton_clicked: name in use" << endl;
262 #endif
263 }
264 }
265
266 // Query text
267 RefPtr<TextBuffer> refBuffer = queryTextview->get_buffer();
268 if (refBuffer)
269 {
270 m_properties.setFreeQuery(refBuffer->get_text());
271 }
272 // Maximum number of results
273 m_properties.setMaximumResultsCount((unsigned int)resultsCountSpinbutton->get_value());
274 // Sort order
275 if (sortOrderCombobox->get_active_row_number() == 1)
276 {
277 m_properties.setSortOrder(QueryProperties::DATE_DESC);
278 }
279 else if (sortOrderCombobox->get_active_row_number() == 2)
280 {
281 m_properties.setSortOrder(QueryProperties::SIZE_DESC);
282 }
283 else
284 {
285 m_properties.setSortOrder(QueryProperties::RELEVANCE);
286 }
287 // Stemming language
288 string languageName(from_utf8(stemmingCombobox->get_active_text()));
289 int chosenLanguagePos = stemmingCombobox->get_active_row_number();
290 if (chosenLanguagePos == 0)
291 {
292 languageName.clear();
293 }
294 m_properties.setStemmingLanguage(languageName);
295 // Index results
296 bool indexResults = indexCheckbutton->get_active();
297 bool indexNewResults = indexNewCheckbutton->get_active();
298 if ((indexResults == true) &&
299 (indexNewResults == true))
300 {
301 m_properties.setIndexResults(QueryProperties::NEW_RESULTS);
302 }
303 else if ((indexResults == true) &&
304 (indexNewResults == false))
305 {
306 m_properties.setIndexResults(QueryProperties::ALL_RESULTS);
307 }
308 else
309 {
310 m_properties.setIndexResults(QueryProperties::NOTHING);
311 }
312
313 // Index label
314 m_properties.setLabelName("");
315 int chosenLabel = labelNameCombobox->get_active_row_number();
316 if (chosenLabel > 0)
317 {
318 m_properties.setLabelName(from_utf8(labelNameCombobox->get_active_text()));
319 }
320
321 close();
322 }
323
on_nameEntry_changed()324 void QueryDialog::on_nameEntry_changed()
325 {
326 ustring name = nameEntry->get_text();
327 if (name.empty() == false)
328 {
329 queryOkButton->set_sensitive(true);
330 }
331 else
332 {
333 queryOkButton->set_sensitive(false);
334 }
335 }
336
on_addFilterButton_clicked()337 void QueryDialog::on_addFilterButton_clicked()
338 {
339 ustring filter;
340 time_t timeT = time(NULL);
341 struct tm *tm = localtime(&timeT);
342
343 // What's the corresponding filter ?
344 int chosenFilter = filterCombobox->get_active_row_number();
345 // FIXME: should the filters be localized ?
346 switch (chosenFilter)
347 {
348 case 0:
349 filter = "site:localhost";
350 break;
351 case 1:
352 filter = "file:xxx.txt";
353 break;
354 case 2:
355 filter = "ext:txt";
356 break;
357 case 3:
358 filter = "title:pinot";
359 break;
360 case 4:
361 filter = "url:file:///home/xxx/yyy.txt";
362 break;
363 case 5:
364 filter = "dir:/home/xxx";
365 break;
366 case 6:
367 filter = "inurl:file:///home/xxx/yyy.tar.gz";
368 break;
369 case 7:
370 filter = "path:Documents";
371 break;
372 case 8:
373 filter = "lang:en";
374 break;
375 case 9:
376 filter = "type:text/plain";
377 break;
378 case 10:
379 filter = "class:text";
380 break;
381 case 11:
382 filter = "label:New";
383 break;
384 case 12:
385 // Separator
386 break;
387 case 13:
388 filter = TimeConverter::toYYYYMMDDString(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
389 filter += "..20991231";
390 break;
391 case 14:
392 filter = TimeConverter::toHHMMSSString(tm->tm_hour, tm->tm_min, tm->tm_sec);
393 filter += "..235959";
394 break;
395 case 15:
396 filter += "0..10240b";
397 break;
398 default:
399 break;
400 }
401
402 RefPtr<TextBuffer> refBuffer = queryTextview->get_buffer();
403 if (refBuffer)
404 {
405 ustring queryText = refBuffer->get_text();
406 queryText += " ";
407 queryText += filter;
408 refBuffer->set_text(queryText);
409 }
410 }
411
on_indexCheckbutton_toggled()412 void QueryDialog::on_indexCheckbutton_toggled()
413 {
414 if (indexCheckbutton->get_active() == false)
415 {
416 indexNewCheckbutton->set_active(false);
417 indexNewCheckbutton->set_sensitive(false);
418 }
419 else
420 {
421 indexNewCheckbutton->set_sensitive(true);
422 }
423 }
424
425