Commit bfbbe02b authored by twanvl's avatar twanvl

* Added console panel for evaluating scripts and showing error messages.

* Rewrite of error queue code: errors are now pulled, instead of being turned into messageboxes automatically.
parent 04ba8492
...@@ -53,7 +53,7 @@ menu: ...@@ -53,7 +53,7 @@ menu:
previous keyword: Select &Previous Keyword PgUp previous keyword: Select &Previous Keyword PgUp
next keyword: Select &Next Keyword PgDn next keyword: Select &Next Keyword PgDn
add keyword: &Add Keyword Ctrl+Enter add keyword: &Add Keyword Ctrl+Enter
remove keyword: &Remove Select Keyword Del remove keyword: &Remove Select Keyword Del
format: F&ormat format: F&ormat
bold: &Bold Ctrl+B bold: &Bold Ctrl+B
...@@ -79,6 +79,7 @@ menu: ...@@ -79,6 +79,7 @@ menu:
keywords tab: &Keywords F8 keywords tab: &Keywords F8
stats tab: S&tatistics F9 stats tab: S&tatistics F9
random pack tab: &Random Packs random pack tab: &Random Packs
console tab: &Console Ctrl+F9
help: &Help help: &Help
index: &Index... F1 index: &Index... F1
...@@ -190,6 +191,7 @@ help: ...@@ -190,6 +191,7 @@ help:
keywords tab: Define extra keywords for this set keywords tab: Define extra keywords for this set
stats tab: Show statistics about the cards in the set stats tab: Show statistics about the cards in the set
random pack tab: Try how the set works out in practice by generating random booster packs. random pack tab: Try how the set works out in practice by generating random booster packs.
console tab: Shows error messages and allows executing script commands.
help: help:
index: index:
...@@ -205,6 +207,8 @@ help: ...@@ -205,6 +207,8 @@ help:
seed: Seed number for the random generator. Using the same seed number gives the same 'random' packs. seed: Seed number for the random generator. Using the same seed number gives the same 'random' packs.
edit pack type: Double click to edit pack type edit pack type: Double click to edit pack type
number of packs: The number of %ss to generate number of packs: The number of %ss to generate
# Console panel
evaluate: Evaluate the entered script command
# Preferences # Preferences
app language: app language:
...@@ -292,6 +296,7 @@ tool: ...@@ -292,6 +296,7 @@ tool:
keywords tab: Keywords keywords tab: Keywords
stats tab: Statistics stats tab: Statistics
random pack tab: Random random pack tab: Random
console tab: Console
# symbol editor # symbol editor
store symbol: Store store symbol: Store
...@@ -337,6 +342,7 @@ tooltip: ...@@ -337,6 +342,7 @@ tooltip:
keywords tab: keywords tab:
stats tab: stats tab:
random pack tab: Random packs random pack tab: Random packs
console tab:
new set: New set new set: New set
open set: Open set open set: Open set
...@@ -562,6 +568,9 @@ button: ...@@ -562,6 +568,9 @@ button:
fixed seed: &Fixed Seed fixed seed: &Fixed Seed
add custom pack: Add &Custom Pack... add custom pack: Add &Custom Pack...
# Console panel
evaluate: &Evaluate
# Welcome # Welcome
new set: New set new set: New set
open set: Open set open set: Open set
......
...@@ -75,7 +75,7 @@ void CLISetInterface::setExportInfoCwd() { ...@@ -75,7 +75,7 @@ void CLISetInterface::setExportInfoCwd() {
void CLISetInterface::run() { void CLISetInterface::run() {
// show welcome logo // show welcome logo
if (!quiet) showWelcome(); if (!quiet) showWelcome();
handle_pending_errors(); print_pending_errors();
// loop // loop
running = true; running = true;
while (running) { while (running) {
...@@ -88,6 +88,7 @@ void CLISetInterface::run() { ...@@ -88,6 +88,7 @@ void CLISetInterface::run() {
String command = cli.getLine(); String command = cli.getLine();
if (command.empty() && !cli.canGetLine()) break; if (command.empty() && !cli.canGetLine()) break;
handleCommand(command); handleCommand(command);
print_pending_errors();
cli.flush(); cli.flush();
cli.flushRaw(); cli.flushRaw();
} }
...@@ -134,7 +135,7 @@ void CLISetInterface::handleCommand(const String& command) { ...@@ -134,7 +135,7 @@ void CLISetInterface::handleCommand(const String& command) {
showUsage(); showUsage();
} else if (before == _(":l") || before == _(":load")) { } else if (before == _(":l") || before == _(":load")) {
if (arg.empty()) { if (arg.empty()) {
cli.showError(_("Give a filename to open.")); cli.show_message(MESSAGE_ERROR,_("Give a filename to open."));
} else { } else {
setSet(import_set(arg)); setSet(import_set(arg));
} }
...@@ -154,10 +155,10 @@ void CLISetInterface::handleCommand(const String& command) { ...@@ -154,10 +155,10 @@ void CLISetInterface::handleCommand(const String& command) {
} }
} else if (before == _(":c") || before == _(":cd")) { } else if (before == _(":c") || before == _(":cd")) {
if (arg.empty()) { if (arg.empty()) {
cli.showError(_("Give a new working directory.")); cli.show_message(MESSAGE_ERROR,_("Give a new working directory."));
} else { } else {
if (!wxSetWorkingDirectory(arg)) { if (!wxSetWorkingDirectory(arg)) {
cli.showError(_("Can't change working directory to ")+arg); cli.show_message(MESSAGE_ERROR,_("Can't change working directory to ")+arg);
} else { } else {
setExportInfoCwd(); setExportInfoCwd();
} }
...@@ -166,7 +167,7 @@ void CLISetInterface::handleCommand(const String& command) { ...@@ -166,7 +167,7 @@ void CLISetInterface::handleCommand(const String& command) {
cli << ei.directory_absolute << ENDL; cli << ei.directory_absolute << ENDL;
} else if (before == _(":!")) { } else if (before == _(":!")) {
if (arg.empty()) { if (arg.empty()) {
cli.showError(_("Give a shell command to execute.")); cli.show_message(MESSAGE_ERROR,_("Give a shell command to execute."));
} else { } else {
#ifdef UNICODE #ifdef UNICODE
#ifdef __WXMSW__ #ifdef __WXMSW__
...@@ -190,7 +191,7 @@ void CLISetInterface::handleCommand(const String& command) { ...@@ -190,7 +191,7 @@ void CLISetInterface::handleCommand(const String& command) {
} }
#endif #endif
} else { } else {
cli.showError(_("Unknown command, type :help for help.")); cli.show_message(MESSAGE_ERROR,_("Unknown command, type :help for help."));
} }
} else if (command == _("exit") || command == _("quit")) { } else if (command == _("exit") || command == _("quit")) {
cli << _("Use :quit to quit\n"); cli << _("Use :quit to quit\n");
...@@ -201,7 +202,7 @@ void CLISetInterface::handleCommand(const String& command) { ...@@ -201,7 +202,7 @@ void CLISetInterface::handleCommand(const String& command) {
vector<ScriptParseError> errors; vector<ScriptParseError> errors;
ScriptP script = parse(command,nullptr,false,errors); ScriptP script = parse(command,nullptr,false,errors);
if (!errors.empty()) { if (!errors.empty()) {
FOR_EACH(error,errors) cli.showError(error.what()); FOR_EACH(error,errors) cli.show_message(MESSAGE_ERROR,error.what());
return; return;
} }
// execute command // execute command
...@@ -212,7 +213,7 @@ void CLISetInterface::handleCommand(const String& command) { ...@@ -212,7 +213,7 @@ void CLISetInterface::handleCommand(const String& command) {
cli << result->toCode() << ENDL; cli << result->toCode() << ENDL;
} }
} catch (const Error& e) { } catch (const Error& e) {
cli.showError(e.what()); cli.show_message(MESSAGE_ERROR,e.what());
} }
} }
...@@ -235,3 +236,11 @@ void CLISetInterface::handleCommand(const String& command) { ...@@ -235,3 +236,11 @@ void CLISetInterface::handleCommand(const String& command) {
} }
} }
#endif #endif
void CLISetInterface::print_pending_errors() {
MessageType type;
String msg;
while (get_queued_message(type,msg)) {
cli.show_message(type,msg);
}
}
...@@ -36,6 +36,7 @@ class CLISetInterface : public SetView { ...@@ -36,6 +36,7 @@ class CLISetInterface : public SetView {
#if USE_SCRIPT_PROFILING #if USE_SCRIPT_PROFILING
void showProfilingStats(const FunctionProfile& parent, int level = 0); void showProfilingStats(const FunctionProfile& parent, int level = 0);
#endif #endif
void print_pending_errors();
/// our own context, when no set is loaded /// our own context, when no set is loaded
Context& getContext(); Context& getContext();
......
...@@ -35,7 +35,7 @@ TextIOHandler cli; ...@@ -35,7 +35,7 @@ TextIOHandler cli;
void TextIOHandler::init() { void TextIOHandler::init() {
bool have_stderr; bool have_stderr;
#ifdef __WXMSW__ #if defined(__WXMSW__)
have_console = false; have_console = false;
escapes = false; escapes = false;
// Detect whether to use console output // Detect whether to use console output
...@@ -51,9 +51,20 @@ void TextIOHandler::init() { ...@@ -51,9 +51,20 @@ void TextIOHandler::init() {
} }
} }
#else #else
// always use console on *nix (?) // TODO: detect console on linux?
have_console = true; have_console = false;
have_stderr = true; have_stderr = false;
// Use console mode if one of the cli flags is passed
static const Char* redirect_flags[] = {_("-?"),_("--help"),_("-v"),_("--version"),_("--cli"),_("-c"),_("--export"),_("--create-installer")};
for (int i = 1 ; i < wxTheApp->argc ; ++i) {
for (int j = 0 ; j < sizeof(redirect_flags)/sizeof(redirect_flags[0]) ; ++j) {
if (String(wxTheApp->argv[i]) == redirect_flags[j]) {
have_console = true;
have_stderr = true;
break;
}
}
}
escapes = true; // TODO: detect output redirection escapes = true; // TODO: detect output redirection
#endif #endif
// write to standard output // write to standard output
...@@ -154,18 +165,14 @@ void TextIOHandler::flushRaw() { ...@@ -154,18 +165,14 @@ void TextIOHandler::flushRaw() {
// ----------------------------------------------------------------------------- : Errors // ----------------------------------------------------------------------------- : Errors
void TextIOHandler::showError(const String& message) { void TextIOHandler::show_message(MessageType type, String const& message) {
stream = stdout; stream = stdout;
*this << RED << _("ERROR: ") << NORMAL << replace_all(message,_("\n"),_("\n ")) << ENDL; if (type == MESSAGE_WARNING) {
flush(); *this << YELLOW << _("WARNING: ") << NORMAL << replace_all(message,_("\n"),_("\n ")) << ENDL;
stream = stdout; } else {
if (raw_mode) raw_mode_status = max(raw_mode_status, 2); *this << RED << _("ERROR: ") << NORMAL << replace_all(message,_("\n"),_("\n ")) << ENDL;
} }
void TextIOHandler::showWarning(const String& message) {
stream = stdout;
*this << YELLOW << _("WARNING: ") << NORMAL << replace_all(message,_("\n"),_("\n ")) << ENDL;
flush(); flush();
stream = stdout; stream = stdout;
if (raw_mode) raw_mode_status = max(raw_mode_status, 1); if (raw_mode) raw_mode_status = max(raw_mode_status, type == MESSAGE_WARNING ? 1 : 2);
} }
...@@ -36,10 +36,8 @@ class TextIOHandler { ...@@ -36,10 +36,8 @@ class TextIOHandler {
/// Flush output /// Flush output
void flush(); void flush();
/// Show an error message /// Show an error or warning message
void showError(const String& message); void show_message(MessageType type, String const& message);
/// Show a warning message
void showWarning(const String& message);
/// Enable raw mode /// Enable raw mode
void enableRaw(); void enableRaw();
......
...@@ -60,7 +60,7 @@ FontP Font::make(int add_flags, AColor* other_color, double* other_size) const { ...@@ -60,7 +60,7 @@ FontP Font::make(int add_flags, AColor* other_color, double* other_size) const {
f->color = Color(128,0,0); f->color = Color(128,0,0);
} }
if (add_flags & FONT_CODE_KW) { if (add_flags & FONT_CODE_KW) {
f->color = Color(158,0,0); f->color = Color(158,100,0);
f->flags |= FONT_BOLD; f->flags |= FONT_BOLD;
} }
if (add_flags & FONT_SOFT) { if (add_flags & FONT_SOFT) {
......
...@@ -215,7 +215,7 @@ void Keyword::prepare(const vector<KeywordParamP>& param_types, bool force) { ...@@ -215,7 +215,7 @@ void Keyword::prepare(const vector<KeywordParamP>& param_types, bool force) {
// throwing an error can mean a set will not be loaded! // throwing an error can mean a set will not be loaded!
// instead, simply disable the keyword // instead, simply disable the keyword
//throw InternalError(_("Unknown keyword parameter type: ") + type); //throw InternalError(_("Unknown keyword parameter type: ") + type);
handle_error(_("Unknown keyword parameter type: ") + type, true, false); handle_error(_("Unknown keyword parameter type: ") + type);
valid = false; valid = false;
return; return;
} }
...@@ -700,7 +700,7 @@ bool KeywordDatabase::tryExpand(const Keyword& kw, ...@@ -700,7 +700,7 @@ bool KeywordDatabase::tryExpand(const Keyword& kw,
try { try {
reminder = kw.reminder.invoke(ctx)->toString(); reminder = kw.reminder.invoke(ctx)->toString();
} catch (const Error& e) { } catch (const Error& e) {
handle_error(_ERROR_2_("in keyword reminder", e.what(), kw.keyword), true, false); handle_error(_ERROR_2_("in keyword reminder", e.what(), kw.keyword));
} }
ctx.setVariable(_("keyword"), to_script(total)); ctx.setVariable(_("keyword"), to_script(total));
ctx.setVariable(_("reminder"), to_script(reminder)); ctx.setVariable(_("reminder"), to_script(reminder));
......
...@@ -86,7 +86,7 @@ SubLocaleP find_wildcard_and_set(map<String,SubLocaleP>& items, const String& na ...@@ -86,7 +86,7 @@ SubLocaleP find_wildcard_and_set(map<String,SubLocaleP>& items, const String& na
// ----------------------------------------------------------------------------- : Translation // ----------------------------------------------------------------------------- : Translation
String warn_and_identity(const String& key) { String warn_and_identity(const String& key) {
handle_warning(_("Missing key in locale: ") + key, false); queue_message(MESSAGE_WARNING, _("Missing key in locale: ") + key);
return key; return key;
} }
...@@ -253,7 +253,7 @@ void Locale::validate(Version ver) { ...@@ -253,7 +253,7 @@ void Locale::validate(Version ver) {
+ _("\n found: ") + ver.toString(); + _("\n found: ") + ver.toString();
} }
if (!errors.empty()) { if (!errors.empty()) {
handle_warning(errors); queue_message(MESSAGE_WARNING, errors);
} }
} }
......
...@@ -121,7 +121,7 @@ void StatsCategory::find_dimensions(const vector<StatsDimensionP>& available) { ...@@ -121,7 +121,7 @@ void StatsCategory::find_dimensions(const vector<StatsDimensionP>& available) {
} }
} }
if (!dim) { if (!dim) {
handle_error(_ERROR_1_("dimension not found",n),false); handle_error(_ERROR_1_("dimension not found",n));
} else { } else {
dimensions.push_back(dim); dimensions.push_back(dim);
} }
......
...@@ -95,7 +95,7 @@ void HtmlExportWindow::onOk(wxCommandEvent&) { ...@@ -95,7 +95,7 @@ void HtmlExportWindow::onOk(wxCommandEvent&) {
void HtmlExportWindow::onTemplateSelect(wxCommandEvent&) { void HtmlExportWindow::onTemplateSelect(wxCommandEvent&) {
wxBusyCursor wait; wxBusyCursor wait;
ExportTemplateP export_template = list->getSelection<ExportTemplate>(); ExportTemplateP export_template = list->getSelection<ExportTemplate>();
handle_pending_errors(); //handle_pending_errors(); // errors are ignored until set window is shown
options->showExport(export_template); options->showExport(export_template);
settings.gameSettingsFor(*set->game).default_export = export_template->name(); settings.gameSettingsFor(*set->game).default_export = export_template->name();
UpdateWindowUI(wxUPDATE_UI_RECURSE); UpdateWindowUI(wxUPDATE_UI_RECURSE);
......
...@@ -61,7 +61,7 @@ NewSetWindow::NewSetWindow(Window* parent) ...@@ -61,7 +61,7 @@ NewSetWindow::NewSetWindow(Window* parent)
void NewSetWindow::onGameSelect(wxCommandEvent&) { void NewSetWindow::onGameSelect(wxCommandEvent&) {
wxBusyCursor wait; wxBusyCursor wait;
GameP game = game_list->getSelection<Game>(false); GameP game = game_list->getSelection<Game>(false);
handle_pending_errors(); //handle_pending_errors(); // errors are ignored until set window is shown
settings.default_game = game->name(); settings.default_game = game->name();
stylesheet_list->showData<StyleSheet>(game->name() + _("-*")); stylesheet_list->showData<StyleSheet>(game->name() + _("-*"));
stylesheet_list->select(settings.gameSettingsFor(*game).default_stylesheet); stylesheet_list->select(settings.gameSettingsFor(*game).default_stylesheet);
...@@ -76,7 +76,7 @@ void NewSetWindow::onStyleSheetSelect(wxCommandEvent&) { ...@@ -76,7 +76,7 @@ void NewSetWindow::onStyleSheetSelect(wxCommandEvent&) {
// store this as default selection // store this as default selection
GameP game = game_list ->getSelection<Game>(false); GameP game = game_list ->getSelection<Game>(false);
StyleSheetP stylesheet = stylesheet_list->getSelection<StyleSheet>(false); StyleSheetP stylesheet = stylesheet_list->getSelection<StyleSheet>(false);
handle_pending_errors(); //handle_pending_errors(); // errors are ignored until set window is shown
settings.gameSettingsFor(*game).default_stylesheet = stylesheet->name(); settings.gameSettingsFor(*game).default_stylesheet = stylesheet->name();
UpdateWindowUI(wxUPDATE_UI_RECURSE); UpdateWindowUI(wxUPDATE_UI_RECURSE);
} }
...@@ -113,7 +113,7 @@ void NewSetWindow::onUpdateUI(wxUpdateUIEvent& ev) { ...@@ -113,7 +113,7 @@ void NewSetWindow::onUpdateUI(wxUpdateUIEvent& ev) {
void NewSetWindow::onIdle(wxIdleEvent& ev) { void NewSetWindow::onIdle(wxIdleEvent& ev) {
// Stuff that must be done in the main thread // Stuff that must be done in the main thread
handle_pending_errors(); //handle_pending_errors(); // errors are ignored until set window is shown
} }
BEGIN_EVENT_TABLE(NewSetWindow, wxDialog) BEGIN_EVENT_TABLE(NewSetWindow, wxDialog)
...@@ -162,7 +162,7 @@ SelectStyleSheetWindow::SelectStyleSheetWindow(Window* parent, const Game& game, ...@@ -162,7 +162,7 @@ SelectStyleSheetWindow::SelectStyleSheetWindow(Window* parent, const Game& game,
} }
void SelectStyleSheetWindow::onStyleSheetSelect(wxCommandEvent&) { void SelectStyleSheetWindow::onStyleSheetSelect(wxCommandEvent&) {
handle_pending_errors(); //handle_pending_errors(); // errors are ignored until set window is shown
UpdateWindowUI(wxUPDATE_UI_RECURSE); UpdateWindowUI(wxUPDATE_UI_RECURSE);
} }
void SelectStyleSheetWindow::onStyleSheetActivate(wxCommandEvent&) { void SelectStyleSheetWindow::onStyleSheetActivate(wxCommandEvent&) {
...@@ -193,7 +193,7 @@ void SelectStyleSheetWindow::onUpdateUI(wxUpdateUIEvent& ev) { ...@@ -193,7 +193,7 @@ void SelectStyleSheetWindow::onUpdateUI(wxUpdateUIEvent& ev) {
void SelectStyleSheetWindow::onIdle(wxIdleEvent& ev) { void SelectStyleSheetWindow::onIdle(wxIdleEvent& ev) {
// Stuff that must be done in the main thread // Stuff that must be done in the main thread
handle_pending_errors(); //handle_pending_errors(); // errors are ignored until set window is shown
} }
BEGIN_EVENT_TABLE(SelectStyleSheetWindow, wxDialog) BEGIN_EVENT_TABLE(SelectStyleSheetWindow, wxDialog)
......
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2010 Twan van Laarhoven and Sean Hunt |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <gui/set/console_panel.hpp>
#include <gui/control/text_ctrl.hpp>
#include <gui/util.hpp>
#include <util/window_id.hpp>
#include <data/stylesheet.hpp>
#include <wx/splitter.h>
#include <wx/dcbuffer.h>
DECLARE_POINTER_TYPE(ConsoleMessage);
DECLARE_TYPEOF_COLLECTION(ScriptParseError);
DECLARE_TYPEOF_COLLECTION(ConsoleMessageP);
// ----------------------------------------------------------------------------- : MessageControl
class ConsoleMessage : public IntrusivePtrBase<ConsoleMessage> {
public:
MessageType type;
String text; // string message
Bitmap bitmap; // image message instead of string
ScriptValueP value; // other valued message (images? cards?)
// location of error messages
String source_file;
int line_number;
// layout
bool joined_to_previous;
int top;
int height;
int bottom() const { return top+height; }
ConsoleMessage(MessageType type, String const& text = _(""))
: type(type), text(text), line_number(-1), joined_to_previous(false), top(-1), height(-1)
{}
};
class MessageCtrl : public wxScrolledWindow {
public:
MessageCtrl(wxWindow* parent, int id)
: wxScrolledWindow(parent, id, wxDefaultPosition, wxDefaultSize, wxBORDER_THEME)
{
SetBackgroundStyle(wxBG_STYLE_CUSTOM);
SetScrollRate(0, 1);
EnableScrolling(false,true);
// icons
BOOST_STATIC_ASSERT(MESSAGE_TYPE_MAX == 6);
icons[MESSAGE_INPUT] = wxBitmap(load_resource_image(_("message_input")));
icons[MESSAGE_OUTPUT] = wxBitmap();
icons[MESSAGE_INFO] = wxBitmap(load_resource_image(_("message_information")));
icons[MESSAGE_WARNING] = wxBitmap(load_resource_image(_("message_warning")));
icons[MESSAGE_ERROR] = wxBitmap(load_resource_image(_("message_error")));
icons[MESSAGE_FATAL_ERROR] = icons[MESSAGE_ERROR];
// color
colors[MESSAGE_INPUT] = wxColour(0,80,0);
colors[MESSAGE_OUTPUT] = wxColour(255,255,255);
colors[MESSAGE_INFO] = wxColour(0,0,255);
colors[MESSAGE_WARNING] = wxColour(255,255,0);
colors[MESSAGE_ERROR] = colors[MESSAGE_FATAL_ERROR] = wxColour(255,0,0);
}
void add_message(ConsoleMessageP const& msg) {
messages.push_back(msg);
layout_all(messages.size() - 1);
// refresh
ensure_visible(*messages.back());
Refresh(false);
}
void add_message(MessageType type, String const& text) {
add_message(intrusive(new ConsoleMessage(type,text)));
}
private:
DECLARE_EVENT_TABLE();
// --------------------------------------------------- : Data
// the messages
vector<ConsoleMessageP> messages;
size_t selection;
wxBitmap icons[MESSAGE_TYPE_MAX];
wxColour colors[MESSAGE_TYPE_MAX];
// --------------------------------------------------- : Events
void onLeftDown(wxMouseEvent& ev) {
int ystart; GetViewStart(nullptr,&ystart);
selection = find_point(ystart + ev.GetY());
if (selection < messages.size()) {
ensure_visible(*messages[selection]);
}
Refresh(false);
}
int find_point(int y) {
// TODO: could do a binary search here
for (size_t i = 0 ; i < messages.size() ; ++i) {
if (y >= messages[i]->top && y < messages[i]->bottom()) return i;
}
return (size_t)-1;
}
void ensure_visible(ConsoleMessage const& msg) {
int ystart; GetViewStart(nullptr,&ystart);
int height = GetClientSize().y;
if (msg.top < ystart) {
Scroll(0, msg.top);
} else if (msg.bottom() > ystart + height) {
Scroll(0, msg.bottom() - height);
}
}
// --------------------------------------------------- : Drawing
void onPaint(wxPaintEvent& ev) {
wxAutoBufferedPaintDC dc(this);
PrepareDC(dc);
draw(dc);
}
void draw(wxDC& dc) const {
clearDC(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
dc.SetFont(*wxNORMAL_FONT);
FOR_EACH_CONST(msg, messages) {
draw(dc, *msg);
}
if (messages.empty()) {
// Say something about no messages?
}
}
void draw(wxDC& dc, ConsoleMessage const& msg) const {
int left = 0;
int top = msg.top;
int width = GetClientSize().x;
wxColour color = colors[msg.type];
wxColour bg, fg;
if (selection < messages.size() && messages[selection].get() == &msg) {
bg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
fg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
} else {
bg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
fg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
}
// draw background
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(lerp(bg,color, 0.05));
dc.DrawRectangle(left,top,width,msg.height);
// draw icon
if (icons[msg.type].Ok()) {
dc.DrawBitmap(icons[msg.type], left + ICON_PADDING,top + ICON_PADDING);
}
// draw text
dc.SetTextForeground(fg);
int text_left = TEXT_PADDING_LEFT;
int text_top = top + TEXT_PADDING_TOP;
// find line breaks in the text
String::const_iterator begin = msg.text.begin();
String::const_iterator it = begin;
while (it != msg.text.end()) {
if (*it == _('\n')) {
// break here
dc.DrawText(String(begin,it), text_left, text_top);
begin = it = it + 1;
text_top += dc.GetCharHeight() + TEXT_LINE_SPACING;
} else {
it++;
}
}
if (begin != msg.text.end()) {
dc.DrawText(String(begin,it), text_left, text_top);
text_top += dc.GetCharHeight() + TEXT_LINE_SPACING;
}
// draw bitmap
if (msg.bitmap.Ok()) {
dc.DrawBitmap(msg.bitmap, text_left, text_top);
text_top += msg.bitmap.GetHeight();
}
// draw line below item
dc.SetPen(lerp(bg,fg, 0.3));
dc.DrawLine(left, top+msg.height, left+width, top+msg.height);
}
int item_height(wxDC& dc, ConsoleMessage const& msg) const {
// text height
int text_height = 0;
// find line breaks in the text
String::const_iterator begin = msg.text.begin();
String::const_iterator it = begin;
while (it != msg.text.end()) {
if (*it == _('\n')) {
// break here
begin = it = it + 1;
text_height += dc.GetCharHeight() + TEXT_LINE_SPACING;
} else {
it++;
}
// TODO: break long lines
}
if (begin != msg.text.end()) {
text_height += dc.GetCharHeight() + TEXT_LINE_SPACING;
}
// height of bitmap
int bitmap_height = msg.bitmap.Ok() ? msg.bitmap.GetHeight() : 0;
return max(MIN_ITEM_HEIGHT, TEXT_PADDING_TOP + TEXT_PADDING_BOTTOM + text_height + bitmap_height) + LIST_SPACING;
}
// --------------------------------------------------- : Layout
static const int LIST_SPACING = 1;
static const int ICON_PADDING = 3;
static const int TEXT_PADDING_LEFT = ICON_PADDING + 16 + 4;
static const int TEXT_PADDING_RIGHT = 4;
static const int TEXT_PADDING_TOP = 4;
static const int TEXT_PADDING_BOTTOM = 2;
static const int TEXT_LINE_SPACING = 1;
static const int MIN_ITEM_HEIGHT = 16 + 2*ICON_PADDING;
/// Layout all messages, starting from number start
/// layout = determine their height
void layout_all(size_t start = 0) {
// scratch dc, for finding text sizes
wxMemoryDC dc;
wxBitmap bmp(1,1);
dc.SelectObject(bmp);
dc.SetFont(*wxNORMAL_FONT);
for (size_t i = start ; i < messages.size() ; ++i) {
// layout a single item
ConsoleMessage& msg = *messages[i];
msg.top = start == 0 ? 0 : messages[i-1]->bottom() + LIST_SPACING;
if (i > 0 && msg.joined_to_previous) msg.top -= LIST_SPACING;
// text size
msg.height = item_height(dc, msg);
}
// set size of the control
if (messages.empty()) {
SetVirtualSize(-1, 0);
} else {
int height = messages.back()->bottom();
SetVirtualSize(-1, height);
}
}
// --------------------------------------------------- : Layout
};
BEGIN_EVENT_TABLE(MessageCtrl,wxScrolledWindow)
EVT_PAINT(MessageCtrl::onPaint)
EVT_LEFT_DOWN(MessageCtrl::onLeftDown)
END_EVENT_TABLE()
// ----------------------------------------------------------------------------- : ConsolePanel
ConsolePanel::ConsolePanel(Window* parent, int id)
: SetWindowPanel(parent, id)
{
// init controls
splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
messages = new MessageCtrl(splitter, wxID_ANY);
entry_panel = new Panel(splitter, wxID_ANY);
entry = new wxTextCtrl(entry_panel, wxID_ANY, _(""), wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
wxButton* evaluate = new wxButton(entry_panel, ID_EVALUATE, _BUTTON_("evaluate"));
// init sizer for entry_panel
wxSizer* se = new wxBoxSizer(wxHORIZONTAL);
se->Add(entry, 1, wxEXPAND, 2);
se->Add(evaluate, 0, wxEXPAND | wxLEFT, 2);
entry_panel->SetSizer(se);
// init splitter
splitter->SetMinimumPaneSize(40);
splitter->SetSashGravity(1.0);
splitter->SplitHorizontally(messages, entry_panel, -50);
// init sizer
wxSizer* s = new wxBoxSizer(wxVERTICAL);
s->Add(splitter, 1, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s);
}
void ConsolePanel::onChangeSet() {
// TODO
}
// ----------------------------------------------------------------------------- : UI
void ConsolePanel::initUI(wxToolBar* tb, wxMenuBar* mb) {
// Menus
// focus on entry
entry->SetFocus();
}
void ConsolePanel::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
// Toolbar
// Menus
}
void ConsolePanel::onUpdateUI(wxUpdateUIEvent& ev) {
if (ev.GetId() == ID_EVALUATE) {
ev.Enable(!entry->GetValue().empty());
}
}
void ConsolePanel::onEnter(wxCommandEvent& ev) {
onCommand(ID_EVALUATE);
}
void ConsolePanel::onCommand(int id) {
if (id == ID_EVALUATE) {
exec(entry->GetValue());
entry->SetValue(_(""));
}
}
void ConsolePanel::onIdle(wxIdleEvent&) {
get_pending_errors();
}
void ConsolePanel::get_pending_errors() {
// add pending messages
MessageType type;
String msg;
while (get_queued_message(type,msg)) {
messages->add_message(type,msg);
}
// If this panel doesn't have the focus, then highlight it somehow
}
void ConsolePanel::exec(String const& command) {
if (command.empty()) return;
// add input message
messages->add_message(MESSAGE_INPUT, command);
try {
// parse command
vector<ScriptParseError> errors;
ScriptP script = parse(command,nullptr,false,errors);
if (!errors.empty()) {
FOR_EACH(error,errors) {
// TODO: also squiglify the input?
messages->add_message(MESSAGE_ERROR,error.what());
}
return;
}
// execute command
//WITH_DYNAMIC_ARG(export_info, &ei); // TODO: allow image export
Context& ctx = set->getContext();
ScriptValueP result = ctx.eval(*script,false);
get_pending_errors();
// show result
ConsoleMessageP message = intrusive(new ConsoleMessage(MESSAGE_OUTPUT));
message->joined_to_previous = true;
message->value = result;
// type of result
ScriptType type = result->type();
if (type == SCRIPT_IMAGE) {
GeneratedImage::Options options(0,0, set->stylesheet.get(), set.get());
wxImage image = result->toImage(result)->generate(options);
message->bitmap = wxBitmap(image);
} else if (type == SCRIPT_COLOR) {
message->text = result->toCode();
AColor color = (AColor)*result;
wxImage image(30,20);
fill_image(image,color);
set_alpha(image, color.alpha);
message->bitmap = wxBitmap(image);
} else {
message->text = result->toCode();
}
messages->add_message(message);
} catch (ScriptError const& e) {
messages->add_message(MESSAGE_ERROR, e.what());
}
}
BEGIN_EVENT_TABLE(ConsolePanel, wxPanel)
EVT_TEXT_ENTER(wxID_ANY,ConsolePanel::onEnter)
EVT_IDLE(ConsolePanel::onIdle)
END_EVENT_TABLE ()
// ----------------------------------------------------------------------------- : Clipboard
/*
bool ConsolePanel::canCut() const { return entry->canCut(); }
bool ConsolePanel::canCopy() const { return entry->canCopy(); }
bool ConsolePanel::canPaste() const { return entry->canPaste(); }
void ConsolePanel::doCut() { entry->doCut(); }
void ConsolePanel::doCopy() { entry->doCopy(); }
void ConsolePanel::doPaste() { entry->doPaste(); }
*/
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2010 Twan van Laarhoven and Sean Hunt |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_GUI_SET_CONSOLE_PANEL
#define HEADER_GUI_SET_CONSOLE_PANEL
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <gui/set/panel.hpp>
class wxSplitterWindow;
class MessageCtrl;
class TextCtrl;
// ----------------------------------------------------------------------------- : ConsolePanel
class ConsolePanel : public SetWindowPanel {
public:
ConsolePanel(Window* parent, int id);
// --------------------------------------------------- : UI
void onIdle(wxIdleEvent&);
void onEnter(wxCommandEvent&);
virtual void initUI (wxToolBar* tb, wxMenuBar* mb);
virtual void destroyUI(wxToolBar* tb, wxMenuBar* mb);
virtual void onUpdateUI(wxUpdateUIEvent&);
virtual void onCommand(int id);
// --------------------------------------------------- : Clipboard
/*
virtual bool canCut() const;
virtual bool canCopy() const;
virtual bool canPaste() const;
virtual void doCut();
virtual void doCopy();
virtual void doPaste();
*/
protected:
virtual void onChangeSet();
private:
DECLARE_EVENT_TABLE();
wxSplitterWindow* splitter;
MessageCtrl* messages;
wxPanel* entry_panel;
wxTextCtrl* entry;
void get_pending_errors();
void exec(String const& code);
};
// ----------------------------------------------------------------------------- : EOF
#endif
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <gui/set/keywords_panel.hpp> #include <gui/set/keywords_panel.hpp>
#include <gui/set/stats_panel.hpp> #include <gui/set/stats_panel.hpp>
#include <gui/set/random_pack_panel.hpp> #include <gui/set/random_pack_panel.hpp>
#include <gui/set/console_panel.hpp>
#include <gui/control/card_list.hpp> #include <gui/control/card_list.hpp>
#include <gui/control/card_viewer.hpp> #include <gui/control/card_viewer.hpp>
#include <gui/control/gallery_list.hpp> #include <gui/control/gallery_list.hpp>
...@@ -145,11 +146,12 @@ SetWindow::SetWindow(Window* parent, const SetP& set) ...@@ -145,11 +146,12 @@ SetWindow::SetWindow(Window* parent, const SetP& set)
// panels // panels
addPanel(menuWindow, tabBar, new CardsPanel (this, wxID_ANY), 0, _("window_cards"), _("cards tab")); addPanel(menuWindow, tabBar, new CardsPanel (this, wxID_ANY), 0, _("window_cards"), _("cards tab"));
addPanel(menuWindow, tabBar, new SetInfoPanel (this, wxID_ANY), 1, _("window_set_info"), _("set info tab")); addPanel(menuWindow, tabBar, new StylePanel (this, wxID_ANY), 1, _("window_style"), _("style tab"));
addPanel(menuWindow, tabBar, new StylePanel (this, wxID_ANY), 2, _("window_style"), _("style tab")); addPanel(menuWindow, tabBar, new SetInfoPanel (this, wxID_ANY), 2, _("window_set_info"), _("set info tab"));
addPanel(menuWindow, tabBar, new KeywordsPanel (this, wxID_ANY), 3, _("window_keywords"), _("keywords tab")); addPanel(menuWindow, tabBar, new KeywordsPanel (this, wxID_ANY), 3, _("window_keywords"), _("keywords tab"));
addPanel(menuWindow, tabBar, new StatsPanel (this, wxID_ANY), 4, _("window_statistics"), _("stats tab")); addPanel(menuWindow, tabBar, new StatsPanel (this, wxID_ANY), 4, _("window_statistics"), _("stats tab"));
addPanel(menuWindow, tabBar, new RandomPackPanel(this, wxID_ANY), 5, _("window_random_pack"),_("random pack tab")); addPanel(menuWindow, tabBar, new RandomPackPanel(this, wxID_ANY), 5, _("window_random_pack"),_("random pack tab"));
addPanel(menuWindow, tabBar, new ConsolePanel (this, wxID_ANY), 6, _("window_console"), _("console tab"));
selectPanel(ID_WINDOW_CARDS); // select cards panel selectPanel(ID_WINDOW_CARDS); // select cards panel
// loose ends // loose ends
...@@ -778,7 +780,6 @@ void SetWindow::onChildMenu(wxCommandEvent& ev) { ...@@ -778,7 +780,6 @@ void SetWindow::onChildMenu(wxCommandEvent& ev) {
void SetWindow::onIdle(wxIdleEvent& ev) { void SetWindow::onIdle(wxIdleEvent& ev) {
// Stuff that must be done in the main thread // Stuff that must be done in the main thread
handle_pending_errors();
show_update_dialog(this); show_update_dialog(this);
} }
......
...@@ -77,7 +77,7 @@ wxThread::ExitCode ThumbnailThreadWorker::Entry() { ...@@ -77,7 +77,7 @@ wxThread::ExitCode ThumbnailThreadWorker::Entry() {
try { try {
img = current->generate(); img = current->generate();
} catch (const Error& e) { } catch (const Error& e) {
handle_error(e, false, false); handle_error(e);
} catch (...) { } catch (...) {
} }
// store in cache // store in cache
...@@ -150,7 +150,7 @@ void ThumbnailThread::request(const ThumbnailRequestP& request) { ...@@ -150,7 +150,7 @@ void ThumbnailThread::request(const ThumbnailRequestP& request) {
try { try {
img = request->generate(); img = request->generate();
} catch (const Error& e) { } catch (const Error& e) {
handle_error(e, false, false); handle_error(e);
} catch (...) { } catch (...) {
} }
// store in cache // store in cache
......
...@@ -186,7 +186,7 @@ void DropDownChoiceListBase::generateThumbnailImages() { ...@@ -186,7 +186,7 @@ void DropDownChoiceListBase::generateThumbnailImages() {
GeneratedImageP img = image_from_script(style().image.getValidScriptP()->eval(ctx)); GeneratedImageP img = image_from_script(style().image.getValidScriptP()->eval(ctx));
style().choice_images.insert(make_pair(name, ScriptableImage(img))); style().choice_images.insert(make_pair(name, ScriptableImage(img)));
} catch (const Error& e) { } catch (const Error& e) {
handle_error(Error(e.what() + _("\n while generating choice images for drop down list")),true,false); handle_error(Error(e.what() + _("\n while generating choice images for drop down list")));
} }
} }
} }
......
...@@ -27,7 +27,9 @@ ...@@ -27,7 +27,9 @@
WelcomeWindow::WelcomeWindow() WelcomeWindow::WelcomeWindow()
: Frame(nullptr, wxID_ANY, _TITLE_("magic set editor"), wxDefaultPosition, wxSize(520,380), wxDEFAULT_DIALOG_STYLE | wxTAB_TRAVERSAL | wxCLIP_CHILDREN ) : Frame(nullptr, wxID_ANY, _TITLE_("magic set editor"), wxDefaultPosition, wxSize(520,380), wxDEFAULT_DIALOG_STYLE | wxTAB_TRAVERSAL | wxCLIP_CHILDREN )
, logo (load_resource_image(_("about"))) , logo (load_resource_image(_("about")))
#if USE_BETA_LOGO
, logo2(load_resource_image(_("two_beta"))) , logo2(load_resource_image(_("two_beta")))
#endif
{ {
SetIcon(load_resource_icon(_("app"))); SetIcon(load_resource_icon(_("app")));
...@@ -86,7 +88,9 @@ void WelcomeWindow::draw(DC& dc) { ...@@ -86,7 +88,9 @@ void WelcomeWindow::draw(DC& dc) {
dc.DrawRectangle(0, 0, ws.GetWidth(), ws.GetHeight()); dc.DrawRectangle(0, 0, ws.GetWidth(), ws.GetHeight());
// draw logo // draw logo
dc.DrawBitmap(logo, (ws.GetWidth() - logo.GetWidth()) / 2, 5); dc.DrawBitmap(logo, (ws.GetWidth() - logo.GetWidth()) / 2, 5);
dc.DrawBitmap(logo2, ws.GetWidth() - logo2.GetWidth(), ws.GetHeight() - logo2.GetHeight()); #if USE_BETA_LOGO
dc.DrawBitmap(logo2, ws.GetWidth() - logo2.GetWidth(), ws.GetHeight() - logo2.GetHeight());
#endif
// draw version number // draw version number
dc.SetFont(wxFont(8, wxSWISS, wxNORMAL, wxNORMAL, false, _("Arial"))); dc.SetFont(wxFont(8, wxSWISS, wxNORMAL, wxNORMAL, false, _("Arial")));
dc.SetTextForeground(Color(0,126,176)); dc.SetTextForeground(Color(0,126,176));
......
...@@ -538,6 +538,14 @@ ...@@ -538,6 +538,14 @@
RelativePath=".\gui\set\cards_panel.hpp" RelativePath=".\gui\set\cards_panel.hpp"
> >
</File> </File>
<File
RelativePath=".\gui\set\console_panel.cpp"
>
</File>
<File
RelativePath=".\gui\set\console_panel.hpp"
>
</File>
<File <File
RelativePath=".\gui\set\keywords_panel.cpp" RelativePath=".\gui\set\keywords_panel.cpp"
> >
......
...@@ -53,7 +53,7 @@ void DataViewer::draw(RotatedDC& dc, const Color& background) { ...@@ -53,7 +53,7 @@ void DataViewer::draw(RotatedDC& dc, const Color& background) {
changed_content_properties = true; changed_content_properties = true;
} }
} catch (const Error& e) { } catch (const Error& e) {
handle_error(e, false, false); handle_error(e);
} }
} }
} }
...@@ -67,7 +67,7 @@ void DataViewer::draw(RotatedDC& dc, const Color& background) { ...@@ -67,7 +67,7 @@ void DataViewer::draw(RotatedDC& dc, const Color& background) {
try { try {
drawViewer(dc, *v); drawViewer(dc, *v);
} catch (const Error& e) { } catch (const Error& e) {
handle_error(e, false, false); handle_error(e);
} }
} }
} }
...@@ -91,7 +91,7 @@ void DataViewer::updateStyles(bool only_content_dependent) { ...@@ -91,7 +91,7 @@ void DataViewer::updateStyles(bool only_content_dependent) {
} }
} }
} catch (const Error& e) { } catch (const Error& e) {
handle_error(e, false, false); handle_error(e);
} }
} }
......
...@@ -36,9 +36,7 @@ void ImageValueViewer::draw(RotatedDC& dc) { ...@@ -36,9 +36,7 @@ void ImageValueViewer::draw(RotatedDC& dc) {
if (image.LoadFile(*image_file)) { if (image.LoadFile(*image_file)) {
image.Rescale(w, h); image.Rescale(w, h);
} }
} catch (Error e) { } CATCH_ALL_ERRORS(false);
handle_error(e, false, false); // don't handle now, we are in onPaint
}
} }
// nice placeholder // nice placeholder
if (!image.Ok() && style().default_image.isReady()) { if (!image.Ok() && style().default_image.isReady()) {
......
# This file contains the keys expected to be in MSE locales # This file contains the keys expected to be in MSE locales
# It was automatically generated by tools/locale/locale.pl # It was automatically generated by tools/locale/locale.pl
# Generated on Sun Jan 16 14:30:12 2011 # Generated on Thu Jan 20 21:48:58 2011
action: action:
add control point: 0 add control point: 0
add item: 1 add item: 1
add symmetry: 0 add symmetry: 0
auto replace: 0 auto replace: 0
backspace: 0 backspace: 0
change: 1 change: 1
change combine mode: 0 change combine mode: 0
change shape name: 0 change shape name: 0
change symmetry copies: 0 change symmetry copies: 0
change symmetry type: 0 change symmetry type: 0
convert to curve: 0 convert to curve: 0
convert to line: 0 convert to line: 0
correct: 0 correct: 0
cut: 0 cut: 0
delete: 0 delete: 0
delete point: 0 delete point: 0
delete points: 0 delete points: 0
duplicate: 1 duplicate: 1
enter: 0 enter: 0
group parts: 0 group parts: 0
insert symbol: 0 insert symbol: 0
lock point: 0 lock point: 0
move: 1 move: 1
move curve: 0 move curve: 0
move handle: 0 move handle: 0
move symmetry center: 0 move symmetry center: 0
move symmetry handle: 0 move symmetry handle: 0
paste: 0 paste: 0
remove item: 1 remove item: 1
reorder parts: 0 reorder parts: 0
rotate: 1 rotate: 1
scale: 1 scale: 1
shear: 1 shear: 1
soft line break: 0 soft line break: 0
typing: 0 typing: 0
ungroup parts: 0 ungroup parts: 0
button: button:
add custom pack: 0 add custom pack: 0
add item: 0 add item: 0
always: 0 always: 0
browse: 0 browse: 0
check now: 0 check now: 0
check updates: 0 check updates: 0
close: 0 close: 0
defaults: 0 defaults: 0
don't install package: 0 don't install package: 0
edit symbol: 0 edit symbol: 0
enabled: 0 enabled: 0
export custom cards selection: 0 export custom cards selection: 0
export entire set: 0 export entire set: 0
export generated packs: 0 export generated packs: 0
fixed seed: 0 fixed seed: 0
generate pack: 0 generate pack: 0
hide: 0 hide: 0
high quality: 0 high quality: 0
if internet connection exists: 0 if internet connection exists: 0
insert parameter: 0 insert parameter: 0
install group: optional, 0 install group: optional, 0
install package: 0 install package: 0
keep old: 0 keep old: 0
keep package: 0 keep package: 0
last opened set: 0 last opened set: 0
move down: 0 move down: 0
move up: 0 move up: 0
never: 0 never: 0
new set: 0 new set: 0
number: 0 number: 0
number overwrite: 0 number overwrite: 0
open set: 0 open set: 0
open sets in new window: 0 open sets in new window: 0
overwrite: 0 overwrite: 0
random seed: 0 random seed: 0
refer parameter: 0 refer parameter: 0
reinstall package: 0 reinstall package: 0
remove group: optional, 0 remove group: optional, 0
remove item: 0 remove item: 0
remove package: 0 remove package: 0
select: optional, 0 select: optional, 0
select all: 0 select all: 0
select cards: 0 select cards: 0
select none: 0 select none: 0
show: 0 show: 0
show editing hints: 0 show editing hints: 0
show lines: 0 show lines: 0
spellcheck enabled: 0 spellcheck enabled: 0
symbol gallery: optional, 0 symbol gallery: optional, 0
upgrade group: optional, 0 upgrade group: optional, 0
upgrade package: 0 upgrade package: 0
use auto replace: 0 use auto replace: 0
use custom styling options: 0 use custom styling options: 0
use for all cards: 0 use for all cards: 0
whole word: 0 whole word: 0
zoom export: 0 zoom export: 0
error: error:
aborting parsing: 0 aborting parsing: 0
can't convert: 2 can't convert: 2
can't convert value: 3 can't convert value: 3
can't download installer: 2 can't download installer: 2
cannot create file: 1 cannot create file: 1
change packages successful: 1 change packages successful: 1
checking updates failed: 0 checking updates failed: 0
coordinates for blending overlap: 0 coordinates for blending overlap: 0
dependency not given: 4 dependency not given: 4
dimension not found: 1 dimension not found: 1
downloading updates: 0 downloading updates: 0
expected key: 1 expected key: 1
file not found: 2 file not found: 2
file not found package like: 2 file not found package like: 2
file parse error: 2 file parse error: 2
has no member: 2 has no member: 2
has no member value: 2 has no member value: 2
images used for blending must have the same size: 0 images used for blending must have the same size: 0
in function: 2 in function: 2
in keyword reminder: 2 in keyword reminder: 2
in parameter: 2 in parameter: 2
install packages successful: 1 install packages successful: 1
installing updates: 0 installing updates: 0
newer version: 2 newer version: 2
no game specified: 1 no game specified: 1
no stylesheet specified for the set: 0 no stylesheet specified for the set: 0
no updates: 0 no updates: 0
pack type duplicate name: 1 pack type duplicate name: 1
pack type not found: 1 pack type not found: 1
package not found: 1 package not found: 1
package out of date: 3 package out of date: 3
package too new: 4 package too new: 4
remove packages: 1 remove packages: 1
remove packages modified: 2 remove packages modified: 2
remove packages successful: 1 remove packages successful: 1
stylesheet and set refer to different game: 0 stylesheet and set refer to different game: 0
successful install: optional, 2 successful install: optional, 2
unable to open output file: 0 unable to open output file: 0
unable to store file: 0 unable to store file: 0
unrecognized value: 2 unrecognized value: 2
unsupported field type: 1 unsupported field type: 1
unsupported fill type: 1 unsupported fill type: 1
unsupported format: 1 unsupported format: 1
word list type not found: 1 word list type not found: 1
help: help:
about: 0 about: 0
add card: 0 add card: 0
add cards: 0 add cards: 0
add keyword: 0 add keyword: 0
add symmetry: 0 add symmetry: 0
add to dictionary: optional, 0 add to dictionary: optional, 0
app language: 0 app language: 0
auto replace: 0 auto replace: 0
bar: 0 bar: 0
basic shapes: 0 basic shapes: 0
bold: 0 bold: 0
border: 0 border: 0
card list columns: 0 card list columns: 0
cards tab: 0 cards tab: 0
check updates: 0 check updates: 0
click to select shape: 0 click to select shape: 0
close symbol editor: 0 close symbol editor: 0
collapse notes: 0 collapse notes: 0
copies: 0 console tab: 0
copy: 0 copies: 0
copy card: 0 copy: 0
copy keyword: 0 copy card: 0
curve segment: 0 copy keyword: 0
cut: 0 curve segment: 0
cut card: 0 cut: 0
cut keyword: 0 cut card: 0
difference: 0 cut keyword: 0
drag to draw shape: 0 difference: 0
drag to move curve: 0 drag to draw shape: 0
drag to move line: 0 drag to move curve: 0
drag to move point: 0 drag to move line: 0
drag to resize: 1 drag to move point: 0
drag to rotate: 1 drag to resize: 1
drag to shear: 1 drag to rotate: 1
draw ellipse: 0 drag to shear: 1
draw polygon: 0 draw ellipse: 0
draw rectangle: 0 draw polygon: 0
draw star: 0 draw rectangle: 0
duplicate: 0 draw star: 0
edit pack type: 0 duplicate: 0
ellipse: 0 edit pack type: 0
exit: 0 ellipse: 0
expand notes: 0 exit: 0
export: 0 expand notes: 0
export apprentice: 0 export: 0
export html: 0 export apprentice: 0
export image: 0 export html: 0
export images: 0 export image: 0
export mws: 0 export images: 0
filename format: 0 export mws: 0
find: 0 filename format: 0
find next: 0 find: 0
fixed seed: 0 find next: 0
free point: 0 fixed seed: 0
grid: 0 free point: 0
group: 0 grid: 0
index: 0 group: 0
intersect: 0 index: 0
italic: 0 intersect: 0
keywords tab: 0 italic: 0
last opened set: 1 keywords tab: 0
line segment: 0 last opened set: 1
merge: 0 line segment: 0
new set: 0 merge: 0
new symbol: 0 new set: 0
new window: 0 new symbol: 0
next card: 0 new window: 0
next keyword: 0 next card: 0
no spelling suggestions: 0 next keyword: 0
number of packs: 1 no spelling suggestions: 0
open set: 0 number of packs: 1
open symbol: 0 open set: 0
orientation: 0 open symbol: 0
overlap: 0 orientation: 0
paint: 0 overlap: 0
paste: 0 paint: 0
paste card: 0 paste: 0
paste keyword: 0 paste card: 0
pie: 0 paste keyword: 0
points: 0 pie: 0
polygon: 0 points: 0
preferences: 0 polygon: 0
previous card: 0 preferences: 0
previous keyword: 0 previous card: 0
print: 0 previous keyword: 0
print preview: 0 print: 0
random pack tab: 0 print preview: 0
random seed: 0 random pack tab: 0
rectangle: 0 random seed: 0
redo: 0 rectangle: 0
reflection: 0 redo: 0
reload data: 0 reflection: 0
reminder text: 0 reload data: 0
remove card: 0 reminder text: 0
remove keyword: 0 remove card: 0
remove symmetry: 0 remove keyword: 0
replace: 0 remove symmetry: 0
rotate: 0 replace: 0
rotate 0: 0 rotate: 0
rotate 180: 0 rotate 0: 0
rotate 270: 0 rotate 180: 0
rotate 90: 0 rotate 270: 0
rotate card: 0 rotate 90: 0
rotation: 0 rotate card: 0
save set: 0 rotation: 0
save set as: 0 save set: 0
save symbol: 0 save set as: 0
save symbol as: 0 save symbol: 0
scatter: 0 save symbol as: 0
scatter pie: 0 scatter: 0
seed: 0 scatter pie: 0
select: 0 seed: 0
set code: 0 select: 0
set info tab: 0 set code: 0
show profiler: 0 set info tab: 0
sides: 0 show profiler: 0
smooth point: 0 sides: 0
snap: 0 smooth point: 0
stack: 0 snap: 0
star: 0 stack: 0
stats tab: 0 star: 0
store symbol: 0 stats tab: 0
style tab: 0 store symbol: 0
subtract: 0 style tab: 0
symbols: 0 subtract: 0
symmetric point: 0 symbols: 0
symmetry: 0 symmetric point: 0
undo: 0 symmetry: 0
ungroup: 0 undo: 0
website: 0 ungroup: 0
welcome: 0 website: 0
zoom export: 0 welcome: 0
label: zoom export: 0
app language: 0 label:
apprentice: 0 app language: 0
apprentice exe: 0 apprentice: 0
apprentice export cancelled: 0 apprentice exe: 0
auto match: 0 apprentice export cancelled: 0
auto replace: 0 auto match: 0
card display: 0 auto replace: 0
card notes: 0 card display: 0
check at startup: 0 card notes: 0
checking requires internet: 0 check at startup: 0
columns: 0 checking requires internet: 0
custom size: 0 columns: 0
export filenames: 0 custom size: 0
external programs: 0 export filenames: 0
filename conflicts: 0 external programs: 0
filename format: 0 filename conflicts: 0
filename is ignored: 0 filename format: 0
filter: 0 filename is ignored: 0
fix aspect ratio: 0 filter: 0
force to fit: 0 fix aspect ratio: 0
game type: 0 force to fit: 0
html export options: 0 game type: 0
html template: 0 html export options: 0
install package: 0 html template: 0
installable version: 0 install package: 0
installed version: 0 installable version: 0
installer size: optional, 0 installed version: 0
installer status: optional, 0 installer size: optional, 0
keyword: 0 installer status: optional, 0
language: 0 keyword: 0
magic set editor package: optional, 0 language: 0
match: 0 magic set editor package: optional, 0
mode: 0 match: 0
no version: 0 mode: 0
original: 0 no version: 0
original size: 0 original: 0
pack name: 0 original size: 0
pack selection: 0 pack name: 0
pack totals: 0 pack selection: 0
package action: 0 pack totals: 0
package conflicts: 0 package action: 0
package installable: 0 package conflicts: 0
package installed: 0 package installable: 0
package modified: 0 package installed: 0
package name: 0 package modified: 0
package status: 0 package name: 0
package updates: 0 package status: 0
percent of normal: 0 package updates: 0
reinstall package: 0 percent of normal: 0
reminder: 0 reinstall package: 0
remove package: 0 reminder: 0
result: 0 remove package: 0
rules: 0 result: 0
save changes: 1 rules: 0
search cards: 0 save changes: 1
search keywords: 0 search cards: 0
seed: 0 search keywords: 0
select cards: 0 seed: 0
select cards print: optional, 0 select cards: 0
select columns: 0 select cards print: optional, 0
selected card count: 1 select columns: 0
selection: 0 selected card count: 1
selection height: 0 selection: 0
selection left: 0 selection height: 0
selection top: 0 selection left: 0
selection width: 0 selection top: 0
set code: 0 selection width: 0
sharpen filter: 0 set code: 0
sides: optional, 0 sharpen filter: 0
size: 0 sides: optional, 0
size to fit: 0 size: 0
standard keyword: 1 size to fit: 0
style type: 0 standard keyword: 1
stylesheet not found: 1 style type: 0
styling options: 0 stylesheet not found: 1
total cards: 0 styling options: 0
upgrade package: 0 total cards: 0
uses: 0 upgrade package: 0
windows: 0 uses: 0
zoom: 0 windows: 0
zoom %: 0 zoom: 0
zoom amount: 0 zoom %: 0
zoom amount x: 0 zoom amount: 0
zoom amount y: 0 zoom amount x: 0
menu: zoom amount y: 0
about: 0 menu:
add card: 0 about: 0
add cards: 0 add card: 0
add keyword: 0 add cards: 0
add to dictionary: optional, 0 add keyword: 0
auto replace: 0 add to dictionary: optional, 0
bar: 0 auto replace: 0
basic shapes: 0 bar: 0
bold: 0 basic shapes: 0
card list columns: 0 bold: 0
cards: 0 card list columns: 0
cards tab: 0 cards: 0
check updates: 0 cards tab: 0
close symbol editor: 0 check updates: 0
copy: 0 close symbol editor: 0
cut: 0 console tab: 0
duplicate: 0 copy: 0
edit: 0 cut: 0
exit: 0 duplicate: 0
export: 0 edit: 0
export apprentice: 0 exit: 0
export html: 0 export: 0
export image: 0 export apprentice: 0
export images: 0 export html: 0
export mws: 0 export image: 0
file: 0 export images: 0
find: 0 export mws: 0
find next: 0 file: 0
format: 0 find: 0
graph: 0 find next: 0
group: 0 format: 0
help: 0 graph: 0
index: 0 group: 0
insert symbol: 0 help: 0
italic: 0 index: 0
keywords: 0 insert symbol: 0
keywords tab: 0 italic: 0
new set: 0 keywords: 0
new symbol: 0 keywords tab: 0
new window: 0 new set: 0
next card: 0 new symbol: 0
next keyword: 0 new window: 0
no spelling suggestions: 0 next card: 0
open set: 0 next keyword: 0
open symbol: 0 no spelling suggestions: 0
orientation: 0 open set: 0
paint: 0 open symbol: 0
paste: 0 orientation: 0
pie: 0 paint: 0
points: 0 paste: 0
preferences: 0 pie: 0
previous card: 0 points: 0
previous keyword: 0 preferences: 0
print: 0 previous card: 0
print preview: 0 previous keyword: 0
random pack tab: 0 print: 0
redo: 1 print preview: 0
reload data: 0 random pack tab: 0
reminder text: 0 redo: 1
remove card: 0 reload data: 0
remove keyword: 0 reminder text: 0
replace: 0 remove card: 0
rotate: 0 remove keyword: 0
rotate 0: 0 replace: 0
rotate 180: 0 rotate: 0
rotate 270: 0 rotate 0: 0
rotate 90: 0 rotate 180: 0
save set: 0 rotate 270: 0
save set as: 0 rotate 90: 0
save symbol: 0 save set: 0
save symbol as: 0 save set as: 0
scatter: 0 save symbol: 0
scatter pie: 0 save symbol as: 0
select: 0 scatter: 0
set info tab: 0 scatter pie: 0
show profiler: 0 select: 0
stack: 0 set info tab: 0
stats tab: 0 show profiler: 0
store symbol: 0 stack: 0
style tab: 0 stats tab: 0
symbols: 0 store symbol: 0
symmetry: 0 style tab: 0
tool: 0 symbols: 0
undo: 1 symmetry: 0
ungroup: 0 tool: 0
website: 0 undo: 1
window: 0 ungroup: 0
title: website: 0
%s - magic set editor: 1 window: 0
about: 0 title:
auto replaces: 0 %s - magic set editor: 1
cannot create file: 0 about: 0
custom pack: 0 auto replaces: 0
directories: 0 cannot create file: 0
display: 0 custom pack: 0
export cancelled: 0 directories: 0
export html: 0 display: 0
export images: 0 export cancelled: 0
global: 0 export html: 0
installing updates: 0 export images: 0
locate apprentice: 0 global: 0
magic set editor: 0 installing updates: 0
new set: 0 locate apprentice: 0
open set: 0 magic set editor: 0
packages window: 0 new set: 0
preferences: 0 open set: 0
print preview: 0 packages window: 0
save changes: 0 preferences: 0
save html: 0 print preview: 0
save image: 0 save changes: 0
save set: 0 save html: 0
select cards: 0 save image: 0
select cards export: 0 save set: 0
select columns: 0 select cards: 0
select stylesheet: 0 select cards export: 0
slice image: 0 select columns: 0
symbol editor: 0 select stylesheet: 0
untitled: 0 slice image: 0
update check: 0 symbol editor: 0
updates: 0 untitled: 0
updates available: 0 update check: 0
tool: updates: 0
add symmetry: 0 updates available: 0
basic shapes: 0 tool:
border: 0 add symmetry: 0
cards tab: 0 basic shapes: 0
curve segment: 0 border: 0
difference: 0 cards tab: 0
ellipse: 0 console tab: 0
free point: 0 curve segment: 0
grid: 0 difference: 0
intersect: 0 ellipse: 0
keywords tab: 0 free point: 0
line segment: 0 grid: 0
merge: 0 intersect: 0
overlap: 0 keywords tab: 0
paint: optional, 0 line segment: 0
points: 0 merge: 0
polygon: 0 overlap: 0
random pack tab: 0 paint: optional, 0
rectangle: 0 points: 0
redo: 0 polygon: 0
reflection: 0 random pack tab: 0
remove symmetry: 0 rectangle: 0
rotate: 0 redo: 0
rotation: 0 reflection: 0
select: 0 remove symmetry: 0
set info tab: 0 rotate: 0
smooth point: 0 rotation: 0
snap: 0 select: 0
star: 0 set info tab: 0
stats tab: 0 smooth point: 0
store symbol: 0 snap: 0
style tab: 0 star: 0
subtract: 0 stats tab: 0
symmetric point: 0 store symbol: 0
symmetry: 0 style tab: 0
undo: 0 subtract: 0
tooltip: symmetric point: 0
add card: 0 symmetry: 0
add keyword: 0 undo: 0
add symmetry: 0 tooltip:
bar: 0 add card: 0
basic shapes: 0 add keyword: 0
bold: 0 add symmetry: 0
border: 0 bar: 0
cards tab: 0 basic shapes: 0
copy: 0 bold: 0
curve segment: 0 border: 0
cut: 0 cards tab: 0
difference: 0 console tab: 0
ellipse: 0 copy: 0
export: 0 curve segment: 0
free point: 0 cut: 0
grid: 0 difference: 0
intersect: 0 ellipse: 0
italic: 0 export: 0
keywords tab: 0 free point: 0
line segment: 0 grid: 0
merge: 0 intersect: 0
new set: 0 italic: 0
open set: 0 keywords tab: 0
overlap: 0 line segment: 0
paint: optional, 0 merge: 0
paste: 0 new set: 0
pie: 0 open set: 0
points: 0 overlap: 0
polygon: 0 paint: optional, 0
random pack tab: 0 paste: 0
rectangle: 0 pie: 0
redo: 1 points: 0
reflection: 0 polygon: 0
reminder text: 0 random pack tab: 0
remove card: 0 rectangle: 0
remove keyword: 0 redo: 1
remove symmetry: 0 reflection: 0
rotate: 0 reminder text: 0
rotate card: 0 remove card: 0
rotation: 0 remove keyword: 0
save set: 0 remove symmetry: 0
scatter: 0 rotate: 0
scatter pie: 0 rotate card: 0
select: 0 rotation: 0
set info tab: 0 save set: 0
smooth point: 0 scatter: 0
snap: 0 scatter pie: 0
stack: 0 select: 0
star: 0 set info tab: 0
stats tab: 0 smooth point: 0
store symbol: 0 snap: 0
style tab: 0 stack: 0
subtract: 0 star: 0
symbols: 0 stats tab: 0
symmetric point: 0 store symbol: 0
symmetry: 0 style tab: 0
undo: 1 subtract: 0
type: symbols: 0
boolean: 0 symmetric point: 0
card: 0 symmetry: 0
cards: 0 undo: 1
circle: 0 type:
collection: 0 boolean: 0
collection of: 1 card: 0
color: 0 cards: 0
date: 0 circle: 0
double: 0 collection: 0
ellipse: 0 collection of: 1
export template: 0 color: 0
field: 0 date: 0
function: 0 double: 0
game: 0 ellipse: 0
group: 0 export template: 0
hexagon: 0 field: 0
image: 0 function: 0
integer: 0 game: 0
keyword: 0 group: 0
keywords: 0 hexagon: 0
locale: optional, 0 image: 0
nil: 0 integer: 0
object: 0 keyword: 0
pack: 0 keywords: 0
package: optional, 0 locale: optional, 0
pentagon: 0 nil: 0
point: 0 object: 0
points: 0 pack: 0
polygon: 0 package: optional, 0
rectangle: 0 pentagon: 0
reflection: 0 point: 0
rhombus: 0 points: 0
rotation: 0 polygon: 0
set: 0 rectangle: 0
shape: 0 reflection: 0
shapes: 0 rhombus: 0
square: 0 rotation: 0
star: 0 set: 0
string: 0 shape: 0
style: 0 shapes: 0
stylesheet: 0 square: 0
symbol: 0 star: 0
triangle: 0 string: 0
value: 0 style: 0
stylesheet: 0
symbol: 0
triangle: 0
value: 0
...@@ -66,6 +66,7 @@ tool/window_style IMAGE "tool/window_style.png" ...@@ -66,6 +66,7 @@ tool/window_style IMAGE "tool/window_style.png"
tool/window_keywords IMAGE "tool/window_keywords.png" tool/window_keywords IMAGE "tool/window_keywords.png"
tool/window_statistics IMAGE "tool/window_statistics.png" tool/window_statistics IMAGE "tool/window_statistics.png"
tool/window_random_pack IMAGE "tool/window_random_pack.png" tool/window_random_pack IMAGE "tool/window_random_pack.png"
tool/window_console IMAGE "tool/window_console.png"
tool/help IMAGE "tool/help.png" tool/help IMAGE "tool/help.png"
...@@ -186,6 +187,11 @@ installer_locales IMAGE "../common/installer_locales.png" ...@@ -186,6 +187,11 @@ installer_locales IMAGE "../common/installer_locales.png"
installer_program IMAGE "../common/installer_program.png" installer_program IMAGE "../common/installer_program.png"
//installer_font IMAGE "../common/installer_font.png" //installer_font IMAGE "../common/installer_font.png"
message_input IMAGE "../common/message_input.png"
message_information IMAGE "../common/message_information.png"
message_warning IMAGE "../common/message_warning.png"
message_error IMAGE "../common/message_error.png"
// -------------------------------------------------------- : WX // -------------------------------------------------------- : WX
wxBITMAP_STD_COLOURS BITMAP "wx/msw/colours.bmp" wxBITMAP_STD_COLOURS BITMAP "wx/msw/colours.bmp"
......
...@@ -23,10 +23,10 @@ DECLARE_TYPEOF_COLLECTION(pair<String COMMA ScriptValueP>); ...@@ -23,10 +23,10 @@ DECLARE_TYPEOF_COLLECTION(pair<String COMMA ScriptValueP>);
SCRIPT_FUNCTION(trace) { SCRIPT_FUNCTION(trace) {
SCRIPT_PARAM_C(String, input); SCRIPT_PARAM_C(String, input);
#ifdef _DEBUG #if defined(_DEBUG) && 0
wxLogDebug(_("Trace:\t") + input); wxLogDebug(_("Trace:\t") + input);
#else #else
handle_warning(_("Trace:\t") + input, false); queue_message(MESSAGE_INFO, _("Trace: ") + input);
#endif #endif
SCRIPT_RETURN(input); SCRIPT_RETURN(input);
} }
...@@ -35,7 +35,7 @@ SCRIPT_FUNCTION(warning) { ...@@ -35,7 +35,7 @@ SCRIPT_FUNCTION(warning) {
SCRIPT_PARAM_C(String, input); SCRIPT_PARAM_C(String, input);
SCRIPT_PARAM_DEFAULT_C(bool, condition, true); SCRIPT_PARAM_DEFAULT_C(bool, condition, true);
if (condition) { if (condition) {
handle_warning(input, true); queue_message(MESSAGE_WARNING, input);
} }
return script_nil; return script_nil;
} }
...@@ -51,7 +51,7 @@ SCRIPT_FUNCTION(warning_if_neq) { ...@@ -51,7 +51,7 @@ SCRIPT_FUNCTION(warning_if_neq) {
try { try {
s2 = v2->toCode(); s2 = v2->toCode();
} catch (...) {} } catch (...) {}
handle_warning(input + s1 + _(" != ") + s2, true); queue_message(MESSAGE_WARNING, input + s1 + _(" != ") + s2);
} }
return script_nil; return script_nil;
} }
......
...@@ -67,7 +67,7 @@ Context& SetScriptContext::getContext(const StyleSheetP& stylesheet) { ...@@ -67,7 +67,7 @@ Context& SetScriptContext::getContext(const StyleSheetP& stylesheet) {
set.game ->init_script.invoke(*ctx, false); set.game ->init_script.invoke(*ctx, false);
stylesheet->init_script.invoke(*ctx, false); stylesheet->init_script.invoke(*ctx, false);
} catch (const Error& e) { } catch (const Error& e) {
handle_error(e, false, false); handle_error(e);
} }
onInit(stylesheet, ctx); onInit(stylesheet, ctx);
return *ctx; return *ctx;
...@@ -108,7 +108,7 @@ void SetScriptManager::onInit(const StyleSheetP& stylesheet, Context* ctx) { ...@@ -108,7 +108,7 @@ void SetScriptManager::onInit(const StyleSheetP& stylesheet, Context* ctx) {
initDependencies(*ctx, *set.game); initDependencies(*ctx, *set.game);
initDependencies(*ctx, *stylesheet); initDependencies(*ctx, *stylesheet);
} catch (const Error& e) { } catch (const Error& e) {
handle_error(e, false, false); handle_error(e);
} }
} }
...@@ -258,7 +258,7 @@ void SetScriptManager::updateStyles(Context& ctx, const IndexMap<FieldP,StyleP>& ...@@ -258,7 +258,7 @@ void SetScriptManager::updateStyles(Context& ctx, const IndexMap<FieldP,StyleP>&
} }
} catch (const ScriptError& e) { } catch (const ScriptError& e) {
// NOTE: don't handle errors now, we are likely in an onPaint handler // NOTE: don't handle errors now, we are likely in an onPaint handler
handle_error(ScriptError(e.what() + _("\n while updating styles for '") + s->fieldP->name + _("'")), false, false); handle_error(ScriptError(e.what() + _("\n while updating styles for '") + s->fieldP->name + _("'")));
} }
} }
} }
...@@ -298,7 +298,7 @@ void SetScriptManager::updateAll() { ...@@ -298,7 +298,7 @@ void SetScriptManager::updateAll() {
PROFILER2( v->fieldP.get(), _("update set.") + v->fieldP->name ); PROFILER2( v->fieldP.get(), _("update set.") + v->fieldP->name );
v->update(ctx); v->update(ctx);
} catch (const ScriptError& e) { } catch (const ScriptError& e) {
handle_error(ScriptError(e.what() + _("\n while updating set value '") + v->fieldP->name + _("'")), false, true); handle_error(ScriptError(e.what() + _("\n while updating set value '") + v->fieldP->name + _("'")));
} }
} }
// update card data of all cards // update card data of all cards
...@@ -312,7 +312,7 @@ void SetScriptManager::updateAll() { ...@@ -312,7 +312,7 @@ void SetScriptManager::updateAll() {
#endif #endif
v->update(ctx); v->update(ctx);
} catch (const ScriptError& e) { } catch (const ScriptError& e) {
handle_error(ScriptError(e.what() + _("\n while updating card value '") + v->fieldP->name + _("'")), false, true); handle_error(ScriptError(e.what() + _("\n while updating card value '") + v->fieldP->name + _("'")));
} }
} }
} }
...@@ -347,7 +347,7 @@ void SetScriptManager::updateToUpdate(const ToUpdate& u, deque<ToUpdate>& to_upd ...@@ -347,7 +347,7 @@ void SetScriptManager::updateToUpdate(const ToUpdate& u, deque<ToUpdate>& to_upd
try { try {
changes = u.value->update(ctx); changes = u.value->update(ctx);
} catch (const ScriptError& e) { } catch (const ScriptError& e) {
handle_error(ScriptError(e.what() + _("\n while updating value '") + u.value->fieldP->name + _("'")), false, true); handle_error(ScriptError(e.what() + _("\n while updating value '") + u.value->fieldP->name + _("'")));
} }
if (changes) { if (changes) {
// changed, send event // changed, send event
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#if wxUSE_STACKWALKER #if wxUSE_STACKWALKER
#include <wx/stackwalk.h> #include <wx/stackwalk.h>
#endif #endif
#include <queue>
DECLARE_TYPEOF_COLLECTION(ScriptParseError); DECLARE_TYPEOF_COLLECTION(ScriptParseError);
...@@ -158,94 +159,45 @@ ScriptParseErrors::ScriptParseErrors(const vector<ScriptParseError>& errors) ...@@ -158,94 +159,45 @@ ScriptParseErrors::ScriptParseErrors(const vector<ScriptParseError>& errors)
// ----------------------------------------------------------------------------- : Error handling // ----------------------------------------------------------------------------- : Error handling
// Errors for which a message box was already shown // messages can be posted from other threads, this mutex protects the message list
vector<String> previous_errors;
vector<String> previous_warnings;
String pending_errors;
String pending_warnings;
DECLARE_TYPEOF_COLLECTION(String);
wxMutex crit_error_handling; wxMutex crit_error_handling;
typedef pair<MessageType,String> Message;
deque<Message> message_queue;
bool show_message_box_for_fatal_errors = true;
bool write_errors_to_cli = false; bool write_errors_to_cli = false;
void show_pending_errors(); void queue_message(MessageType type, String const& msg) {
void show_pending_warnings(); if (write_errors_to_cli && wxThread::IsMain()) {
cli.show_message(type,msg);
void handle_error(const String& e, bool allow_duplicate = true, bool now = true) { return; // TODO: is this the right thing to do?
{
// Thread safety
wxMutexLocker lock(crit_error_handling);
// Check duplicates
if (!allow_duplicate) {
FOR_EACH(pe, previous_errors) {
if (e == pe) return;
}
previous_errors.push_back(e);
}
// Only show errors in the main thread
if (!pending_errors.empty()) pending_errors += _("\n\n");
pending_errors += e;
} }
// show messages if (show_message_box_for_fatal_errors && type == MESSAGE_FATAL_ERROR && wxThread::IsMain()) {
if ((write_errors_to_cli || now) && wxThread::IsMain()) { // bring this to the user's attention right now!
show_pending_warnings(); // warnings are older, show them first wxMessageBox(msg, _("Error"), wxOK | wxICON_ERROR);
show_pending_errors();
} }
// Thread safety
wxMutexLocker lock(crit_error_handling);
// Only show errors in the main thread
message_queue.push_back(make_pair(type,msg));
} }
void handle_error(const Error& e, bool allow_duplicate, bool now) { void handle_error(const Error& e) {
handle_error(e.what(), allow_duplicate, now); queue_message(e.is_fatal() ? MESSAGE_FATAL_ERROR : MESSAGE_ERROR, e.what());
}
void handle_warning(const String& w, bool now) {
{
// Check duplicates
wxMutexLocker lock(crit_error_handling);
// Check duplicates
FOR_EACH(pw, previous_warnings) {
if (w == pw) return;
}
previous_warnings.push_back(w);
// Only show errors in the main thread
if (!pending_warnings.empty()) pending_warnings += _("\n\n");
pending_warnings += w;
}
// show messages
if ((write_errors_to_cli || now) && wxThread::IsMain()) {
show_pending_errors();
show_pending_warnings();
}
} }
void handle_pending_errors() { bool have_queued_message() {
show_pending_errors(); wxMutexLocker lock(crit_error_handling);
show_pending_warnings(); return !message_queue.empty();
} }
void show_pending_errors() { bool get_queued_message(MessageType& type, String& msg) {
assert(wxThread::IsMain()); wxMutexLocker lock(crit_error_handling);
if (crit_error_handling.TryLock() != wxMUTEX_NO_ERROR) if (message_queue.empty()) {
return; return false;
if (!pending_errors.empty()) { } else {
if (write_errors_to_cli) { type = message_queue.back().first;
cli.showError(pending_errors); msg = message_queue.back().second;
} else { message_queue.pop_back();
wxMessageBox(pending_errors, _("Error"), wxOK | wxICON_ERROR); return true;
}
pending_errors.clear();
}
crit_error_handling.Unlock();
}
void show_pending_warnings() {
assert(wxThread::IsMain());
if (crit_error_handling.TryLock() != wxMUTEX_NO_ERROR)
return;
if (!pending_warnings.empty()) {
if (write_errors_to_cli) {
cli.showWarning(pending_warnings);
} else {
wxMessageBox(pending_warnings, _("Warning"), wxOK | wxICON_EXCLAMATION);
}
pending_warnings.clear();
} }
crit_error_handling.Unlock();
} }
...@@ -26,6 +26,8 @@ class Error { ...@@ -26,6 +26,8 @@ class Error {
/// Return the error message /// Return the error message
virtual String what() const; virtual String what() const;
/// Is the message (potentially) fatal?
virtual bool is_fatal() const { return false; }
protected: protected:
String message; ///< The error message String message; ///< The error message
...@@ -36,6 +38,8 @@ class Error { ...@@ -36,6 +38,8 @@ class Error {
class InternalError : public Error { class InternalError : public Error {
public: public:
InternalError(const String& str); InternalError(const String& str);
// not all internal errors are fatal, but we had still better warn the user about them.
virtual bool is_fatal() const { return true; }
}; };
// ----------------------------------------------------------------------------- : File errors // ----------------------------------------------------------------------------- : File errors
...@@ -128,37 +132,62 @@ class ScriptErrorNoMember : public ScriptError { ...@@ -128,37 +132,62 @@ class ScriptErrorNoMember : public ScriptError {
: ScriptError(_ERROR_2_("has no member", type, member)) {} : ScriptError(_ERROR_2_("has no member", type, member)) {}
}; };
// ----------------------------------------------------------------------------- : Error handling // ----------------------------------------------------------------------------- : Bounds checking
/// Should errors be written to stdout? template <typename T>
T& at(vector<T>& x, size_t pos) {
if (pos < x.size()) {
return x[pos];
} else {
throw InternalError(_("vector<T> index out of bounds: %d > %d, where T = ") + typeid(x).name());
}
}
// ----------------------------------------------------------------------------- : Error/message handling
/// Should a popup be shown for internal errors?
extern bool show_message_box_for_fatal_errors;
extern bool write_errors_to_cli; extern bool write_errors_to_cli;
/// Handle an error by showing a message box /// Types/levels of (error)messages
/** If !allow_duplicate and the error is the same as the previous error, does nothing. enum MessageType
* If !now the error is handled by a later call to handle_pending_errors() { MESSAGE_INPUT
, MESSAGE_OUTPUT
, MESSAGE_INFO
, MESSAGE_WARNING
, MESSAGE_ERROR
, MESSAGE_FATAL_ERROR
, MESSAGE_TYPE_MAX
};
/// Queue an (error) message, it can later be retrieved with get_queued_message
/** If the message is a MESSAGE_FATAL_ERROR, and show_message_box_for_fatal_errors==true, then a popup is shown
*/ */
void handle_error(const Error& e, bool allow_duplicate = true, bool now = true); void queue_message(MessageType type, String const& msg);
/// Handle an error by queuing a message
void handle_error(const Error& e);
/// Are there any queued messages?
bool have_queued_message();
/// Handle a warning by showing a message box /// Get the first queued message, or return false
void handle_warning(const String& w, bool now = true); bool get_queued_message(MessageType& type, String& msg);
/// Handle errors and warnings that were not handled immediatly in handleError
/** Should be called repeatedly (e.g. in an onIdle event handler) */
void handle_pending_errors();
/// Make a stack trace for use in InternalErrors /// Make a stack trace for use in InternalErrors
String get_stack_trace(); String get_stack_trace();
/// Catch all types of errors, and pass then to handle_error /// Catch all types of errors, and pass then to handle_error
#define CATCH_ALL_ERRORS(handle_now) \ #define CATCH_ALL_ERRORS(handle_now) \
catch (const Error& e) { \ catch (const Error& e) { \
handle_error(e, false, handle_now); \ handle_error(e); \
} catch (const std::exception& e) { \ } catch (const std::exception& e) { \
/* we don't throw std::exception ourselfs, so this is probably something serious */ \ /* we don't throw std::exception ourselfs, so this is probably something serious */ \
String message(e.what(), IF_UNICODE(wxConvLocal, wxSTRING_MAXLEN) ); \ String message(e.what(), IF_UNICODE(wxConvLocal, wxSTRING_MAXLEN) ); \
handle_error(InternalError(message), false, handle_now); \ handle_error(InternalError(message)); \
} catch (...) { \ } catch (...) { \
handle_error(InternalError(_("An unexpected exception occurred!")), false, handle_now); \ handle_error(InternalError(_("An unexpected exception occurred!"))); \
} }
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
......
...@@ -600,16 +600,16 @@ void Packaged::requireDependency(Packaged* package) { ...@@ -600,16 +600,16 @@ void Packaged::requireDependency(Packaged* package) {
FOR_EACH(dep, dependencies) { FOR_EACH(dep, dependencies) {
if (dep->package == n) { if (dep->package == n) {
if (package->version < dep->version) { if (package->version < dep->version) {
handle_warning(_ERROR_3_("package out of date", n, package->version.toString(), dep->version.toString()), false); queue_message(MESSAGE_WARNING,_ERROR_3_("package out of date", n, package->version.toString(), dep->version.toString()));
} else if (package->compatible_version > dep->version) { } else if (package->compatible_version > dep->version) {
handle_warning(_ERROR_4_("package too new", n, package->version.toString(), dep->version.toString(), relativeFilename()), false); queue_message(MESSAGE_WARNING,_ERROR_4_("package too new", n, package->version.toString(), dep->version.toString(), relativeFilename()));
} else { } else {
return; // ok return; // ok
} }
} }
} }
// dependency not found // dependency not found
handle_warning(_ERROR_4_("dependency not given", name(), package->relativeFilename(), package->relativeFilename(), package->version.toString()), false); queue_message(MESSAGE_WARNING,_ERROR_4_("dependency not given", name(), package->relativeFilename(), package->relativeFilename(), package->version.toString()));
} }
// ----------------------------------------------------------------------------- : IncludePackage // ----------------------------------------------------------------------------- : IncludePackage
......
...@@ -153,20 +153,20 @@ bool PackageManager::checkDependency(const PackageDependency& dep, bool report_e ...@@ -153,20 +153,20 @@ bool PackageManager::checkDependency(const PackageDependency& dep, bool report_e
// mse package? // mse package?
if (dep.package == mse_package) { if (dep.package == mse_package) {
if (app_version < dep.version) { if (app_version < dep.version) {
handle_warning(_ERROR_3_("package out of date", _("Magic Set Editor"), app_version.toString(), dep.version.toString()),false); queue_message(MESSAGE_WARNING, _ERROR_3_("package out of date", _("Magic Set Editor"), app_version.toString(), dep.version.toString()));
} }
return true; return true;
} }
// does the package exist? // does the package exist?
if (!local.exists(dep.package) && !global.exists(dep.package)) { if (!local.exists(dep.package) && !global.exists(dep.package)) {
if (report_errors) if (report_errors)
handle_warning(_ERROR_1_("package not found", dep.package),false); queue_message(MESSAGE_WARNING, _ERROR_1_("package not found", dep.package));
return false; return false;
} }
PackagedP package = openAny(dep.package, true); PackagedP package = openAny(dep.package, true);
if (package->version < dep.version) { if (package->version < dep.version) {
if (report_errors) if (report_errors)
handle_warning(_ERROR_3_("package out of date", dep.package, package->version.toString(), dep.version.toString()),false); queue_message(MESSAGE_WARNING, _ERROR_3_("package out of date", dep.package, package->version.toString(), dep.version.toString()));
return false; return false;
} }
return true; return true;
...@@ -378,7 +378,7 @@ bool PackageDirectory::install(const InstallablePackage& package) { ...@@ -378,7 +378,7 @@ bool PackageDirectory::install(const InstallablePackage& package) {
bool PackageDirectory::actual_install(const InstallablePackage& package, const String& install_dir) { bool PackageDirectory::actual_install(const InstallablePackage& package, const String& install_dir) {
String name = package.description->name; String name = package.description->name;
if (!package.installer->installer) { if (!package.installer->installer) {
handle_warning(_("Installer not found for package: ") + name); queue_message(MESSAGE_ERROR, _("Installer not found for package: ") + name);
return false; return false;
} }
Installer& installer = *package.installer->installer; Installer& installer = *package.installer->installer;
......
...@@ -61,7 +61,7 @@ void Reader::handleAppVersion() { ...@@ -61,7 +61,7 @@ void Reader::handleAppVersion() {
if (enterBlock(_("mse_version"))) { if (enterBlock(_("mse_version"))) {
handle(file_app_version); handle(file_app_version);
if (app_version < file_app_version) { if (app_version < file_app_version) {
handle_warning(_ERROR_2_("newer version", filename, file_app_version.toString()), false); queue_message(MESSAGE_WARNING, _ERROR_2_("newer version", filename, file_app_version.toString()));
} }
exitBlock(); exitBlock();
} }
...@@ -75,7 +75,7 @@ void Reader::warning(const String& msg, int line_number_delta, bool warn_on_prev ...@@ -75,7 +75,7 @@ void Reader::warning(const String& msg, int line_number_delta, bool warn_on_prev
void Reader::showWarnings() { void Reader::showWarnings() {
if (!warnings.empty()) { if (!warnings.empty()) {
handle_warning(_("Warnings while reading file:\n") + filename + _("\n") + warnings, false); queue_message(MESSAGE_WARNING, _("Warnings while reading file:\n") + filename + _("\n") + warnings);
warnings.clear(); warnings.clear();
} }
} }
......
...@@ -598,12 +598,12 @@ void check_tagged(const String& str, bool check_balance) { ...@@ -598,12 +598,12 @@ void check_tagged(const String& str, bool check_balance) {
if (str.GetChar(i) == _('<')) { if (str.GetChar(i) == _('<')) {
size_t end = skip_tag(str,i); size_t end = skip_tag(str,i);
if (end == String::npos) { if (end == String::npos) {
handle_warning(_("Invalid tagged string: missing '>'"),false); queue_message(MESSAGE_WARNING, _("Invalid tagged string: missing '>'"));
} }
for (size_t j = i + 1 ; j + 1 < end ; ++j) { for (size_t j = i + 1 ; j + 1 < end ; ++j) {
Char c = str.GetChar(j); Char c = str.GetChar(j);
if (c == _(' ') || c == _('<')) { if (c == _(' ') || c == _('<')) {
handle_warning(_("Invalid character in tag"),false); queue_message(MESSAGE_WARNING, _("Invalid character in tag"));
} }
} }
if (check_balance) { if (check_balance) {
...@@ -614,7 +614,7 @@ void check_tagged(const String& str, bool check_balance) { ...@@ -614,7 +614,7 @@ void check_tagged(const String& str, bool check_balance) {
} else { } else {
size_t close = match_close_tag(str,i); size_t close = match_close_tag(str,i);
if (close == String::npos) { if (close == String::npos) {
handle_warning(_("Invalid tagged string: missing close tag for <") + tag_at(str,i) + _(">"),false); queue_message(MESSAGE_WARNING, _("Invalid tagged string: missing close tag for <") + tag_at(str,i) + _(">"));
} }
} }
} }
......
...@@ -50,7 +50,7 @@ void SubversionVCS::removeFile(const wxFileName& filename) ...@@ -50,7 +50,7 @@ void SubversionVCS::removeFile(const wxFileName& filename)
{ {
String name = filename.GetFullPath(); String name = filename.GetFullPath();
const Char* name_c[] = {_("svn"), _("rm"), name.c_str(), nullptr}; const Char* name_c[] = {_("svn"), _("rm"), name.c_str(), nullptr};
handle_warning(String(name_c[0]) + name_c[1] + name_c[2]); queue_message(MESSAGE_WARNING, String(name_c[0]) + name_c[1] + name_c[2]);
// TODO: do we really need to remove the file before calling "svn remove"? // TODO: do we really need to remove the file before calling "svn remove"?
VCS::removeFile(filename); VCS::removeFile(filename);
if (!run_svn(name_c)) { if (!run_svn(name_c)) {
......
...@@ -207,6 +207,9 @@ enum ChildMenuID { ...@@ -207,6 +207,9 @@ enum ChildMenuID {
, ID_GENERATE_PACK , ID_GENERATE_PACK
, ID_CUSTOM_PACK , ID_CUSTOM_PACK
// Console panel
, ID_EVALUATE
// SymbolFont (Format menu) // SymbolFont (Format menu)
, ID_INSERT_SYMBOL_MENU_MIN = 9001 , ID_INSERT_SYMBOL_MENU_MIN = 9001
, ID_INSERT_SYMBOL_MENU_MAX = 10000 , ID_INSERT_SYMBOL_MENU_MAX = 10000
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment