Various changes to preferences object, file loading, and error logging.
[jben.git] / frame_maingui.cpp
blob6297e5a5f6513ca461cde92de05a74fab6ab1ce0
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 tabMajor = NULL;
105 tabMinor = NULL;
107 menuBar = new wxMenuBar;
109 menu = new wxMenu;
110 menu->Append(ID_menuFileQuit, _T("E&xit..."));
111 menuBar->Append(menu, _T("&File"));
113 /* Kanji Menu */
114 kanjiMenu = new wxMenu;
115 /* Submenu: Search for Kanji (probably a temporary menu, for now) */
116 subMenu = new wxMenu;
117 subMenu->Append(ID_menuKanjiSearchKanjiPad, _T("By &Handwriting"));
118 kanjiMenu->AppendSubMenu(subMenu, _T("&Find Kanji"));
119 /* Submenu: Add Kanji to List */
120 subMenu = new wxMenu;
121 subMenu->Append(ID_menuKanjiAddFromFile, _T("&From File..."));
122 subMenu->Append(ID_menuKanjiAddByGrade, _T("By Jouyou &Grade Level..."));
123 subMenu->Append(ID_menuKanjiAddByFreq,
124 _T("By Newspaper F&requency Ranking..."));
125 kanjiMenu->AppendSubMenu(subMenu, _T("&Add Kanji to List"));
126 /* Submenu: Sort Kanji in List*/
127 subMenu = new wxMenu;
128 subMenu->Append(ID_menuKanjiSortByGrade, _T("By Jouyou &Grade Level"));
129 subMenu->Append(ID_menuKanjiSortByFreq,
130 _T("By Newspaper F&requency Ranking"));
131 kanjiMenu->AppendSubMenu(subMenu, _T("S&ort Kanji in List"));
132 /* Other Kanji Menu options */
133 kanjiMenu->Append(ID_menuKanjiSaveToFile,
134 _T("&Save Kanji List to File..."));
135 if(jben->kanjiList->Size()==0)
136 kanjiMenu->Enable(ID_menuKanjiSaveToFile, false);
137 kanjiMenu->AppendSeparator();
138 kanjiMenu->Append(ID_menuKanjiClearList,
139 _T("&Clear Kanji List"));
140 if(jben->kanjiList->Size()==0)
141 kanjiMenu->Enable(ID_menuKanjiClearList, false);
142 #ifdef DEBUG
143 kanjiMenu->Append(ID_menuKanjiDumpList, _T("&Dump Kanji List to Console"));
144 #endif
145 menuBar->Append(kanjiMenu, _T("&Kanji"));
147 menu = new wxMenu;
148 menu->Append(ID_menuHelpAbout, _T("&About..."));
149 menu->Append(ID_menuHelpLicense, _T("&License Information..."));
150 menuBar->Append(menu, _T("&Help"));
152 SetMenuBar(menuBar);
154 tabsMain = new wxNotebook(this,
155 ID_tabsMain,wxDefaultPosition,
156 wxDefaultSize,wxCLIP_CHILDREN | wxNB_TOP);
157 #ifdef __WXMSW__
158 tabsKanji = new wxNotebook(tabsMain,
159 ID_tabsKanji,wxDefaultPosition,
160 wxDefaultSize,wxCLIP_CHILDREN | wxNB_TOP);
161 tabsWords = new wxNotebook(tabsMain,
162 ID_tabsWords,wxDefaultPosition,
163 wxDefaultSize,wxCLIP_CHILDREN | wxNB_TOP);
164 tabsConfig = new wxNotebook(tabsMain,
165 ID_tabsConfig,wxDefaultPosition,
166 wxDefaultSize,wxCLIP_CHILDREN | wxNB_TOP);
167 #else
168 tabsKanji = new wxNotebook(tabsMain,
169 ID_tabsKanji,wxDefaultPosition,
170 wxDefaultSize,wxCLIP_CHILDREN | wxNB_LEFT);
171 tabsWords = new wxNotebook(tabsMain,
172 ID_tabsWords,wxDefaultPosition,
173 wxDefaultSize,wxCLIP_CHILDREN | wxNB_LEFT);
174 tabsConfig = new wxNotebook(tabsMain,
175 ID_tabsConfig,wxDefaultPosition,
176 wxDefaultSize,wxCLIP_CHILDREN | wxNB_LEFT);
177 #endif
179 panelKanjiDict = new PanelKanjiDict(tabsKanji);
180 panelKanjiDrill = new PanelKanjiDrill(tabsKanji);
181 panelKanjiListEditor = new PanelKanjiListEditor(tabsKanji);
182 tabsKanji->AddPage(panelKanjiDict,_T("Dictionary"),true);
183 tabsKanji->AddPage(panelKanjiDrill,_T("Practice"),false);
184 tabsKanji->AddPage(panelKanjiListEditor,_T("Study List"),false);
186 panelWordDict = new PanelWordDict(tabsWords);
187 /* ADVANCED IDEA: Use radical database to create a multi-choice test option
188 for vocab and kanji. That is, like on the JLPT for reading/writing
189 Kanji, use kanji which share one or more radicals or readings as
190 alternate options when possible. (Without this, panelVocabTest seems
191 somewhat pointless at this time.) */
192 panelVocabListEditor = new PanelVocabListEditor(tabsWords);
193 tabsWords->AddPage(panelWordDict,_T("Dictionary"),true);
194 tabsWords->AddPage(panelVocabListEditor,_T("Study List"),false);
196 panelConfig = new PanelConfig(tabsConfig);
197 tabsConfig->AddPage(panelConfig,_T("Main Options"),true);
199 tabsMain->AddPage(tabsWords,_T("Words"),true);
200 tabsMain->AddPage(tabsKanji,_T("Kanji"),false);
201 tabsMain->AddPage(tabsConfig,_T("Configuration"),false);
203 tabMajor = (wxNotebookPage *) tabsWords;
204 tabMinor = (wxNotebookPage *) panelWordDict;
207 void FrameMainGUI::OnFileQuit(wxCommandEvent& event) {
208 Close();
211 void FrameMainGUI::OnKanjiAddFromFile(wxCommandEvent& event) {
212 /* NOTE: We may add the flag wxFD_CHANGE_DIR later, if we add in code
213 to save the full path for the jben.cfg file. */
214 wxFileDialog *fd = new wxFileDialog(
215 this, _T("Open File"), wxEmptyString, wxEmptyString, _T("*"),
216 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE);
217 if(fd->ShowModal()==wxID_OK) {
218 wxArrayString filenames;
219 wstring file, allFiles;
220 fd->GetPaths(filenames);
221 for(unsigned int i=0;i<filenames.Count();i++) {
222 if(ReadEncodedFile(
223 utfconv_wm(filenames[i].c_str()).c_str(),
224 file)==REF_SUCCESS)
225 allFiles.append(file);
227 int result = jben->kanjiList->AddFromString(allFiles);
228 this->Redraw();
229 wxMessageBox(wxString::Format(
230 _T("Added %d kanji to the list."), result),
231 _T("Add Kanji From File"), wxOK | wxICON_INFORMATION, this);
233 fd->Destroy();
236 void FrameMainGUI::OnKanjiAddByGrade(wxCommandEvent& event) {
237 if(!dialogAddKanjiByGrade)
238 dialogAddKanjiByGrade = new DialogAddKanjiByGrade(this);
239 int result = dialogAddKanjiByGrade->ShowModal();
240 if(result==wxID_OK) {
241 result = jben->kanjiList->AddByGrade(
242 dialogAddKanjiByGrade->GetLowGrade(),
243 dialogAddKanjiByGrade->GetHighGrade());
244 this->Redraw();
245 wxMessageBox(wxString::Format(
246 _T("Added %d kanji to the list."), result),
247 _T("Add Kanji by Jouyou Grade"), wxOK | wxICON_INFORMATION, this);
248 } else if(result==wxID_CANCEL) {
249 /* Do nothing */
251 #ifdef DEBUG
252 else printf("Unknown key (%08X) pressed within dialog!\n", result);
253 #endif
256 void FrameMainGUI::OnKanjiAddByFreq(wxCommandEvent& event) {
257 if(!dialogAddKanjiByFreq)
258 dialogAddKanjiByFreq = new DialogAddKanjiByFreq(this);
259 int result = dialogAddKanjiByFreq->ShowModal();
260 if(result==wxID_OK) {
261 result = jben->kanjiList->AddByFrequency(
262 dialogAddKanjiByFreq->GetLowFreq(),
263 dialogAddKanjiByFreq->GetHighFreq());
264 this->Redraw();
265 wxMessageBox(wxString::Format(
266 _T("Added %d kanji to the list."), result),
267 _T("Add Kanji by Frequency"), wxOK | wxICON_INFORMATION, this);
268 } else if(result==wxID_CANCEL) {
269 /* Do nothing */
271 #ifdef DEBUG
272 else printf("Unknown key (%08X) pressed within dialog!\n", result);
273 #endif
276 void FrameMainGUI::OnKanjiSaveToFile(wxCommandEvent& event) {
277 /* NOTE: We may add the flag wxFD_CHANGE_DIR later, if we add in code
278 to save the full path for the jben.cfg file. */
279 wxFileDialog *fd = new wxFileDialog(
280 this, _T("Save Kanji List to File"), wxEmptyString, wxEmptyString,
281 _T("*"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
282 if(fd->ShowModal()==wxID_OK) {
283 wxString kanjiList = jben->kanjiList->ToString(20);
284 wxString filename = fd->GetPath();
285 /* Open file/write to file/close file */ /* TO DO */
286 wxFFile f(filename, _T("w"));
287 if(f.IsOpened()) {
288 f.Write(kanjiList, *wxConvCurrent);
289 f.Close();
292 fd->Destroy();
295 void FrameMainGUI::OnKanjiClearList(wxCommandEvent& event) {
296 jben->kanjiList->Clear();
297 this->Redraw();
300 #ifdef DEBUG
301 void FrameMainGUI::OnKanjiDumpList(wxCommandEvent& event) {
302 printf("Current kanji list: %ls\n", jben->kanjiList->ToString().c_str());
304 #endif
306 void FrameMainGUI::OnHelpAbout(wxCommandEvent& event) {
307 wxMessageBox(_T(
308 PROGRAM_NAME " v" VERSION_STR
309 "\nBy " AUTHOR_NAME
310 "\nCopyright " COPYRIGHT_DATE "\n\n"
312 "Inspired in large by JWPce and JFC by Glenn Rosenthal:\n"
313 "http://www.physics.ucla.edu/~grosenth/\n\n"
315 "Powered by Monash University's EDICT2 and KANJIDIC:\n"
316 "http://www.csse.monash.edu.au/~jwb/edict_doc.html\n"
317 "http://www.csse.monash.edu.au/~jwb/kanjidic.html\n\n"
319 "Built using wxWidgets: http://www.wxwidgets.org/\n\n"
321 "Hand writing recognition is based upon code from im-ja:\n"
322 "http://im-ja.sourceforge.net/\n"
323 "Which uses code based upon KanjiPad by Owen Taylor:\n"
324 "http://fishsoup.net/software/kanjipad/\n\n"
326 "See \"Help->License Information...\" for important license details."),
327 _T("About " PROGRAM_NAME), wxOK | wxICON_INFORMATION, this);
330 void FrameMainGUI::OnHelpLicense(wxCommandEvent& event) {
331 wxString licenseMessage = _T(
332 "Program distributed under the GNU General Public License (GPL) version 2:\n"
333 "http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt\n\n"
334 "EDICT2 and KANJIDIC distributed under a separate license specified at\n"
335 "http://www.csse.monash.edu.au/~jwb/edrdg/license.htm\n\n"
337 "The SKIP (System of Kanji Indexing by Patterns) system for ordering kanji "
338 "was developed by Jack Halpern (Kanji Dictionary Publishing Society at "
339 "http://www.kanji.org/), and is used with his permission.\n\n"
341 "Copies of the GNU General Public License, Monash University's license for "
342 "the dictionary files and documentation for the dictionary files are "
343 "contained in this program's \"license\" directory.");
344 #ifndef __WXMSW__
345 licenseMessage.append(
346 _T(" (On this system, it should be located in\n"));
347 licenseMessage.append(utfconv_mw(LICENSEDIR));
348 licenseMessage.append(_T(".)"));
349 #endif
350 wxMessageBox(licenseMessage, _T("License Information"),
351 wxOK | wxICON_INFORMATION, this);
354 void FrameMainGUI::OnMajorTabChanged(wxNotebookEvent& event) {
355 #ifdef DEBUG
356 printf("DEBUG: OnMAJORTabChanged called.\n");
357 #endif
358 tabMajor = (wxNotebookPage *) tabsMain->GetPage(event.GetSelection());
359 tabMinor = ((wxNotebook *)tabMajor)->GetCurrentPage();
360 #ifdef DEBUG
361 printf("tabMajor = %p, tabMinor = %p\n", tabMajor, tabMinor);
362 #endif
363 this->Redraw();
366 void FrameMainGUI::OnMinorTabChanged(wxNotebookEvent& event) {
367 #ifdef DEBUG
368 printf("DEBUG: OnMinorTabChanged called.\n");
369 #endif
370 wxNotebook *nb = (wxNotebook *) tabsMain->GetCurrentPage();
371 if(nb) {
372 tabMinor = (wxNotebookPage *) nb->GetPage(event.GetSelection());
373 } else tabMinor = NULL;
374 #ifdef DEBUG
375 printf("tabMajor = %p, tabMinor = %p\n", tabMajor, tabMinor);
376 #endif
377 this->Redraw();
380 /* This is the handler code for our tab changes.
381 It's called by both OnTabChanging functions.
382 Returns true if the tab change should take place, and false if it
383 should be vetoed. */
384 bool FrameMainGUI::TabChangeHandler(wxNotebookPage *page) {
385 int result;
386 if(page == panelConfig) {
387 if(panelConfig->ChangeDetected()) {
388 result = wxMessageBox(
389 _T("You have made changes to your configuration. Do you want "
390 "to save them?"),
391 _T("Unsaved Changes Detected!"),
392 wxYES_NO | wxCANCEL | wxICON_QUESTION, this);
393 if(result==wxYES) {
394 panelConfig->Commit();
395 } else if(result==wxNO) {
396 panelConfig->Revert();
397 } else if(result==wxCANCEL) {
398 return false;
402 else if(page == panelKanjiListEditor) {
403 if(panelKanjiListEditor->ChangeDetected()) {
404 result = wxMessageBox(
405 _T("You have made changes to the kanji list. Do you want to "
406 "save them?"),
407 _T("Unsaved Changes Detected!"),
408 wxYES_NO | wxCANCEL | wxICON_QUESTION, this);
409 if(result==wxYES) {
410 panelKanjiListEditor->Commit();
411 } else if(result==wxNO) {
412 panelKanjiListEditor->Revert();
413 } else if(result==wxCANCEL) {
414 return false;
418 else if(page == panelVocabListEditor) {
419 if(panelVocabListEditor->ChangeDetected()) {
420 result = wxMessageBox(
421 _T("You have made changes to the vocab list. Do you want to "
422 "save them?"),
423 _T("Unsaved Changes Detected!"),
424 wxYES_NO | wxCANCEL | wxICON_QUESTION, this);
425 if(result==wxYES) {
426 panelVocabListEditor->Commit();
427 } else if(result==wxNO) {
428 panelVocabListEditor->Revert();
429 } else if(result==wxCANCEL) {
430 return false;
434 else if(page == panelKanjiDrill) {
435 if(panelKanjiDrill->TestInProgress()) {
436 result =
437 wxMessageBox(_T("A test is in progress. Switching tabs will "
438 "abort the test. Are you sure you want to do "
439 "this?"),
440 _T("Test in progress!"), wxYES_NO | wxICON_EXCLAMATION, this);
441 if(result==wxYES) {
442 panelKanjiDrill->Stop();
443 } else {
444 return false;
448 return true;
451 void FrameMainGUI::OnTabChanging(wxNotebookEvent& event) {
452 int index = event.GetOldSelection();
453 if(index==-1) return;
455 if(!TabChangeHandler(tabMinor)) event.Veto();
458 void FrameMainGUI::OnKanjiSortByGrade(wxCommandEvent& ev) {
459 jben->kanjiList->Sort(ST_GRADE);
460 this->Redraw();
463 void FrameMainGUI::OnKanjiSortByFreq(wxCommandEvent& ev) {
464 jben->kanjiList->Sort(ST_FREQUENCY);
465 this->Redraw();
468 void FrameMainGUI::OnKanjiSearchKanjiPad(wxCommandEvent& ev) {
469 /* Multiple instances are allowed - just spin off an instance. */
470 FrameKanjiPad *kanjiPad =
471 new FrameKanjiPad(this, -1, _T("J-Ben: KanjiPad"));
472 kanjiPad->Show();
475 void FrameMainGUI::Redraw() {
476 bool state = (jben->kanjiList->Size()>0);
477 kanjiMenu->Enable(ID_menuKanjiSaveToFile, state);
478 kanjiMenu->Enable(ID_menuKanjiClearList, state);
480 if(tabMinor) {
481 ((RedrawablePanel *)tabMinor)->Redraw();
485 void FrameMainGUI::OnClose(wxCloseEvent& event) {
486 if(!event.CanVeto()) {
487 #ifdef DEBUG
488 fprintf(stderr, "event.CanVeto() returned false!\n");
489 #endif
490 this->Destroy();
492 /* Check for active kanji drill */
493 if(tabsMain->GetCurrentPage()==panelKanjiDrill &&
494 panelKanjiDrill->TestInProgress()) {
495 int result =
496 wxMessageBox(_T("A test is in progress. Are you sure you want to "
497 "quit?"),
498 _T("Test in progress!"), wxYES_NO | wxICON_EXCLAMATION, this);
499 if(result==wxYES) {
500 panelKanjiDrill->Stop();
501 } else {
502 event.Veto();
503 return;
507 /* Everything is okay - close the program. */
508 this->Destroy();