/* Meganekko Copyright (C) 2008 Alex Yatskov This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "Pch.h" #include "FrameMeganekko.h" #include "DialogCardManager.h" #include "DialogCard.h" #include "DialogAbout.h" #include "DialogOptions.h" BEGIN_EVENT_TABLE(FrameMeganekko, wxFrame) EVT_MENU(XRCID("menuFileNew"), FrameMeganekko::OnMenuFileNew) EVT_MENU(XRCID("menuFileOpen"), FrameMeganekko::OnMenuFileOpen) EVT_MENU(XRCID("menuFileSave"), FrameMeganekko::OnMenuFileSave) EVT_MENU(XRCID("menuFileSaveAs"), FrameMeganekko::OnMenuFileSaveAs) EVT_MENU(XRCID("menuFileExit"), FrameMeganekko::OnMenuFileExit) EVT_MENU(XRCID("menuToolsCardsManage"), FrameMeganekko::OnMenuToolsCardsManage) EVT_MENU(XRCID("menuToolsCardsExpire"), FrameMeganekko::OnMenuToolsCardsExpire) EVT_MENU(XRCID("menuToolsOptions"), FrameMeganekko::OnMenuToolsOptions) EVT_MENU(XRCID("menuToolsReviewSequential"), FrameMeganekko::OnMenuToolsReviewSequential) EVT_MENU(XRCID("menuToolsReviewStudy"), FrameMeganekko::OnMenuToolsReviewStudy) EVT_MENU(XRCID("menuHelpHomepage"), FrameMeganekko::OnMenuHelpHomepage) EVT_MENU(XRCID("menuHelpAbout"), FrameMeganekko::OnMenuHelpAbout) EVT_BUTTON(XRCID("buttonExpired"), FrameMeganekko::OnButtonExpired) EVT_BUTTON(XRCID("buttonFailed"), FrameMeganekko::OnButtonFailed) EVT_BUTTON(XRCID("buttonUntested"), FrameMeganekko::OnButtonUntested) EVT_BUTTON(XRCID("buttonPending"), FrameMeganekko::OnButtonPending) EVT_CLOSE(FrameMeganekko::OnClose) END_EVENT_TABLE() FrameMeganekko::FrameMeganekko(const wxString& filename) : m_gaugeExpired(NULL), m_gaugeFailed(NULL), m_gaugeUntested(NULL), m_gaugePending(NULL), m_buttonExpired(NULL), m_buttonFailed(NULL), m_buttonUntested(NULL), m_buttonPending(NULL) { wxXmlResource::Get()->LoadFrame(this, NULL, wxT("FrameMeganekko")); SetSize(wxSize(640, 480)); m_gaugeExpired = XRCCTRL(*this, "gaugeExpired", wxGauge); m_gaugeFailed = XRCCTRL(*this, "gaugeFailed", wxGauge); m_gaugeUntested = XRCCTRL(*this, "gaugeUntested", wxGauge); m_gaugePending = XRCCTRL(*this, "gaugePending", wxGauge); m_buttonExpired = XRCCTRL(*this, "buttonExpired", wxButton); m_buttonFailed = XRCCTRL(*this, "buttonFailed", wxButton); m_buttonUntested = XRCCTRL(*this, "buttonUntested", wxButton); m_buttonPending = XRCCTRL(*this, "buttonPending", wxButton); if (!filename.IsEmpty()) { OpenDecks(filename); } UpdateDecks(); } void FrameMeganekko::OnMenuFileNew(wxCommandEvent& event) { if (!SavePromptBail()) { NewDecks(); } } void FrameMeganekko::OnMenuFileOpen(wxCommandEvent& event) { if (SavePromptBail()) { return; } wxString filename = wxFileSelector( wxT("Choose a deck file to open"), wxEmptyString, wxEmptyString, wxT("mnko"), wxT("Meganekko files|*.mnko"), wxOPEN, this ); if (filename.IsEmpty()) { return; } #ifdef wxGTK // is this a bug in gtk wx? the default_extension doesn't appear to do anything // so for now just explicitly provide an extension if one isn't specified wxFileName temp(filename); if (temp.GetExt().IsEmpty()) { temp.SetExt(wxT("mnko")); filename = temp.GetFullPath(); } #endif OpenDecks(filename); } void FrameMeganekko::OnMenuFileSave(wxCommandEvent& event) { SaveDecks(); } void FrameMeganekko::OnMenuFileSaveAs(wxCommandEvent& event) { SaveDecksAs(); } void FrameMeganekko::OnMenuFileExit(wxCommandEvent&) { Close(true); } void FrameMeganekko::OnMenuToolsCardsManage(wxCommandEvent& event) { DialogCardManager* const dialog = new DialogCardManager(this, &m_manager); dialog->ShowModal(); UpdateDecks(); } void FrameMeganekko::OnMenuToolsCardsExpire(wxCommandEvent& event) { const int count = m_manager.ExpireCards(); if (count == 0) { wxMessageBox(wxT("There are no newly expired cards"), wxT("Meganekko"), wxOK | wxICON_INFORMATION, this); } else { wxMessageBox(wxString::Format(wxT("There are %d newly expired cards"), count), wxT("Meganekko"), wxOK | wxICON_INFORMATION, this); UpdateDecks(); } } void FrameMeganekko::OnMenuToolsOptions(wxCommandEvent& event) { DialogOptions* const dialog = new DialogOptions(this, &m_manager); dialog->ShowModal(); UpdateDecks(); } void FrameMeganekko::OnMenuToolsReviewSequential(wxCommandEvent& event) { std::vector cards; m_manager.EnumerateCards(&cards, static_cast(-1) & ~BIT(DECK_TYPE_FAILED), true, false, DECK_SORT_TYPE_TIME_REVIEW_PREVIOUS); if (cards.size() > 0) { DialogCard* const dialog = new DialogCard(this, BIT(DialogCard::CARD_CTRL_QUIZ), cards, m_manager.GetOptions()); dialog->ShowModal(); UpdateDecks(); } } void FrameMeganekko::OnMenuToolsReviewStudy(wxCommandEvent& event) { std::vector cards; m_manager.EnumerateCards(&cards, static_cast(-1), false, true, DECK_SORT_TYPE_TIME_ADDED); if (cards.size() > 0) { const unsigned controls = BIT(DialogCard::CARD_CTRL_ENABLED) | BIT(DialogCard::CARD_CTRL_NAVIGATE); DialogCard* const dialog = new DialogCard(this, controls, cards, m_manager.GetOptions()); dialog->ShowModal(); UpdateDecks(); } } void FrameMeganekko::OnMenuHelpHomepage(wxCommandEvent& event) { wxLaunchDefaultBrowser(wxT("http://foosoft.net/meganekko")); } void FrameMeganekko::OnMenuHelpAbout(wxCommandEvent& event) { DialogAbout* const dialog = new DialogAbout(this); dialog->ShowModal(); } void FrameMeganekko::OnButtonExpired(wxCommandEvent& event) { UseDeck(DECK_TYPE_EXPIRED); } void FrameMeganekko::OnButtonFailed(wxCommandEvent& event) { UseDeck(DECK_TYPE_FAILED); } void FrameMeganekko::OnButtonUntested(wxCommandEvent& event) { UseDeck(DECK_TYPE_UNTESTED); } void FrameMeganekko::OnButtonPending(wxCommandEvent& event) { UseDeck(DECK_TYPE_PENDING); } void FrameMeganekko::OnClose(wxCloseEvent& event) { if (event.CanVeto() && SavePromptBail()) { event.Veto(); } else { Destroy(); } } bool FrameMeganekko::UseDeck(DeckType type) { unsigned controls = BIT(DialogCard::CARD_CTRL_QUIZ); if (type == DECK_TYPE_FAILED) { controls = BIT(DialogCard::CARD_CTRL_LEARNED) | BIT(DialogCard::CARD_CTRL_NAVIGATE); } std::vector cards; m_manager.EnumerateCards(&cards, BIT(type), true, false, DECK_SORT_TYPE_SHUFFLE); if (cards.size() > 0) { DialogCard* const dialog = new DialogCard(this, controls, cards, m_manager.GetOptions()); dialog->ShowModal(); UpdateDecks(); } return cards.size() > 0; } bool FrameMeganekko::SaveDecksAs() { wxString filename = wxFileSelector( wxT("Choose a deck file to save"), wxEmptyString, wxEmptyString, wxT("mnko"), wxT("Meganekko files|*.mnko"), wxSAVE, this ); if (filename.IsEmpty()) { return false; } m_filename = filename; #ifdef wxGTK // is this a bug in gtk wx? the default_extension doesn't appear to do anything // so for now just explicitly provide an extension if one isn't specified wxFileName temp(m_filename); if (temp.GetExt().IsEmpty()) { temp.SetExt(wxT("mnko")); m_filename = temp.GetFullPath(); } #endif return SaveDecks(m_filename); } bool FrameMeganekko::SaveDecks() { return m_filename.IsEmpty() ? SaveDecksAs() : SaveDecks(m_filename); } bool FrameMeganekko::SaveDecks(const wxString& filename) { if (!m_manager.Save(filename.c_str())) { wxMessageBox(wxString::Format(wxT("Cannot save deck %s"), filename.c_str()), wxT("Meganekko"), wxOK | wxICON_ERROR, this); return false; } m_filename = filename; UpdateDecks(); return true; } bool FrameMeganekko::OpenDecks(const wxString& filename) { if (!m_manager.Open(filename.c_str())) { wxMessageBox(wxString::Format(wxT("Cannot open deck %s"), filename.c_str()), wxT("Meganekko"), wxOK | wxICON_ERROR, this); return false; } m_filename = filename; UpdateDecks(); return true; } bool FrameMeganekko::NewDecks() { m_manager.Close(); m_filename.Clear(); UpdateDecks(); return true; } void FrameMeganekko::UpdateDecks() { const wxString title = wxString::Format( wxT("Meganekko - %s %c"), m_filename.IsEmpty() ? wxT("Untitled") : m_filename.c_str(), m_manager.IsModified() ? '*' : ' ' ); SetTitle(title); const int expired = m_manager.GetDeckSize(DECK_TYPE_EXPIRED, false); const int failed = m_manager.GetDeckSize(DECK_TYPE_FAILED, false); const int untested = m_manager.GetDeckSize(DECK_TYPE_UNTESTED, false); const int pending = m_manager.GetDeckSize(DECK_TYPE_PENDING, false); const int total = expired + failed + untested + pending; float percentExpired = 0; float percentFailed = 0; float percentUntested = 0; float percentPending = 0; if (total > 0) { percentExpired = 100.0f * static_cast(expired) / static_cast(total); percentFailed = 100.0f * static_cast(failed) / static_cast(total); percentUntested = 100.0f * static_cast(untested) / static_cast(total); percentPending = 100.0f * static_cast(pending) / static_cast(total); } m_gaugeExpired->SetValue(static_cast(percentExpired)); m_gaugeExpired->SetToolTip(wxString::Format(wxT("%.2f%%"), percentExpired)); m_buttonExpired->SetLabel(wxString::Format(wxT("&Expired (%d)"), expired)); m_buttonExpired->Enable(expired > 0); m_gaugeFailed->SetValue(static_cast(percentFailed)); m_gaugeFailed->SetToolTip(wxString::Format(wxT("%.2f%%"), percentFailed)); m_buttonFailed->SetLabel(wxString::Format(wxT("F&ailed (%d)"), failed)); m_buttonFailed->Enable(failed > 0); m_gaugeUntested->SetValue(static_cast(percentUntested)); m_gaugeUntested->SetToolTip(wxString::Format(wxT("%.2f%%"), percentUntested)); m_buttonUntested->SetLabel(wxString::Format(wxT("&Untested (%d)"), untested)); m_buttonUntested->Enable(untested > 0); m_gaugePending->SetValue(static_cast(percentPending)); m_gaugePending->SetToolTip(wxString::Format(wxT("%.2f%%"), percentPending)); m_buttonPending->SetLabel(wxString::Format(wxT("&Pending (%d)"), pending)); m_buttonPending->Enable(pending > 0); } bool FrameMeganekko::SavePromptBail() { if (!m_manager.IsModified()) { return false; } const int result = m_manager.GetOptions().autoSave ? wxYES : wxMessageBox( wxT("The flash card database has been modified, do you want to save?"), wxT("Meganekko"), wxYES_NO | wxCANCEL | wxICON_QUESTION, this ); if (result == wxNO || (result == wxYES && SaveDecks())) { return false; } return true; }