diff --git a/include/classes.h b/include/classes.h index db1bb9057..aed82d420 100755 --- a/include/classes.h +++ b/include/classes.h @@ -56,6 +56,7 @@ #define CLASS_SLIDER_FIELD 254 #define CLASS_PROP_FIELD 255 #define CLASS_MVC_FIELD 256 +#define CLASS_TREELIST_FIELD 257 #define CLASS_TOOL_FIELD 280 #define CLASS_BUTTON_TOOL 281 diff --git a/include/dongle.cpp b/include/dongle.cpp index 93a3f3cf5..73a84ec33 100755 --- a/include/dongle.cpp +++ b/include/dongle.cpp @@ -1087,32 +1087,12 @@ int Tdninst::test_cmdline(const TString& cmdline, bool key_must_exist, TString& const word codmod = don.module_name2code(strmod); if (codmod == BAAUT) return 0; - - /*if (!don.active(codmod)) - { - msg << TR("Modulo non attivo sulla chiave: ") << strmod; - return 2; - }*/ } } - const TDate oggi(TODAY); - const int solar_year = oggi.year(); - const int dongle_ass = don.year_assist(); - const int dongle_year = assistance_year2solar(dongle_ass); - if (solar_year - dongle_year > 2) - { - msg << TR("Anno di assistenza non valido sulla chiave: ") << dongle_year; - return 3; - } - TEnigma_machine em; const int dninst_ass = em.year_assist(); - if (dongle_ass > dninst_ass) - { - msg << TR("File dninst.zip obsoleto"); - return 4; - } + const TDate oggi(TODAY); bool bFound = false; if (dninst_ass > 2100) @@ -1129,6 +1109,7 @@ int Tdninst::test_cmdline(const TString& cmdline, bool key_must_exist, TString& if (parse_date(dninst_line, key, datascad)) { + const TDate oggi(TODAY); const bool scaduto = datascad < oggi; if (key == "*") { @@ -1202,6 +1183,38 @@ bool Tdninst::can_I_run(const bool is_personal_program) const return test_cmdline(cmdline, me, msg) == 0; } +bool Tdninst::find_serno() const +{ + const word serno = dongle().number(); + if (serno == 0) + return true; + + const TDate oggi(TODAY); + bool good = false; + TEnigma_machine em; + if (em.ok()) + { + if (em.year_assist() > 2100) + { + TToken_string l(80, '='); + good = em.find_serno(serno); + } + else + { + TToken_string l(80, ';'); + while (em.line(l)) + { + if (l.get_long(0) == serno) + { + good = true; + break; + } + } + } + } + return good; +} + bool Tdninst::find_killed(TToken_string& kill_list) const { kill_list.cut(0); @@ -1255,6 +1268,38 @@ bool Tdninst::find_killed(TToken_string& kill_list) const return good; } +bool Tdninst::find_expiring(int days, TString& module, TDate& expires) const +{ + const TDate oggi(TODAY); + + expires = oggi; expires += days; + module.cut(0); + + const word serno = dongle().number(); + if (serno == 0) + return false; + + TEnigma_machine em; + if (em.ok() && em.year_assist() > 2100 && em.find_serno(serno)) + { + TToken_string l(80, '='); + TString16 str; + TDate ds; + while (em.line(l)) + { + if (l.empty() || l[0] == '[') + break; + if (parse_date(l, str, ds) && ds >= oggi && ds <= expires) + { + module = str; + expires = ds; + } + } + } + + return module.full(); +} + Tdninst::Tdninst() : _year_assist(0) { TEnigma_machine s; diff --git a/include/dongle.h b/include/dongle.h index 50bad5747..05e8cd8b5 100755 --- a/include/dongle.h +++ b/include/dongle.h @@ -115,7 +115,10 @@ public: int solar_year() const { return assistance_year2solar(_year_assist); } int test_cmdline(const TString& cmdline, bool key_must_exist, TString& msg) const; bool can_I_run(const bool is_personal_program = false) const; + bool find_serno() const; bool find_killed(TToken_string& kill_list) const; + bool find_expiring(int days, TString& module, TDate& expires) const; + Tdninst(); }; diff --git a/include/mask.cpp b/include/mask.cpp index 9d223a676..623d414c3 100755 --- a/include/mask.cpp +++ b/include/mask.cpp @@ -1102,6 +1102,7 @@ TMask_field* TMask::parse_field(TScanner& scanner) if (k == "SP") return new TSheet_field(this); if (k == "ST") return new TEdit_field(this); if (k == "TE") return new TText_field(this); + if (k == "TL") return new TTreelist_field(this); if (k == "TR") return new TTree_field(this); if (k == "ZO") return new TZoom_field(this); diff --git a/include/tree.h b/include/tree.h index dae078fa8..a30383afb 100755 --- a/include/tree.h +++ b/include/tree.h @@ -5,6 +5,10 @@ #include #endif +#ifndef __VARIANT_H +#include +#endif + class TTree; class TImage; @@ -59,6 +63,7 @@ public: virtual void curr_id(TString& id) const { node2id(curr_node(), id); } virtual bool get_description(TString& desc) const { curr_id(desc); return desc.not_empty(); } + virtual TFieldtypes get_var(const TString& name, TVariant& var) const { return _nullfld; } virtual bool expand(); virtual bool shrink(); diff --git a/include/treectrl.cpp b/include/treectrl.cpp index b5e2935b1..4790097d0 100755 --- a/include/treectrl.cpp +++ b/include/treectrl.cpp @@ -245,6 +245,8 @@ class TTree_window : public TControl_host_window { TTree* _tree; bool _hide_leaves; + +protected: TAuto_token_string _header; private: @@ -1221,3 +1223,359 @@ TField_window* TProp_field::create_window(int x, int y, int dx, int dy, WINDOW p TProp_field::TProp_field(TMask* m) : TWindowed_field(m) { } + +/////////////////////////////////////////////////////////// +// TTreelist_window +/////////////////////////////////////////////////////////// + +class TTreelist_window : public TTree_window +{ + TAuto_token_string _fields; + +private: + virtual void create_children(XVT_TREEVIEW_NODE node); + virtual void handle_tree_event(EVENT* ep); + virtual bool add_child(XVT_TREEVIEW_NODE parent); + +protected: + virtual long handler(WINDOW win, EVENT* ep); + bool get_fields(TToken_string& csv); + +public: + virtual bool select_current(); + virtual bool goto_selected(); + virtual void set_header(const char* head); + virtual void set_fields(const char* flds); + + TTreelist_window(int x, int y, int dx, int dy, WINDOW parent, TTreelist_field* owner); + virtual ~TTreelist_window() { } +}; + +bool TTreelist_window::get_fields(TToken_string& csv) +{ + if (_fields.empty_items()) + return tree()->get_description(csv); + + csv.cut(0); + TVariant var; + FOR_EACH_TOKEN(_fields, str) + { + var.set_null(); + tree()->get_var(str, var); + if (var.is_empty()) + csv.add(" "); + else + csv.add(var.as_string()); + } + + return true; +} + +bool TTreelist_window::add_child(XVT_TREEVIEW_NODE parent) +{ + XVT_TREEVIEW_NODE_TYPE type = tree()->could_have_son() ? XVT_TREEVIEW_NODE_NONTERMINAL + : XVT_TREEVIEW_NODE_TERMINAL; + + XVT_IMAGE ii = NULL, ic = NULL, ie = NULL; + TImage* im_nor = tree()->image(false); + if (im_nor != NULL) + { + if (type == XVT_TREEVIEW_NODE_NONTERMINAL) + { + TImage* im_sel = tree()->image(true); + ic = im_nor->xvt_image(); + ie = im_sel->xvt_image(); + } + else + ii = im_nor->xvt_image(); + } + TToken_string csv(80, '\t'); get_fields(csv); + TString256 id; tree()->curr_id(id); + XVT_TREEVIEW_NODE child = xvt_treelist_add_child_node(_ctrl, parent, type, ii, ic, ie, csv, NULL, id); + if (child != NULL) + { + if (!tree()->enabled()) + xvt_treelist_enable_node(_ctrl, child, FALSE); + if (tree()->marked()) + xvt_treelist_set_node_bold(_ctrl, child, TRUE); + + if (type == XVT_TREEVIEW_NODE_NONTERMINAL && tree()->expanded()) + { + for (bool ok = tree()->goto_firstson(); ok; ok = tree()->goto_rbrother()) + add_child(child); + xvt_treelist_expand_node(_ctrl, child, FALSE); + } + } + + tree()->goto_node(id); + return true; +} + +void TTreelist_window::create_children(XVT_TREEVIEW_NODE node) +{ + bool ok = false; + TString id; + if (tree() != NULL) + { + if (node != NULL) + id = xvt_treelist_get_node_data(_ctrl, node); + if (id.empty()) // Sono sulla radice + { + node = xvt_treelist_get_root_node(_ctrl); + ok = tree()->goto_root(); + } + else + { + tree()->goto_node(id); + ok = tree()->goto_firstson(); + } + } + xvt_treelist_remove_node_children(_ctrl, node); + for (; ok; ok = tree()->goto_rbrother()) + add_child(node); + + // Riposiziona per benino l'alberello + if (id.empty()) + tree()->goto_root(); + else + tree()->goto_node(id); +} + +void TTreelist_window::handle_tree_event(EVENT* ep) +{ + XVT_TREEVIEW_NODE node = ep->v.ctl.ci.v.treeview.node; + const TString id = (const char*)xvt_treelist_get_node_data(_ctrl, node); + if (tree()->goto_node(id)) + { + if (ep->v.ctl.ci.v.treeview.sgl_click || ep->v.ctl.ci.v.treeview.dbl_click) + { + KEY key = K_SPACE; // Single click selection + if (ep->v.ctl.ci.v.treeview.dbl_click) + key += K_CTRL; // Double click selection + if (owner().on_key(key) && tree()->goto_node(id)) + { + // Aggiorna testo ed immagini che possono essere cambiate + XVT_IMAGE ii = NULL, ic = NULL, ie = NULL; + TImage* im_nor = tree()->image(false); + if (tree()->has_son()) + { + TImage* im_sel = tree()->image(true); + ic = im_nor->xvt_image(); + ie = im_sel->xvt_image(); + } + else + ii = im_nor->xvt_image(); + xvt_treelist_set_node_images(_ctrl, node, ii, ic, ie); + TToken_string csv(80, '\t'); get_fields(csv); + xvt_treelist_set_node_string(_ctrl, node, csv); + } + } + else + { + int nWhat = 0; + if (ep->v.ctl.ci.v.treeview.expanded) + nWhat |= 0x1; + if (ep->v.ctl.ci.v.treeview.collapsed) + nWhat |= 0x2; + switch (nWhat) + { + case 0x1: // Expanded + tree()->expand(); + owner().on_key(K_SHIFT + K_SPACE); + break; + case 0x2: // Collapsed + tree()->shrink(); + break; + case 0x3: // Expanding + tree()->expand(); + create_children(node); + owner().on_key(K_SHIFT + K_SPACE); + owner().on_key(K_SPACE); + break; + default : break; + } + } + } +} + +long TTreelist_window::handler(WINDOW win, EVENT* ep) +{ + switch (ep->type) + { + case E_CONTROL: + if (ep->v.ctl.ci.type == WC_TREELIST && tree() != NULL) + { + handle_tree_event(ep); + return 0L; + } + break; + case E_UPDATE: + return 0L; + default: + break; + } + return TControl_host_window::handler(win, ep); +} + +bool TTreelist_window::select_current() +{ + XVT_TREEVIEW_NODE nextsel = NULL; // Nodo da selezionare (se mai lo trovero') + + if (tree() != NULL) + { + TString id; tree()->curr_id(id); // id del nodo corrente dell'albero + + // Controllo se il tree control e' gia' posizionato bene + XVT_TREEVIEW_NODE cursel = xvt_treelist_get_selected_node(_ctrl); + nextsel = xvt_treelist_find_node_string(_ctrl, id); + if (nextsel != NULL && cursel == nextsel) + return true; + + if (nextsel == NULL) + { + xvt_treelist_suspend(_ctrl); // Sospendo le notifiche degli eventi + TString_array a; + a.add(id); + // Creo la lista dei progenitori + while (tree()->goto_father()) + { + const int i = a.add(EMPTY_STRING); + tree()->curr_id(a.row(i)); + tree()->expand(); // Nel caso non fosse gia' espanso + } + + // Scandisco i progenitori partendo dalla radice + XVT_TREEVIEW_NODE parent = NULL; // was xvt_treeview_get_root_node(_ctrl); + bool killed = false; // Ho interrotto "bruscamente" la ricerca? + FOR_EACH_ARRAY_ROW_BACK(a, r, row) + { + if (killed) + break; + for (int i = 0; ; i++) + { + XVT_TREEVIEW_NODE child = xvt_treelist_get_child_node(_ctrl, parent, i); + if (child == NULL && i == 0) // Forse non c'e' nessun figlio ... + { + create_children(parent); // ... sara' vero? + child = xvt_treelist_get_child_node(_ctrl, parent, i); + } + if (child == NULL) // Certamente non ci sono piu' figli + { + //killed = true; // Non ho trovato quello che cercavo: esco subito + break; + } + const char* data = xvt_treelist_get_node_data(_ctrl, child); + if (*row == data) + { + nextsel = child; + if (*row == id) // Ho finito + killed = true; + else + { + parent = child; + xvt_treelist_expand_node(_ctrl, child, FALSE); + } + break; + } + } + } + xvt_treelist_resume(_ctrl); // Riattivo le notifiche degli eventi + tree()->goto_node(id); // Riposiziono l'albero + } + if (nextsel != NULL) + { + xvt_treelist_select_node(_ctrl, nextsel, TRUE); + if (tree()->expanded()) + xvt_treelist_expand_node(_ctrl, nextsel, FALSE); + } + } + return nextsel != NULL; +} + +bool TTreelist_window::goto_selected() +{ + bool ok = false; + XVT_TREEVIEW_NODE child = xvt_treelist_get_selected_node(_ctrl); + if (child != NULL) + { + const char* data = (const char*)xvt_treelist_get_node_data(_ctrl, child); + ok = tree()->goto_node(data); + } + return ok; +} + +void TTreelist_window::set_header(const char* head) +{ + _header = head; + xvt_treelist_set_node_string(_ctrl, NULL, _header); +} + +void TTreelist_window::set_fields(const char* field) +{ _fields = field; } + + +TTreelist_window::TTreelist_window(int x, int y, int dx, int dy, WINDOW parent, TTreelist_field* owner) + : TTree_window(x, y, dx, dy, parent, owner) +{ + XVT_COLOR_COMPONENT xcc[8]; memset(xcc, 0, sizeof(xcc)); + xcc[0].type = XVT_COLOR_BACKGROUND; xcc[0].color = NORMAL_BACK_COLOR; + xcc[1].type = XVT_COLOR_FOREGROUND; xcc[1].color = NORMAL_COLOR; + xcc[2].type = XVT_COLOR_HIGHLIGHT; xcc[2].color = FOCUS_BACK_COLOR; + xcc[3].type = XVT_COLOR_SELECT; xcc[3].color = FOCUS_COLOR; + xcc[4].type = XVT_COLOR_BLEND; xcc[4].color = MASK_BACK_COLOR; + xcc[5].type = XVT_COLOR_TROUGH; xcc[5].color = DISABLED_COLOR; + + WIN_DEF wd[2]; memset(&wd, 0, sizeof(wd)); + wd->wtype = WC_TREELIST; + wd->v.ctl.ctrl_id = owner->dlg(); + wd->v.ctl.font_id = xvtil_default_font(); + xvt_vobj_get_client_rect(win(), &wd->rct); + wd->ctlcolors = xcc; + + _ctrl = xvt_ctl_create_def(wd, win(), (long)this); + if (!_items.empty()) + { + TToken_string header(80, '\t'); + TToken_string fields(80, '\t'); + FOR_EACH_ARRAY_ROW(_items, i, text) + { + header.add(text->get(0)); + fields.add(text->get()); + } + set_header(header); + set_fields(fields); + _items.destroy(); + } +} + +/////////////////////////////////////////////////////////// +// TTreelist_field +/////////////////////////////////////////////////////////// + +word TTreelist_field::class_id() const +{ return CLASS_TREELIST_FIELD; } + +bool TTreelist_field::is_kind_of(word cid) const +{ return cid == CLASS_TREELIST_FIELD || TTree_field::is_kind_of(cid); } + +bool TTreelist_field::parse_item(TScanner& scanner) +{ + if (scanner.key() == "DI") // Encouraged syntax: DISPLAY "Header@10" FieldName + { + const TString80 label = dictionary_translate_header(scanner.string()); + TString80 fld = scanner.line(); fld.strip(" '\""); + + TToken_string* item = new TToken_string(80, '\t'); + item->add(label); + item->add(fld); + _items.add(item); + return true; + } + return TTree_field::parse_item(scanner); +} + +TField_window* TTreelist_field::create_window(int x, int y, int dx, int dy, WINDOW parent) +{ return new TTreelist_window(x, y, dx, dy, parent, this); } + +TTreelist_field::TTreelist_field(TMask* m) : TTree_field(m) +{ _items.destroy(); } diff --git a/include/treectrl.h b/include/treectrl.h index 560347e71..fbbb51b95 100755 --- a/include/treectrl.h +++ b/include/treectrl.h @@ -165,5 +165,20 @@ public: TProp_field(TMask* m); }; +class TTreelist_field : public TTree_field +{ +protected: // TObject + virtual word class_id() const; + virtual bool is_kind_of(word cid) const; + +protected: // TWindowed_field + virtual TField_window* create_window(int x, int y, int dx, int dy, WINDOW parent); + virtual bool parse_item(TScanner& scanner); + +public: + TTreelist_field(TMask* m); + virtual ~TTreelist_field() { } +}; + #endif