Renamed kpengine to jben_kpengine and made its data dir relocatable.
[jben.git] / frame_maingui.cpp
blobe4bbd3825b48adb3757decfe36e8366e3e4fd59d
1 /*
2 Project: J-Ben
3 Author: Paul Goins
4 Website: http://www.vultaire.net/software/jben/
5 License: GNU General Public License (GPL) version 2
6 (http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt)
8 File: maingui.cpp
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>
24 #include "frame_maingui.h"
25 #include "jben.h"
26 #include "version.h"
27 #include "wx/msgdlg.h"
28 #include "file_utils.h"
29 #include "wx/ffile.h"
30 #include "frame_kanjipad.h"
31 #include "encoding_convert.h"
33 #ifndef __WXMSW__
34 #include "jben.xpm"
35 #endif
37 enum {
38 ID_menuFileQuit=wxID_EXIT,
39 ID_menuHelpAbout=wxID_ABOUT,
41 ID_menuKanjiAddFromFile=1,
42 ID_menuKanjiAddByGrade,
43 ID_menuKanjiAddByFreq,
44 ID_menuKanjiSaveToFile,
45 ID_menuKanjiClearList,
46 #ifdef DEBUG
47 ID_menuKanjiDumpList,
48 #endif
49 ID_menuKanjiSortByGrade,
50 ID_menuKanjiSortByFreq,
51 ID_menuKanjiSearchKanjiPad,
52 ID_menuHelpLicense,
53 ID_tabsMain,
54 ID_tabsKanji,
55 ID_tabsWords,
56 ID_tabsConfig
59 BEGIN_EVENT_TABLE(FrameMainGUI, wxFrame)
60 EVT_CLOSE(FrameMainGUI::OnClose)
62 EVT_MENU(ID_menuFileQuit, FrameMainGUI::OnFileQuit)
64 EVT_MENU(ID_menuKanjiAddFromFile, FrameMainGUI::OnKanjiAddFromFile)
65 EVT_MENU(ID_menuKanjiAddByGrade, FrameMainGUI::OnKanjiAddByGrade)
66 EVT_MENU(ID_menuKanjiAddByFreq, FrameMainGUI::OnKanjiAddByFreq)
67 EVT_MENU(ID_menuKanjiSaveToFile, FrameMainGUI::OnKanjiSaveToFile)
68 EVT_MENU(ID_menuKanjiClearList, FrameMainGUI::OnKanjiClearList)
69 #ifdef DEBUG
70 EVT_MENU(ID_menuKanjiDumpList, FrameMainGUI::OnKanjiDumpList)
71 #endif
72 EVT_MENU(ID_menuKanjiSortByGrade, FrameMainGUI::OnKanjiSortByGrade)
73 EVT_MENU(ID_menuKanjiSortByFreq, FrameMainGUI::OnKanjiSortByFreq)
74 EVT_MENU(ID_menuKanjiSearchKanjiPad, FrameMainGUI::OnKanjiSearchKanjiPad)
76 EVT_MENU(ID_menuHelpAbout, FrameMainGUI::OnHelpAbout)
77 EVT_MENU(ID_menuHelpLicense, FrameMainGUI::OnHelpLicense)
79 EVT_NOTEBOOK_PAGE_CHANGING(ID_tabsMain, FrameMainGUI::OnTabChanging)
80 EVT_NOTEBOOK_PAGE_CHANGED (ID_tabsMain, FrameMainGUI::OnMajorTabChanged)
81 EVT_NOTEBOOK_PAGE_CHANGING(ID_tabsKanji, FrameMainGUI::OnTabChanging)
82 EVT_NOTEBOOK_PAGE_CHANGED (ID_tabsKanji, FrameMainGUI::OnMinorTabChanged)
83 EVT_NOTEBOOK_PAGE_CHANGING(ID_tabsWords, FrameMainGUI::OnTabChanging)
84 EVT_NOTEBOOK_PAGE_CHANGED (ID_tabsWords, FrameMainGUI::OnMinorTabChanged)
85 EVT_NOTEBOOK_PAGE_CHANGING(ID_tabsConfig, FrameMainGUI::OnTabChanging)
86 EVT_NOTEBOOK_PAGE_CHANGED (ID_tabsConfig, FrameMainGUI::OnMinorTabChanged)
88 END_EVENT_TABLE()
90 FrameMainGUI::FrameMainGUI() : wxFrame
91 ((wxFrame *)NULL, -1,
92 _T(PROGRAM_NAME " v" VERSION_STR " by " AUTHOR_NAME),
93 wxDefaultPosition, wxSize(600,400)) {
94 this->SetIcon(wxICON(iconJben));
95 wxInitAllImageHandlers(); /* This is needed for PNG support - GIFs seem to
96 load fine without it. */
98 /* Don't create these objects until/unless needed. */
99 dialogAddKanjiByFreq = NULL;
100 dialogAddKanjiByGrade = NULL;
102 wxMenuBar *menuBar;
103 wxMenu *menu, *subMenu;
104 tabMinor = NULL;
106 menuBar = new wxMenuBar;
108 menu = new wxMenu;
109 menu->Append(ID_menuFileQuit, _T("E&xit..."));
110 menuBar->Append(menu, _T("&File"));
112 /* Kanji Menu */
113 kanjiMenu = new wxMenu;
114 /* Submenu: Search for Kanji (probably a temporary menu, for now) */
115 subMenu = new wxMenu;
116 subMenu->Append(ID_menuKanjiSearchKanjiPad, _T("By &Handwriting"));
117 kanjiMenu->AppendSubMenu(subMenu, _T("&Find Kanji"));
118 /* Submenu: Add Kanji to List */
119 subMenu = new wxMenu;
120 subMenu->Append(ID_menuKanjiAddFromFile, _T("&From File..."));
121 subMenu->Append(ID_menuKanjiAddByGrade, _T("By Jouyou &Grade Level..."));
122 subMenu->Append(ID_menuKanjiAddByFreq,
123 _T("By Newspaper F&requency Ranking..."));
124 kanjiMenu->AppendSubMenu(subMenu, _T("&Add Kanji to List"));
125 /* Submenu: Sort Kanji in List*/
126 subMenu = new wxMenu;
127 subMenu->Append(ID_menuKanjiSortByGrade, _T("By Jouyou &Grade Level"));
128 subMenu->Append(ID_menuKanjiSortByFreq,
129 _T("By Newspaper F&requency Ranking"));
130 kanjiMenu->AppendSubMenu(subMenu, _T("S&ort Kanji in List"));
131 /* Other Kanji Menu options */
132 kanjiMenu->Append(ID_menuKanjiSaveToFile,
133 _T("&Save Kanji List to File..."));
134 if(jben->kanjiList->Size()==0)
135 kanjiMenu->Enable(ID_menuKanjiSaveToFile, false);
136 kanjiMenu->AppendSeparator();
137 kanjiMenu->Append(ID_menuKanjiClearList,
138 _T("&Clear Kanji List"));
139 if(jben->kanjiList->Size()==0)
140 kanjiMenu->Enable(ID_menuKanjiClearList, false);
141 #ifdef DEBUG
142 kanjiMenu->Append(ID_menuKanjiDumpList, _T("&Dump Kanji List to Console"));
143 #endif
144 menuBar->Append(kanjiMenu, _T("&Kanji"));
146 menu = new wxMenu;
147 menu->Append(ID_menuHelpAbout, _T("&About..."));
148 menu->Append(ID_menuHelpLicense, _T("&License Information..."));
149 menuBar->Append(menu, _T("&Help"));
151 SetMenuBar(menuBar);
153 tabsMain = new wxNotebook(this,
154 ID_tabsMain,wxDefaultPosition,
155 wxDefaultSize,wxCLIP_CHILDREN | wxNB_TOP);
156 #ifdef __WXMSW__
157 tabsKanji = new wxNotebook(tabsMain,
158 ID_tabsKanji,wxDefaultPosition,
159 wxDefaultSize,wxCLIP_CHILDREN | wxNB_TOP);
160 tabsWords = new wxNotebook(tabsMain,
161 ID_tabsWords,wxDefaultPosition,
162 wxDefaultSize,wxCLIP_CHILDREN | wxNB_TOP);
163 tabsConfig = new wxNotebook(tabsMain,
164 ID_tabsConfig,wxDefaultPosition,
165 wxDefaultSize,wxCLIP_CHILDREN | wxNB_TOP);
166 #else
167 tabsKanji = new wxNotebook(tabsMain,
168 ID_tabsKanji,wxDefaultPosition,
169 wxDefaultSize,wxCLIP_CHILDREN | wxNB_LEFT);
170 tabsWords = new wxNotebook(tabsMain,
171 ID_tabsWords,wxDefaultPosition,
172 wxDefaultSize,wxCLIP_CHILDREN | wxNB_LEFT);
173 tabsConfig = new wxNotebook(tabsMain,
174 ID_tabsConfig,wxDefaultPosition,
175 wxDefaultSize,wxCLIP_CHILDREN | wxNB_LEFT);
176 #endif
177 tabsMain->AddPage(tabsKanji,_T("Kanji"),true);
178 tabsMain->AddPage(tabsWords,_T("Words"),false);
179 tabsMain->AddPage(tabsConfig,_T("Configuration"),false);
180 tabMajor = (wxNotebookPage *) tabsKanji;
182 panelKanjiDict = new PanelKanjiDict(tabsKanji);
183 panelKanjiDrill = new PanelKanjiDrill(tabsKanji);
184 panelKanjiListEditor = new PanelKanjiListEditor(tabsKanji);
185 tabsKanji->AddPage(panelKanjiDict,_T("Dictionary"),true);
186 tabsKanji->AddPage(panelKanjiDrill,_T("Practice"),false);
187 tabsKanji->AddPage(panelKanjiListEditor,_T("Study List"),false);
188 tabMinor = (wxNotebookPage *) panelKanjiDict;
190 panelWordDict = new PanelWordDict(tabsWords);
191 /* ADVANCED IDEA: Use radical database to create a multi-choice test option
192 for vocab and kanji. That is, like on the JLPT for reading/writing
193 Kanji, use kanji which share one or more radicals or readings as
194 alternate options when possible. (Without this, panelVocabTest seems
195 somewhat pointless at this time.) */
196 panelVocabListEditor = new PanelVocabListEditor(tabsWords);
197 tabsWords->AddPage(panelWordDict,_T("Dictionary"),true);
198 tabsWords->AddPage(panelVocabListEditor,_T("Study List"),false);
200 panelConfig = new PanelConfig(tabsConfig);
201 tabsConfig->AddPage(panelConfig,_T("Main Options"),true);
204 void FrameMainGUI::OnFileQuit(wxCommandEvent& event) {
205 Close();
208 void FrameMainGUI::OnKanjiAddFromFile(wxCommandEvent& event) {
209 /* NOTE: We may add the flag wxFD_CHANGE_DIR later, if we add in code
210 to save the full path for the jben.cfg file. */
211 wxFileDialog *fd = new wxFileDialog(
212 this, _T("Open File"), wxEmptyString, wxEmptyString, _T("*"),
213 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE);
214 if(fd->ShowModal()==wxID_OK) {
215 wxArrayString filenames;
216 wstring file, allFiles;
217 fd->GetPaths(filenames);
218 for(unsigned int i=0;i<filenames.Count();i++) {
219 if(ReadEncodedFile(
220 utfconv_wm(filenames[i].c_str()).c_str(),
221 file)==REF_SUCCESS)
222 allFiles.append(file);
224 int result = jben->kanjiList->AddFromString(allFiles);
225 this->Redraw();
226 wxMessageBox(wxString::Format(
227 _T("Added %d kanji to the list."), result),
228 _T("Add Kanji From File"), wxOK | wxICON_INFORMATION, this);
230 fd->Destroy();
233 void FrameMainGUI::OnKanjiAddByGrade(wxCommandEvent& event) {
234 if(!dialogAddKanjiByGrade)
235 dialogAddKanjiByGrade = new DialogAddKanjiByGrade(this);
236 int result = dialogAddKanjiByGrade->ShowModal();
237 if(result==wxID_OK) {
238 /*printf("Selected grades: %d to %d\n",
239 dialogAddKanjiByGrade->GetLowGrade(),
240 dialogAddKanjiByGrade->GetHighGrade()
241 );*/
242 result = jben->kanjiList->AddByGrade(
243 dialogAddKanjiByGrade->GetLowGrade(),
244 dialogAddKanjiByGrade->GetHighGrade());
245 this->Redraw();
246 wxMessageBox(wxString::Format(
247 _T("Added %d kanji to the list."), result),
248 _T("Add Kanji by Jouyou Grade"), wxOK | wxICON_INFORMATION, this);
249 } else if(result==wxID_CANCEL) {
250 /*printf("Cancel event occurred within dialog!\n");*/
252 #ifdef DEBUG
253 else printf("Unknown key (%08X) pressed within dialog!\n", result);
254 #endif
257 void FrameMainGUI::OnKanjiAddByFreq(wxCommandEvent& event) {
258 if(!dialogAddKanjiByFreq)
259 dialogAddKanjiByFreq = new DialogAddKanjiByFreq(this);
260 int result = dialogAddKanjiByFreq->ShowModal();
261 if(result==wxID_OK) {
262 /*printf("Selected frequencies: %d to %d\n",
263 dialogAddKanjiByFreq->GetLowFreq(),
264 dialogAddKanjiByFreq->GetHighFreq()
265 );*/
266 result = jben->kanjiList->AddByFrequency(
267 dialogAddKanjiByFreq->GetLowFreq(),
268 dialogAddKanjiByFreq->GetHighFreq());
269 this->Redraw();
270 wxMessageBox(wxString::Format(
271 _T("Added %d kanji to the list."), result),
272 _T("Add Kanji by Frequency"), wxOK | wxICON_INFORMATION, this);
273 } else if(result==wxID_CANCEL) {
274 /* Do nothing */
276 #ifdef DEBUG
277 else printf("Unknown key (%08X) pressed within dialog!\n", result);
278 #endif
281 void FrameMainGUI::OnKanjiSaveToFile(wxCommandEvent& event) {
282 /* NOTE: We may add the flag wxFD_CHANGE_DIR later, if we add in code
283 to save the full path for the jben.cfg file. */
284 wxFileDialog *fd = new wxFileDialog(
285 this, _T("Save Kanji List to File"), wxEmptyString, wxEmptyString,
286 _T("*"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
287 if(fd->ShowModal()==wxID_OK) {
288 wxString kanjiList = jben->kanjiList->ToString(20);
289 wxString filename = fd->GetPath();
290 /* Open file/write to file/close file */ /* TO DO */
291 wxFFile f(filename, _T("w"));
292 if(f.IsOpened()) {
293 f.Write(kanjiList, *wxConvCurrent);
294 f.Close();
297 fd->Destroy();
300 void FrameMainGUI::OnKanjiClearList(wxCommandEvent& event) {
301 jben->kanjiList->Clear();
302 this->Redraw();
305 #ifdef DEBUG
306 void FrameMainGUI::OnKanjiDumpList(wxCommandEvent& event) {
307 printf("Current kanji list: %ls\n", jben->kanjiList->ToString().c_str());
309 #endif
311 void FrameMainGUI::OnHelpAbout(wxCommandEvent& event) {
312 wxMessageBox(_T(
313 PROGRAM_NAME " v" VERSION_STR
314 "\nBy " AUTHOR_NAME
315 "\nCopyright " COPYRIGHT_DATE "\n\n"
317 "Inspired in large by JWPce and JFC by Glenn Rosenthal:\n"
318 "http://www.physics.ucla.edu/~grosenth/\n\n"
320 "Powered by Monash University's EDICT2 and KANJIDIC:\n"
321 "http://www.csse.monash.edu.au/~jwb/edict_doc.html\n"
322 "http://www.csse.monash.edu.au/~jwb/kanjidic.html\n\n"
324 "Built using wxWidgets: http://www.wxwidgets.org/\n\n"
326 "Hand writing recognition is based upon code from im-ja:\n"
327 "http://im-ja.sourceforge.net/\n"
328 "Which uses code based upon KanjiPad by Owen Taylor:\n"
329 "http://fishsoup.net/software/kanjipad/\n\n"
331 "See \"Help->License Information...\" for important license details."),
332 _T("About " PROGRAM_NAME), wxOK | wxICON_INFORMATION, this);
335 void FrameMainGUI::OnHelpLicense(wxCommandEvent& event) {
336 wxMessageBox(_T(
337 "Program distributed under the GNU General Public License (GPL) version 2:\n"
338 "http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt\n\n"
339 "EDICT2 and KANJIDIC distributed under a separate license specified at\n"
340 "http://www.csse.monash.edu.au/~jwb/edrdg/license.htm\n\n"
342 "The SKIP (System of Kanji Indexing by Patterns) system for ordering kanji "
343 "was developed by Jack Halpern (Kanji Dictionary Publishing Society at "
344 "http://www.kanji.org/), and is used with his permission.\n\n"
346 "Copies of the GNU General Public License, Monash University's license for "
347 "the dictionary files and documentation for the dictionary files are "
348 "contained in this program's \"license\" directory."),
349 _T("License Information"), wxOK | wxICON_INFORMATION, this);
352 void FrameMainGUI::OnMajorTabChanged(wxNotebookEvent& event) {
353 #ifdef DEBUG
354 printf("DEBUG: OnMAJORTabChanged called.\n");
355 #endif
356 tabMajor = (wxNotebookPage *) tabsMain->GetPage(event.GetSelection());
357 tabMinor = ((wxNotebook *)tabMajor)->GetCurrentPage();
358 #ifdef DEBUG
359 printf("tabMajor = %p, tabMinor = %p\n", tabMajor, tabMinor);
360 #endif
361 this->Redraw();
364 void FrameMainGUI::OnMinorTabChanged(wxNotebookEvent& event) {
365 #ifdef DEBUG
366 printf("DEBUG: OnMinorTabChanged called.\n");
367 #endif
368 wxNotebook *nb = (wxNotebook *) tabsMain->GetCurrentPage();
369 if(nb) {
370 tabMinor = (wxNotebookPage *) nb->GetPage(event.GetSelection());
371 } else tabMinor = NULL;
372 #ifdef DEBUG
373 printf("tabMajor = %p, tabMinor = %p\n", tabMajor, tabMinor);
374 #endif
375 this->Redraw();
378 /* This is the handler code for our tab changes.
379 It's called by both OnTabChanging functions.
380 Returns true if the tab change should take place, and false if it
381 should be vetoed. */
382 bool FrameMainGUI::TabChangeHandler(wxNotebookPage *page) {
383 int result;
384 if(page == panelConfig) {
385 if(panelConfig->ChangeDetected()) {
386 result = wxMessageBox(
387 _T("You have made changes to your configuration. Do you want "
388 "to save them?"),
389 _T("Unsaved Changes Detected!"),
390 wxYES_NO | wxCANCEL | wxICON_QUESTION, this);
391 if(result==wxYES) {
392 panelConfig->Commit();
393 } else if(result==wxNO) {
394 panelConfig->Revert();
395 } else if(result==wxCANCEL) {
396 return false;
400 else if(page == panelKanjiListEditor) {
401 if(panelKanjiListEditor->ChangeDetected()) {
402 result = wxMessageBox(
403 _T("You have made changes to the kanji list. Do you want to "
404 "save them?"),
405 _T("Unsaved Changes Detected!"),
406 wxYES_NO | wxCANCEL | wxICON_QUESTION, this);
407 if(result==wxYES) {
408 panelKanjiListEditor->Commit();
409 } else if(result==wxNO) {
410 panelKanjiListEditor->Revert();
411 } else if(result==wxCANCEL) {
412 return false;
416 else if(page == panelVocabListEditor) {
417 if(panelVocabListEditor->ChangeDetected()) {
418 result = wxMessageBox(
419 _T("You have made changes to the vocab list. Do you want to "
420 "save them?"),
421 _T("Unsaved Changes Detected!"),
422 wxYES_NO | wxCANCEL | wxICON_QUESTION, this);
423 if(result==wxYES) {
424 panelVocabListEditor->Commit();
425 } else if(result==wxNO) {
426 panelVocabListEditor->Revert();
427 } else if(result==wxCANCEL) {
428 return false;
432 else if(page == panelKanjiDrill) {
433 if(panelKanjiDrill->TestInProgress()) {
434 result =
435 wxMessageBox(_T("A test is in progress. Switching tabs will "
436 "abort the test. Are you sure you want to do "
437 "this?"),
438 _T("Test in progress!"), wxYES_NO | wxICON_EXCLAMATION, this);
439 if(result==wxYES) {
440 panelKanjiDrill->Stop();
441 } else {
442 return false;
446 return true;
449 void FrameMainGUI::OnTabChanging(wxNotebookEvent& event) {
450 int index = event.GetOldSelection();
451 if(index==-1) return;
453 if(!TabChangeHandler(tabMinor)) event.Veto();
456 void FrameMainGUI::OnKanjiSortByGrade(wxCommandEvent& ev) {
457 jben->kanjiList->Sort(ST_GRADE);
458 this->Redraw();
461 void FrameMainGUI::OnKanjiSortByFreq(wxCommandEvent& ev) {
462 jben->kanjiList->Sort(ST_FREQUENCY);
463 this->Redraw();
466 void FrameMainGUI::OnKanjiSearchKanjiPad(wxCommandEvent& ev) {
467 /* Multiple instances are allowed - just spin off an instance. */
468 FrameKanjiPad *kanjiPad =
469 new FrameKanjiPad(this, -1, _T("J-Ben: KanjiPad"));
470 kanjiPad->Show();
473 void FrameMainGUI::Redraw() {
474 bool state = (jben->kanjiList->Size()>0);
475 kanjiMenu->Enable(ID_menuKanjiSaveToFile, state);
476 kanjiMenu->Enable(ID_menuKanjiClearList, state);
478 if(tabMinor) {
479 ((RedrawablePanel *)tabMinor)->Redraw();
483 void FrameMainGUI::OnClose(wxCloseEvent& event) {
484 if(!event.CanVeto()) {
485 #ifdef DEBUG
486 fprintf(stderr, "event.CanVeto() returned false!\n");
487 #endif
488 this->Destroy();
490 /* Check for active kanji drill */
491 if(tabsMain->GetCurrentPage()==panelKanjiDrill &&
492 panelKanjiDrill->TestInProgress()) {
493 int result =
494 wxMessageBox(_T("A test is in progress. Are you sure you want to "
495 "quit?"),
496 _T("Test in progress!"), wxYES_NO | wxICON_EXCLAMATION, this);
497 if(result==wxYES) {
498 panelKanjiDrill->Stop();
499 } else {
500 event.Veto();
501 return;
505 /* Everything is okay - close the program. */
506 this->Destroy();