| /////////////////////////////////////////////////////////////////////// |
| // File: varabled.cpp |
| // Description: Variables Editor |
| // Author: Joern Wanke |
| // Created: Wed Jul 18 10:05:01 PDT 2007 |
| // |
| // (C) Copyright 2007, Google Inc. |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| /////////////////////////////////////////////////////////////////////// |
| // |
| // The variables editor is used to edit all the variables used within |
| // tesseract from the ui. |
| #ifndef GRAPHICS_DISABLED |
| #include "varabled.h" |
| |
| #ifdef WIN32 |
| #else |
| #include <stdlib.h> |
| #include <stdio.h> |
| #endif |
| |
| #include <map> |
| |
| #include "scrollview.h" |
| #include "svmnode.h" |
| |
| #include "varable.h" |
| #include "mainblk.h" |
| |
| #define VARDIR "configs/" /*variables files */ |
| #define MAX_ITEMS_IN_SUBMENU 30 |
| |
| const ERRCODE NO_VARIABLES_TO_EDIT = "No Variables defined to edit"; |
| |
| // Contains the mappings from unique VC ids to their actual pointers. |
| static std::map<int, VariableContent*> vcMap; |
| |
| static int nrVariables = 0; |
| static int writeCommands[2]; |
| |
| ELISTIZE(VariableContent) |
| |
| // Constructors for the various VarTypes. |
| VariableContent::VariableContent(STRING_VARIABLE* it) { |
| my_id_ = nrVariables; |
| nrVariables++; |
| var_type_ = VT_STRING; |
| sIt = it; |
| vcMap[my_id_] = this; |
| } |
| // Constructors for the various VarTypes. |
| VariableContent::VariableContent(INT_VARIABLE* it) { |
| my_id_ = nrVariables; |
| nrVariables++; |
| var_type_ = VT_INTEGER; |
| iIt = it; |
| vcMap[my_id_] = this; |
| } |
| // Constructors for the various VarTypes. |
| VariableContent::VariableContent(BOOL_VARIABLE* it) { |
| my_id_ = nrVariables; |
| nrVariables++; |
| var_type_ = VT_BOOLEAN; |
| bIt = it; |
| vcMap[my_id_] = this; |
| } |
| // Constructors for the various VarTypes. |
| VariableContent::VariableContent(double_VARIABLE* it) { |
| my_id_ = nrVariables; |
| nrVariables++; |
| var_type_ = VT_DOUBLE; |
| dIt = it; |
| vcMap[my_id_] = this; |
| } |
| |
| // Gets a VC object identified by its ID. |
| VariableContent* VariableContent::GetVariableContentById(int id) { |
| return vcMap[id]; |
| } |
| |
| // Copy the first N words from the source string to the target string. |
| // Words are delimited by "_". |
| void VariablesEditor::GetFirstWords( |
| const char *s, // source string |
| int n, // number of words |
| char *t // target string |
| ) { |
| int full_length = strlen(s); |
| int reqd_len = 0; // No. of chars requird |
| const char *next_word = s; |
| |
| while ((n > 0) && reqd_len < full_length) { |
| reqd_len += strcspn(next_word, "_") + 1; |
| next_word += reqd_len; |
| n--; |
| } |
| strncpy(t, s, reqd_len); |
| t[reqd_len] = '\0'; // ensure null terminal |
| } |
| |
| // Getter for the name. |
| const char* VariableContent::GetName() const { |
| if (var_type_ == VT_INTEGER) { return iIt->name_str(); } |
| else if (var_type_ == VT_BOOLEAN) { return bIt->name_str(); } |
| else if (var_type_ == VT_DOUBLE) { return dIt->name_str(); } |
| else if (var_type_ == VT_STRING) { return sIt->name_str(); } |
| else |
| return "ERROR: VariableContent::GetName()"; |
| } |
| |
| // Getter for the description. |
| const char* VariableContent::GetDescription() const { |
| if (var_type_ == VT_INTEGER) { return iIt->info_str(); } |
| else if (var_type_ == VT_BOOLEAN) { return bIt->info_str(); } |
| else if (var_type_ == VT_DOUBLE) { return dIt->info_str(); } |
| else if (var_type_ == VT_STRING) { return sIt->info_str(); } |
| else return NULL; |
| } |
| |
| // Getter for the value. |
| const char* VariableContent::GetValue() const { |
| char* msg = new char[1024]; |
| if (var_type_ == VT_INTEGER) { |
| sprintf(msg, "%d", ((inT32) *(iIt))); |
| } else if (var_type_ == VT_BOOLEAN) { |
| sprintf(msg, "%d", ((BOOL8) * (bIt))); |
| } else if (var_type_ == VT_DOUBLE) { |
| sprintf(msg, "%g", ((double) * (dIt))); |
| } else if (var_type_ == VT_STRING) { |
| if (((STRING) * (sIt)).string() != NULL) { |
| sprintf(msg, "%s", ((STRING) * (sIt)).string()); |
| } else { |
| return "Null"; |
| } |
| } |
| return msg; |
| } |
| |
| // Setter for the value. |
| void VariableContent::SetValue(const char* val) { |
| // TODO (wanke) Test if the values actually are properly converted. |
| // (Quickly visible impacts?) |
| changed_ = TRUE; |
| if (var_type_ == VT_INTEGER) { |
| iIt->set_value(atoi(val)); |
| } else if (var_type_ == VT_BOOLEAN) { |
| bIt->set_value(atoi(val)); |
| } else if (var_type_ == VT_DOUBLE) { |
| dIt->set_value(strtod(val, NULL)); |
| } else if (var_type_ == VT_STRING) { |
| sIt->set_value(val); |
| } |
| } |
| |
| // Gets the up to the first 3 prefixes from s (split by _). |
| // For example, tesseract_foo_bar will be split into tesseract,foo and bar. |
| void VariablesEditor::GetPrefixes(const char* s, STRING* level_one, |
| STRING* level_two, |
| STRING* level_three) { |
| char* p = new char[1024]; |
| GetFirstWords(s, 1, p); |
| *level_one = p; |
| GetFirstWords(s, 2, p); |
| *level_two = p; |
| GetFirstWords(s, 3, p); |
| *level_three = p; |
| delete[] p; |
| } |
| |
| // Compare two VC objects by their name. |
| int VariableContent::Compare(const void* v1, const void* v2) { |
| const VariableContent* one = |
| *reinterpret_cast<const VariableContent* const *>(v1); |
| const VariableContent* two = |
| *reinterpret_cast<const VariableContent* const *>(v2); |
| return strcmp(one->GetName(), two->GetName()); |
| } |
| |
| // Find all editable variables used within tesseract and create a |
| // SVMenuNode tree from it. |
| // TODO (wanke): This is actually sort of hackish. |
| SVMenuNode* VariablesEditor::BuildListOfAllLeaves() { // find all variables. |
| SVMenuNode* mr = new SVMenuNode(); |
| VariableContent_LIST vclist; |
| VariableContent_IT vc_it(&vclist); |
| // Amount counts the number of entries for a specific char*. |
| // TODO(rays) get rid of the use of std::map. |
| std::map<const char*, int> amount; |
| |
| INT_VARIABLE_C_IT int_it(INT_VARIABLE::get_head()); |
| BOOL_VARIABLE_C_IT bool_it(BOOL_VARIABLE::get_head()); |
| STRING_VARIABLE_C_IT str_it(STRING_VARIABLE::get_head()); |
| double_VARIABLE_C_IT dbl_it(double_VARIABLE::get_head()); |
| |
| // Add all variables to a list. |
| for (int_it.mark_cycle_pt(); !int_it.cycled_list(); int_it.forward()) { |
| vc_it.add_after_then_move(new VariableContent(int_it.data())); |
| } |
| |
| for (bool_it.mark_cycle_pt(); !bool_it.cycled_list(); bool_it.forward()) { |
| vc_it.add_after_then_move(new VariableContent(bool_it.data())); |
| } |
| |
| for (str_it.mark_cycle_pt(); !str_it.cycled_list(); str_it.forward()) { |
| vc_it.add_after_then_move(new VariableContent(str_it.data())); |
| } |
| |
| for (dbl_it.mark_cycle_pt(); !dbl_it.cycled_list(); dbl_it.forward()) { |
| vc_it.add_after_then_move(new VariableContent(dbl_it.data())); |
| } |
| |
| // Count the # of entries starting with a specific prefix. |
| for (vc_it.mark_cycle_pt(); !vc_it.cycled_list(); vc_it.forward()) { |
| VariableContent* vc = vc_it.data(); |
| STRING tag; |
| STRING tag2; |
| STRING tag3; |
| |
| GetPrefixes(vc->GetName(), &tag, &tag2, &tag3); |
| amount[tag.string()]++; |
| amount[tag2.string()]++; |
| amount[tag3.string()]++; |
| } |
| |
| vclist.sort(VariableContent::Compare); // Sort the list alphabetically. |
| |
| SVMenuNode* other = mr->AddChild("OTHER"); |
| |
| // go through the list again and this time create the menu structure. |
| vc_it.move_to_first(); |
| for (vc_it.mark_cycle_pt(); !vc_it.cycled_list(); vc_it.forward()) { |
| VariableContent* vc = vc_it.data(); |
| STRING tag; |
| STRING tag2; |
| STRING tag3; |
| GetPrefixes(vc->GetName(), &tag, &tag2, &tag3); |
| |
| if (amount[tag.string()] == 1) { other->AddChild(vc->GetName(), vc->GetId(), |
| vc->GetValue(), |
| vc->GetDescription()); |
| } else { // More than one would use this submenu -> create submenu. |
| SVMenuNode* sv = mr->AddChild(tag.string()); |
| if ((amount[tag.string()] <= MAX_ITEMS_IN_SUBMENU) || |
| (amount[tag2.string()] <= 1)) { |
| sv->AddChild(vc->GetName(), vc->GetId(), |
| vc->GetValue(), vc->GetDescription()); |
| } else { // Make subsubmenus. |
| SVMenuNode* sv2 = sv->AddChild(tag2.string()); |
| sv2->AddChild(vc->GetName(), vc->GetId(), |
| vc->GetValue(), vc->GetDescription()); |
| } |
| } |
| } |
| return mr; |
| } |
| |
| // Event listener. Waits for SVET_POPUP events and processes them. |
| void VariablesEditor::Notify(const SVEvent* sve) { |
| if (sve->type == SVET_POPUP) { // only catch SVET_POPUP! |
| char* param = sve->parameter; |
| if (sve->command_id == writeCommands[0]) { |
| WriteVars(param, false); |
| } else if (sve->command_id == writeCommands[1]) { |
| WriteVars(param, true); |
| } else { |
| VariableContent* vc = VariableContent::GetVariableContentById( |
| sve->command_id); |
| vc->SetValue(param); |
| sv_window_->AddMessage("Setting %s to %s", |
| vc->GetName(), vc->GetValue()); |
| } |
| } |
| } |
| |
| // Integrate the variables editor as popupmenu into the existing scrollview |
| // window (usually the pg editor). If sv == null, create a new empty |
| // empty window and attach the variables editor to that window (ugly). |
| VariablesEditor::VariablesEditor(const tesseract::Tesseract* tess, |
| ScrollView* sv) { |
| if (sv == NULL) { |
| const char* name = "VarEditorMAIN"; |
| sv = new ScrollView(name, 1, 1, 200, 200, 300, 200); |
| } |
| |
| sv_window_ = sv; |
| |
| //Only one event handler per window. |
| //sv->AddEventHandler((SVEventHandler*) this); |
| |
| SVMenuNode* svMenuRoot = BuildListOfAllLeaves(); |
| |
| STRING varfile; |
| varfile = tess->datadir; |
| varfile += VARDIR; // variables dir |
| varfile += "edited"; // actual name |
| |
| SVMenuNode* std_menu = svMenuRoot->AddChild ("Build Config File"); |
| |
| writeCommands[0] = nrVariables+1; |
| std_menu->AddChild("All Variables", writeCommands[0], |
| varfile.string(), "Config file name?"); |
| |
| writeCommands[1] = nrVariables+2; |
| std_menu->AddChild ("changed_ Variables Only", writeCommands[1], |
| varfile.string(), "Config file name?"); |
| |
| svMenuRoot->BuildMenu(sv, false); |
| } |
| |
| |
| // Write all (changed_) variables to a config file. |
| void VariablesEditor::WriteVars(char *filename, // in this file |
| bool changes_only // changed_ vars only? |
| ) { |
| FILE *fp; // input file |
| char msg_str[255]; |
| // if file exists |
| if ((fp = fopen (filename, "r")) != NULL) { |
| fclose(fp); |
| sprintf (msg_str, "Overwrite file " "%s" "? (Y/N)", filename); |
| int a = sv_window_->ShowYesNoDialog(msg_str); |
| if (a == 'n') { return; } // dont write |
| } |
| |
| |
| fp = fopen (filename, "w"); // can we write to it? |
| if (fp == NULL) { |
| sv_window_->AddMessage("Cant write to file " "%s" "", filename); |
| return; |
| } |
| |
| for (std::map<int, VariableContent*>::iterator iter = vcMap.begin(); |
| iter != vcMap.end(); |
| ++iter) { |
| VariableContent* cur = iter->second; |
| if (!changes_only || cur->HasChanged()) { |
| fprintf (fp, "%-25s %-12s # %s\n", |
| cur->GetName(), cur->GetValue(), cur->GetDescription()); |
| } |
| } |
| fclose(fp); |
| } |
| #endif |