2 Copyright 2013 Karel Matas
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 3 of the License, or
7 (at your option) any later version.
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.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * Contains App - the main class of the application.
30 #include "datatypes.hxx"
32 #include "romanization.hxx"
34 #include "sqlite3.hxx"
36 #include "parsers.hxx"
37 #include "gui_dicview.hxx"
38 #include "gui_kanjiview.hxx"
54 enum KANJI_SORT_MODE
{
63 * One item (line) in listview (dictionary results).
64 * \sa cb_filter_listview()
69 // vector<string> flags;
73 DicViewItem( int id
, const set
<string
> &p
, const string
&r
,
74 const string
&k
, const string
&s
)
75 : did(id
), pos(p
), reading(r
), kanji(k
), sense(s
) {};
81 * Main class of the program. <b>Singleton</b>. Manages database, logger,
82 * config and UI. Provides functions for UI's callbacks.
83 * \note This should be only class to call query()
84 * \todo when calling ui_* functions check whether the ui_ pointer is valid
89 class SQLite3::SQLite3
*db_
;
90 class Romanization
*rmn_
;
91 class aoi_ui::GUI
*ui_
;
92 class aoi_config::Config
*cfg_
;
94 vector
<DicViewItem
> listview_items_
;
95 map
<string
,int> components_
; //!< component: stroke_count
96 std::multimap
<int,string
> curr_components_
; //!< frequency:component
99 App
& operator=(App
const&) = delete;
100 static App
* instance_
;
103 * Returns part of the SQL query for DicView.
104 * \param id database id (did) of the searched word
105 * \sa parse_dic_input()
107 inline string
q_reading ( const string
&id
="")
109 string s1
= id
.empty() ? "":"(select ";
110 string s2
= id
.empty() ? "":(" from d_reading where d_reading.did="+id
+") ");
111 return s1
+ "group_concat("\
112 "(case freq when 1 then '<reading_freq>'||reading||'</reading_freq>' "\
113 "else '<reading>'||reading||'</reading>' end)||"\
114 "'<rinf>'||inf||'</rinf>',"\
115 "\"<br/>\")" + s2
+ "as reading, ";
119 * Returns part of the SQL query for DicView.
120 * \param id database id (did) of the searched word
121 * \sa parse_dic_input()
123 inline string
q_kanji ( const string
&id
="" )
125 string s1
= id
.empty() ? "":"(select ";
126 string s2
= id
.empty() ? "":(" from d_kanji where d_kanji.did="+id
+") ");
127 return s1
+ "group_concat("\
128 "(case freq when 1 then '<kanji_freq>'||kanji||'</kanji_freq>' "\
129 "else '<kanji>'||kanji||'</kanji>' end)||"\
130 "'<kinf>'||inf||'</kinf>',"\
131 "\"<br/>\")" + s2
+ "as kanji, ";
135 * Returns part of the SQL query for DicView.
136 * \param id database id (did) of the searched word
137 * \sa parse_dic_input()
139 inline string
q_sense ( const string
&id
="" )
141 string s1
= id
.empty() ? "":"(select ";
142 string s2
= id
.empty() ? "":(" from d_sense where d_sense.did="+id
+") ");
143 return s1
+ "group_concat("\
144 "(case pos when '' then '' else '<pos>'||pos||'</pos>' end)||"\
145 "(case misc when '' then '' else '<misc>'||misc||'</misc>' end)||"\
147 "(case field when '' then '' else '<field>'||field||'</field>' end)||"\
148 "(case dial when '' then '' else '<dial>'||dial||'</dial>' end),"\
149 "'<sep/>') " + s2
+ " as sense ";
155 //! Returns instance of App.
156 static inline App
*get (){
158 instance_
= new App();
162 //! Returns pointer to Romanization.
163 inline Romanization
*rmn () const { return rmn_
; };
165 //! Opens the main database and attach the user database.
166 void open_database ();
169 inline void log ( const string
&s
) { logger_
.msg(s
); };
171 inline void log_e ( const string
&s
) { logger_
.msg(s
,Logger::MSG_ERROR
); };
173 inline void log_w ( const string
&s
) { logger_
.msg(s
,Logger::MSG_WARNING
); };
174 //! Log debug message.
175 inline void log_d ( const string
&s
) { logger_
.msg(s
,Logger::MSG_DEBUG
); };
177 inline void log ( const std::stringstream
&s
) { logger_
.msg(s
); };
179 inline void log_e ( const std::stringstream
&s
)
180 { logger_
.msg(s
,Logger::MSG_ERROR
); };
182 inline void log_w ( const std::stringstream
&s
)
183 { logger_
.msg(s
,Logger::MSG_WARNING
); };
184 //! Log debug message.
185 inline void log_d ( const std::stringstream
&s
)
186 { logger_
.msg(s
,Logger::MSG_DEBUG
); };
188 //! Returns pointer to UI.
189 inline aoi_ui::GUI
*ui() const { return ui_
; };
191 //! Call UI::run(), which calls Fl::run()
192 int run ( int argc
, char **argv
);
195 * Performs database query q.
196 * \param q SQLite query
197 * \param log_query true: q will be logged as debug message
198 * \param replace_separator true: parsers::SEPARATOR_SQL ('|')
199 * will be replaced by ", "
200 * \sa SQLite3::query()
201 * \returns data in same format as SQLite3::query()
203 vector
<string
> query ( const char *q
, bool log_query
=true,
204 bool replace_separator
= true );
206 //! Gets one kanji from database.
207 Kanji
db_get_kanji ( const string
&kanji
);
209 //! Gets one word(record) from database
210 DicWord
db_get_word( int did
);
212 //! Returns whole config as map.
213 inline std::map
<string
,aoi_config::Config::Value
> get_config_map ()
214 { return cfg_
->get_map(); };
215 //! Returns default config map.
216 inline std::map
<string
,aoi_config::Config::Value
> get_config_map_default ()
217 { return cfg_
->get_default_map(); };
219 * Sets one key=value config pair.
222 inline void set_config ( const string
&key
, const string
&val
)
223 { cfg_
->set( key
, val
); };
226 * Overrides one config option. Overidden option cant be changed until restart
228 * \sa Config::set_override()
230 inline void config_override ( const string
&key
, const string
&val
) {
232 cfg_
->set_override(key
,val
);
234 catch ( const std::exception
&e
) {
235 log_e("Unknown config: " + key
);
240 * Load color from database (string 0xRRGGBB00) and converts it to Fl_Color
243 inline Fl_Color
get_color ( const string
&color
){
244 string s
= cfg_
->get
<string
>("color/"+color
);
245 std::stringstream ss
;
246 ss
<< std::hex
<< s
.substr(2);
253 * Applies config - sets colors, loglevel, fonts, ... Redraws UI.
256 void apply_config ();
258 * Gets one config item
259 * \exception std::runtime_error when key does not exist
261 template<class T
=string
> inline T
get_config( const string
&s
)
262 { return cfg_
->get
<T
>(s
); }
264 * Writes current config to database. Calls set_config() for each
265 * item in config map. After that calls init_dicview()
266 * \sa get_config_map()
269 * \todo check new keys
271 void save_config ( const std::map
<string
,aoi_config::Config::Value
> &newmap
={});
274 * Loads config from database.
275 * \todo Compare loaded and default config. Drop keys which exists in loaded
276 * but dont in default (i.e. keys from previous versions).
281 * Initializes and sets styles in DicView.
284 * \sa GUI::register_tag_dicview()
286 void init_dicview ();
288 //! Shows alert/error window.
289 void alert ( const string
&msg
, const string
&desc
="" );
292 * Checks tables in database. Creates missing.
293 * \sa aoi_config::db_tables
295 void check_tables ();
297 * Checks indexes in database. Creates missing indexes and runs
298 * VACUUM if neccessary.
299 * \sa aoi_config::db_tables
301 void check_indexes ();
304 * Loads database stored as SQLite script. File may be GZipped.
306 void load_dbscript ( const char *fname
);
307 inline void load_dbscript ( const string
&fname
){ load_dbscript(fname
.c_str());};
310 * Calls input parser. Resets GUI (pos chekboxes).
312 void cb_dic_input ();
314 // void on_dic_selected ( int id );
317 * Shows dialog which allows editing of the currently selected word
318 * (i.e. row in DicView)
320 void cb_edit_word ();
323 * Parses the content of dic_input_, builds and performs the query
325 * \see DictionaryInputParser
326 * \see q_sense(), q_reading(), q_kanji()
328 void parse_dic_input ( const char *str
);
331 * Gets kanji from database and calls GUI::popup_kanji()
333 void cb_popup_kanji ( const string
&kanji
);
334 void cb_kanji_search ();
337 * Sets contents of the listview and listview_items_.
338 * \parameter v preformatted text (output from query()) to be used
342 void set_listview ( const vector
<string
> &v
);
345 * Shows a context menu that contains kanji which appears in the selected
346 * word and items: Examples, Notes and Edit word.
347 * \see GUI::dicview_menu()
349 void cb_dicview_rightclick ( int did
);
352 * Shows a dialog with example sentences. Sentances marked as good example
353 * for the word are displayed first and in the color.
358 * Shows a dialog that allows managing the DB and downloading one.
360 void cb_manage_db ();
363 * Filters visible rows in the listview according to selected checkboxes.
365 void cb_filter_listview ();
368 * Builds a histogram of the components in currently visible kanjis and
369 * sets the content of ComponentView.
371 void cb_set_components ();
374 * Downloads prebuilt (gzipped) database from aoi.souko.cz.
376 void cb_download_db();
379 * Used as callback for download button in aoi_ui::ManageDBDialog::cb_download()
380 * \see cb_manage_db() (here it is set as callback)
381 * \see cb_download_db()
383 inline static void scb_download_db ( Fl_Widget
*w
, void *p
)
384 { ((App
*)p
)->cb_download_db(); }
385 //! See cb_examples()
386 inline static void scb_examples ( Fl_Widget
*w
, void *p
)
387 { ((App
*)p
)->cb_examples(); }
388 //! See cb_dic_input()
389 inline static void scb_dic_input ( Fl_Widget
*w
, void *p
)
390 { ((App
*)p
)->cb_dic_input(); }
391 //! See cb_filter_listview()
392 inline static void scb_filter_listview ( Fl_Widget
*w
, void *p
)
393 { ((App
*)p
)->cb_filter_listview(); }
394 //! See cb_manage_db()
395 inline static void scb_manage_db ( Fl_Widget
*w
, void *p
)
396 { ((App
*)p
)->cb_manage_db(); }
397 //! See cb_kanji_search()
398 inline static void scb_kanji_search ( Fl_Widget
*w
, void *p
)
399 { ((App
*)p
)->cb_kanji_search(); }
402 * \todo siplify and unite with GUI::popup_kanji
403 * \todo change to direct kanjisearch
405 inline static void scb_kanjiview_select ( Fl_Widget
*w
, void *p
){
406 aoi_ui::KanjiView
*v
= (aoi_ui::KanjiView
*)w
;
407 aoi_ui::KanjiView::Cell
*c
= v
->selected();
409 ((App
*)p
)->cb_popup_kanji( c
->str
);
410 // copy to selection buffer (middle mouse)
411 Fl::copy(c
->str
.c_str(), strlen(c
->str
.c_str()), 0);
415 * Static callback for doubleclick in dicview.
416 * \see cb_edit_word()
418 inline static void scb_dicview_doubleclick ( Fl_Widget
*w
, void *p
){
419 ((App
*)p
)->cb_edit_word(); }
421 * \see cb_edit_word()
423 inline static void scb_edit_word ( Fl_Widget
*w
, void *p
){
424 ((App
*)p
)->cb_edit_word(); }
427 * Calls back DicViews' callback for rightclick.
428 * \todo simplify, clarify
430 inline static void scb_dicview_rightclick ( Fl_Widget
*w
, void *p
){
431 aoi_ui::DicView
*v
= (aoi_ui::DicView
*)w
;
432 ((App
*)p
)->cb_dicview_rightclick( v
->selected_row_id() );
434 //! See cb_set_components()
435 inline static void scb_set_components ( Fl_Widget
*w
, void *p
)
436 { ((App
*)p
)->cb_set_components(); }
441 * Parses string in the dictionary's input fiels.
442 * Breaks the input string into the parts ( parts_ ) and build query.
443 * Part = content of one {}, [] or ().
444 * \see App:parse_dic_input()
446 class DictionaryInputParser
449 enum PartType
{ STRING
, WORD
, KANJI
};
451 vector
<std::pair
<string
,PartType
>> parts_
;
452 std::stringstream buffer_
;
453 PartType type_
= STRING
;
454 bool warning_
= false;
457 * Adds content of the buffer_ to parts_ and sets its type (called after
458 * encountering the start of a new part or end of string).
462 if ( buffer_
.str().empty() ) return;
463 parts_
.push_back( { buffer_
.str(), type_
} );
468 * Performs a kanji query, extracts all kanji from the result to the new set
469 * and intersects it with the set <i>current</i>. Called by find_kanji().
470 * \returns result of the intersection
472 set
<string
> intersection ( const string
&query
, const set
<string
> ¤t
);
475 DictionaryInputParser(){};
476 ~DictionaryInputParser(){};
479 * Returns whether the caller should display a warning about too broad search.
480 * \see check_warning(), Config::"dic/input_parser_warning"
482 inline bool warning () const { return warning_
; };
485 * Parses the text in [] or (). Does some db queries (based on SKIP,
486 * reading of the word or on/kun).
487 * \param from_words If true then [] else ().
489 * \returns string consisting from all the matching kanji
491 string
find_kanji ( const string
&s
, bool from_words
=true );
494 * Checks whether the flag warning_ should be set.
497 void check_warning ( const string
&s
, const string
&previous
);
500 * Splits the input string into parts, identifies their types and
501 * \return list of matching kanji in the curly brackets (GLOB like)
503 string
parse ( const char *s
);