campo-sirio/ba/ba0105.cpp
guy dddb1a668f Supporto base per tema METRO
git-svn-id: svn://10.65.10.50/branches/R_10_00@23185 c028cbd2-c16b-5b4b-a496-9718f37d4682
2016-04-15 08:12:39 +00:00

697 lines
19 KiB
C++

#include "ba0103.h"
#include <applicat.h>
#include <config.h>
#include <dongle.h>
#include <image.h>
#include <isamrpc.h>
#include <reprint.h>
#include <isamrpc.h>
///////////////////////////////////////////////////////////
// Utilities
///////////////////////////////////////////////////////////
static int draw_text(WINDOW win, const char* txt, RCT& rct, char halign='L', char valign='T')
{
const int max_row_width = xvt_rect_get_width(&rct);
int lines = 0;
if (xvt_dwin_get_text_width(win, txt, -1) < max_row_width)
{
advanced_draw_text_line(win, txt,rct, halign, valign);
lines = 1;
}
else
{
TString_array para;
TToken_string p(txt, '\n');
para.destroy();
FOR_EACH_TOKEN(p, line)
para.add(line);
for (int i = 0; i < para.items(); i++)
{
TString& row = para.row(i);
int pix = xvt_dwin_get_text_width(win, row, -1);
if (pix > max_row_width)
{
int good_len = 0;
const int first_space = row.find(' ');
if (first_space >= 0)
{
// Linea con almeno uno spazio
for (int i = first_space; row[i]; i++) if (row[i] == ' ')
{
pix = xvt_dwin_get_text_width(win, row, i);
if (pix <= max_row_width)
good_len = i;
else
break;
}
}
if (good_len == 0) // Puo' succedere per linee senza spazi o con parole lunghissime
{
for (good_len = row.len(); good_len > 0; good_len--)
{
const int pix = xvt_dwin_get_text_width(win, row, good_len);
if (pix < max_row_width)
break;
}
}
TString next_row = row.mid(good_len);
next_row.ltrim();
para.insert(next_row, i+1);
row.cut(good_len);
}
}
advanced_draw_paragraph(win, para, rct, halign, valign, CHARY);
lines = para.items();
}
return lines;
}
///////////////////////////////////////////////////////////
// TMetro_menu
///////////////////////////////////////////////////////////
static TOutlook_mask* _main_mask = NULL;
class TMetro_item : public TSortable
{
RCT _rct;
protected:
virtual int compare(const TSortable& s) const
{
const TMetro_item& mi = (const TMetro_item&)s;
return mi.score() - score();
}
virtual COLOR back() const { return REQUIRED_BACK_COLOR; }
virtual COLOR fore() const { return NORMAL_COLOR; }
virtual int icon() const { return 0; }
virtual const TString& caption() const pure { return EMPTY_STRING; }
virtual const TMetro_item& item(int) const { return *this; }
public:
virtual void sort() { }
virtual int score() const { return 0; }
virtual const TString& code() const pure { return EMPTY_STRING; }
virtual PNT size_min() const { PNT p = { 32+2*CHARY, 16*CHARX }; return p; }
virtual void draw(WINDOW win, const RCT& rct);
virtual bool on_click(const PNT& pnt) { return xvt_rect_has_point(&_rct, pnt) != 0; }
const RCT& rect() const { return _rct; }
TMetro_item() { memset(&_rct, 0, sizeof(_rct)); }
};
void TMetro_item::draw(WINDOW win, const RCT& rct)
{
_rct = rct; // store for hit test
xvt_dwin_set_std_cpen(win, TL_PEN_HOLLOW);
CBRUSH brush;
brush.color = back();
brush.pat = PAT_SOLID;
xvt_dwin_set_cbrush(win, &brush);
xvt_dwin_draw_rect(win, &rct);
if (caption().full())
{
xvt_dwin_set_back_color(win, back());
xvt_dwin_set_fore_color(win, fore());
}
}
class TMetro_cell : public TMetro_item
{
const TMenuitem* _mi;
int _count; // usage count
TDate _last; // last run
protected:
virtual int score() const { return _count; }
virtual int compare(const TSortable& s) const;
virtual const TDate& last_run() const { return _last; }
virtual const TString& code() const { return _mi->action(); }
virtual const TString& caption() const { return _mi->caption(); }
virtual const TString& message() const { return EMPTY_STRING; }
virtual int icon() const { return _mi->icon(); }
virtual bool on_click(const PNT& pnt);
virtual void draw(WINDOW win, const RCT& rct);
public:
TMetro_cell(const TMenuitem& mi, int cnt, const TDate& last) : _mi(&mi), _count(cnt), _last(last) {}
};
int TMetro_cell::compare(const TSortable& s) const
{
const TMetro_cell& mi = (const TMetro_cell&)s;
int cmp = TMetro_item::compare(mi);
if (cmp == 0)
cmp = mi._last - _last;
return cmp;
}
void TMetro_cell::draw(WINDOW win, const RCT& rct)
{
TMetro_item::draw(win, rct); // store for hit test
const int margin = 2;
RCT area = rct; xvt_rect_deflate(&area, margin, margin);
if (caption().full())
{
draw_text(win, caption(), area, 'L', 'B');
area.bottom -= CHARY;
if (xvt_rect_get_height(&area) > 32)
{
int ico = icon();
if (ico <= 0) ico = ICON_RSRC;
xvt_dwin_draw_icon(win, area.left, area.top, ico);
area.top += 32+margin;
}
}
if (xvt_rect_get_height(&area) >= CHARY)
draw_text(win, message(), area, 'C', 'C');
}
bool TMetro_cell::on_click(const PNT& pnt)
{
bool go = TMetro_item::on_click(pnt);
if (go && _main_mask)
{
go = _main_mask->run_child(*_mi);
if (go)
{
_count++;
_last = TODAY;
}
}
return go;
}
///////////////////////////////////////////////////////////
// TMetro_setup_cell
///////////////////////////////////////////////////////////
class TMetro_setup_cell : public TMetro_cell
{
int _updates;
protected:
virtual COLOR back() const { return _updates > 0 ? FOCUS_BACK_COLOR : TMetro_cell::back(); }
virtual const TString& message() const;
public:
TMetro_setup_cell(const TMenuitem& mi, int cnt, const TDate& last);
};
const TString& TMetro_setup_cell::message() const
{
TString& tmp = get_tmp_string();
tmp.format(FR("%d aggiornamenti disponibili"), _updates);
return tmp;
}
TMetro_setup_cell::TMetro_setup_cell(const TMenuitem& mi, int cnt, const TDate& last) : TMetro_cell(mi, cnt, last), _updates(0)
{
const TDongle& don = dongle();
if (don.administrator() && ini_get_int(CONFIG_INSTALL, "Main", "Type") != 2 && xvt_net_get_status()>=2)
{
int y,r,t,p;
main_app().get_version_info(y, r, t, p);
TString dir; dir.format("/release%02d0/*a.ini", r);
TString_array patches;
http_dir("http://93.146.247.172", dir, patches);
TArray modules;
FOR_EACH_ARRAY_ROW(patches, i, row)
{
const TString& mod = row->left(2);
const word aut = don.module_name2code(mod);
if (don.active(aut))
{
TToken_string* p = (TToken_string*)modules.objptr(aut);
if (p == NULL)
{
p = new TToken_string;
p->add(ini_get_int(CONFIG_GENERAL, mod, "Patch"));
modules.add(p);
}
if (p->items() == 1)
{
const int local_patch = p->get_int(0);
const int remote_patch = atoi(row->mid(2));
if (remote_patch > local_patch)
{
p->add(remote_patch, 1);
_updates++;
}
}
}
}
}
}
///////////////////////////////////////////////////////////
// TMetro_dbase_cell
///////////////////////////////////////////////////////////
class TMetro_dbase_cell : public TMetro_cell
{
clock_t _next_update;
int _users;
protected:
int users() const;
virtual COLOR back() const { return users() > 1 ? FOCUS_BACK_COLOR : TMetro_cell::back(); }
virtual const TString& message() const;
public:
TMetro_dbase_cell(const TMenuitem& mi, int cnt, const TDate& last) : TMetro_cell(mi, cnt, last), _users(0) {}
};
int TMetro_dbase_cell::users() const
{
const clock_t now = clock();
if (_users <= 0 || now > _next_update)
{
TRelation users(LF_USER);
TCursor connections(&users, "CONNECTED=\"X\"");
(int&)_users = max(1, connections.items());
(clock_t&)_next_update = clock() + 15*CLOCKS_PER_SEC;
}
return _users;
}
const TString& TMetro_dbase_cell::message() const
{
TString& tmp = get_tmp_string();
const int u = users();
if (u > 1)
tmp.format(FR("%d utenti connessi"), u);
else
tmp.format(FR("Un utente connesso"));
return tmp;
}
///////////////////////////////////////////////////////////
// TMetro_backup_cell
///////////////////////////////////////////////////////////
class TMetro_backup_cell : public TMetro_cell
{
long days() const { return TDate(TODAY) - last_run(); }
protected:
virtual COLOR back() const { return days() > 7 ? FOCUS_BACK_COLOR : TMetro_cell::back(); }
virtual const TString& message() const;
public:
TMetro_backup_cell(const TMenuitem& mi, int cnt, const TDate& last) : TMetro_cell(mi, cnt, last) {}
};
const TString& TMetro_backup_cell::message() const
{
TString& tmp = get_tmp_string();
const int d = days();
if (d > 0)
tmp.format(FR("%d giorni dall'ultimo backup"), d);
return tmp;
}
///////////////////////////////////////////////////////////
// TMetro_panel
///////////////////////////////////////////////////////////
class TMetro_panel : public TMetro_item
{
TString _name;
int _icon;
TArray _child;
protected:
virtual int score() const;
virtual const TString& code() const { return _name; }
virtual const TString& caption() const { return _name; }
virtual int icon() const { return _icon; }
virtual COLOR fore() const { return PROMPT_COLOR; }
virtual COLOR back() const { return _name.full() ? MASK_BACK_COLOR : NORMAL_BACK_COLOR; }
virtual PNT size_min() const { PNT p = TMetro_item::size_min(); p.v = p.v * 2 + 32; p.h *= 3; return p; }
virtual const TMetro_item& item(int i) const { return (const TMetro_item&)_child[i]; }
public:
virtual void sort();
virtual void draw(WINDOW win, const RCT& rct);
virtual bool on_click(const PNT& pnt);
TMetro_cell* add_item(const TMenuitem& item, int cnt, const TDate& last);
TMetro_panel* add_panel(const TString& name, int icon);
bool is_empty() const { return _child.empty(); }
TMetro_panel(const TString& name, int icon) : _name(name), _icon(icon) {}
};
#define FOR_EACH_CHILD(i) TMetro_item* i; for (int _r##i = 0; (i = (TMetro_item*)_child.objptr(_r##i)) != NULL; _r##i++)
int TMetro_panel::score() const
{
int max_score = 0;
FOR_EACH_CHILD(i)
{
const int s = i->score();
if (s > max_score)
max_score = s;
}
return max_score;
}
void TMetro_panel::sort()
{
_child.sort();
FOR_EACH_CHILD(i)
i->sort();
}
TMetro_cell* TMetro_panel::add_item(const TMenuitem& mi, int cnt, const TDate& last)
{
// check for duplicates
FOR_EACH_CHILD(i)
if (mi.action() == i->code())
return (TMetro_cell*)i;
TMetro_cell* mir = NULL;
if (mi.action() == "ba1 -0")
mir = new TMetro_dbase_cell(mi, cnt, last); else
if (mi.action() == "ba1 -6")
mir = new TMetro_setup_cell(mi, cnt, last); else
if (mi.action() == "ba2 -1")
mir = new TMetro_backup_cell(mi, cnt, last);
else
mir = new TMetro_cell(mi, cnt, last);
_child.add(mir);
return mir;
}
TMetro_panel* TMetro_panel::add_panel(const TString& name, int icon)
{
// check for duplicates
FOR_EACH_CHILD(i)
if (i->code() == name)
return (TMetro_panel*)i;
TMetro_panel* mp = new TMetro_panel(name, icon);
_child.add(mp);
return mp;
}
void TMetro_panel::draw(WINDOW win, const RCT& rct)
{
TMetro_item::draw(win, rct);
const int tot = _child.items();
const int margin = 4;
RCT area = rct;
area.left += margin; area.top += margin;
if (caption().full())
{
RCT txt = area; txt.bottom = area.top + 36;
if (icon())
{
xvt_dwin_draw_icon(win, txt.left, txt.top, icon());
txt.left += 36;
}
advanced_draw_text_line(win, caption(), txt, 'L', 'C');
area.top = txt.bottom;
}
const TMetro_item& mi = item(0);
const int width = xvt_rect_get_width(&area);
const int height = xvt_rect_get_height(&area);
const int cols = width / mi.size_min().h;
const int rows = height / mi.size_min().v;
const int drawables = rows * cols;
for (int i = 0; i < tot && i < drawables; i++)
{
const int x = i % cols, y = i / cols;
RCT r;
r.left = area.left + width * x / cols;
r.right = area.left + width * (x+1) / cols - margin;
r.top = area.top + height * y / rows;
r.bottom = area.top + height * (y+1) / rows - margin;
TMetro_item& mi = *(TMetro_item*)_child.objptr(i);
mi.draw(win, r);
}
}
bool TMetro_panel::on_click(const PNT& pnt)
{
const bool go = TMetro_item::on_click(pnt);
if (go)
{
FOR_EACH_CHILD(i)
if (i->on_click(pnt))
{
sort();
break;
}
}
return go;
}
///////////////////////////////////////////////////////////
// TMetro_menu
///////////////////////////////////////////////////////////
class TMetro_menu : public TMetro_panel
{
TWindow* _book;
TImage* _logo;
protected:
int find_icon(const TMenuitem& mi, const TSubmenu& node, TAssoc_array& visited) const;
bool add_item(const TMenuitem& mi, int cnt, const TDate& d);
void find_actions(const TSubmenu& sm, const TArray& actions) const;
virtual void draw(WINDOW win, RCT& rct);
static long handler(WINDOW win, EVENT* ep);
public:
void create(TWindow* book_win, const TMenu& menu);
TWindow* book() const { return _book; }
TMetro_menu() : TMetro_panel(EMPTY_STRING, 0), _book(NULL), _logo(NULL) {}
};
static TMetro_menu _metro_menu;
void TMetro_menu::draw(WINDOW win, RCT& rct)
{
TMetro_panel::draw(win,rct);
if (_logo == NULL)
_logo = new TImage(get_logo());
if (_logo->ok())
{
RCT child = item(0).rect();
const int dx = rct.right - child.right;
const int dy = rct.bottom - child.bottom;
xvt_rect_offset(&child, dx, dy);
xvt_dwin_set_std_cbrush(win, TL_BRUSH_WHITE);
xvt_dwin_draw_rect(win, &child);
_logo->draw(win, child, 'C', 'C', '*');
}
}
long TMetro_menu::handler(WINDOW win, EVENT* ep)
{
if (ep->type == E_UPDATE)
{
if (xvt_win_get_children_count(win) == 0) // Visibility test
{
RCT rct; xvt_vobj_get_client_rect(win, &rct);
rct.bottom = ep->v.update.rct.bottom;
_metro_menu.draw(win, rct);
}
return 0;
}
if (ep->type == E_MOUSE_DOWN)
{
if (_metro_menu.on_click(ep->v.mouse.where))
return 0;
}
return _metro_menu.book()->handler(win, ep);
}
// 0 = not found; -1 = no icon; >0 = icon
int TMetro_menu::find_icon(const TMenuitem& mi, const TSubmenu& node, TAssoc_array& visited) const
{
int ico = 0;
for (int i = 0; ico == 0 && i < node.items(); i++)
{
const TMenuitem& sm = node.item(i);
if (sm.is_program())
{
if (mi.action() == sm.action())
{
ico = -1;
break;
}
} else
if (sm.is_submenu())
{
const TSubmenu* sub = sm.child_submenu();
if (sub && !visited.is_key(sub->name()))
{
visited.add(sub->name());
ico = find_icon(mi, *sub, visited);
if (ico < 0 && sm.icon() > 0)
ico = sm.icon();
}
}
}
return ico;
}
bool TMetro_menu::add_item(const TMenuitem& mi, int cnt, const TDate& last)
{
const TString& action = mi.action();
TString4 mod = action.left(2);
TString desc;
int ico = 0;
if ((mod == "ba" && action[2]<='2') || action.find("iewer")>= 0)
{
if (!dongle().administrator())
return false;
mod = "sy";
ico = 10210;
desc = TR("Sistema");
}
else
{
const word idx = dongle().module_name2code(mod);
desc = dongle().module_code2desc(idx);
TMenu& menu = mi.menu();
const TSubmenu* root = menu.find("MENU_000");
if (root)
{
TAssoc_array visited;
visited.add(root->name());
visited.add("MENU_PREFERITI)");
ico = find_icon(mi, *root, visited);
}
if (ico <= 0)
ico = ICON_RSRC;
}
TMetro_panel* a = add_panel(desc, ico);
return a ? (a->add_item(mi, cnt, last) != NULL) : false;
}
struct TFreq_info : public TString
{
const TMenuitem* _mi;
int _freq;
TDate _last;
double _score;
TFreq_info(const TString& cmd, int f, const TDate& last) : TString(cmd), _mi(NULL), _freq(f), _last(last), _score(0.8) {}
};
void TMetro_menu::find_actions(const TSubmenu& sm, const TArray& actions) const
{
if (sm.enabled() && sm.name() != "MENU_PREFERITI")
{
for (int i = 0; i < sm.items(); i++)
{
const TMenuitem& mi = sm[i];
if (mi.enabled() && mi.is_program())
{
FOR_EACH_ARRAY_ITEM(actions, a, itm)
{
TFreq_info& fi = *(TFreq_info*)itm;
if (fi._score < 1.0)
{
const double score = xvt_str_fuzzy_compare_ignoring_case(fi, mi.action());
if (score > fi._score)
{
fi._score = score;
fi._mi = &mi;
}
}
}
}
}
}
}
void TMetro_menu::create(TWindow* book, const TMenu& menu)
{
const int def_cnt = 999999;
const TDate def_dat(TODAY);
/*
const TSubmenu* pref = menu.find("MENU_PREFERITI");
if (pref)
{
for (int i = 0; i < pref->items(); i++)
add_item(pref->item(i), def_cnt, def_dat);
}
*/
TArray freq;
TConfig gui(CONFIG_GUI, "Counters");
TAssoc_array& cmds = gui.list_variables();
TToken_string pair;
FOR_EACH_ASSOC_OBJECT(cmds, obj, cmd, cnt)
{
pair = *(TString*)cnt;
freq.add(new TFreq_info(cmd, pair.get_int(0), TDate(pair.get_long(1))));
}
if (dongle().administrator())
{
const char* cmd[] = { "ba1 -0", "ba1 -6", "ba2 -1",
"setup/TeamviewerQS_it.exe", NULL };
for (int i = 0; cmd[i]; i++)
{
TFreq_info* fi = new TFreq_info(cmd[i], def_cnt-i, def_dat);
freq.add(fi);
}
}
TAssoc_array& am = (TAssoc_array&)menu; // cheating :-)
FOR_EACH_ASSOC_OBJECT(am, obj, name, sub)
find_actions(*(const TSubmenu*)sub, freq);
FOR_EACH_ARRAY_ITEM(freq, i, itm)
{
const TFreq_info& fi = *(const TFreq_info*)itm;
if (fi._mi != NULL)
add_item(*fi._mi, fi._freq, fi._last);
}
sort();
_book = book;
xvt_win_set_handler(book->win(), handler); // Nasty code injection
}
///////////////////////////////////////////////////////////
// TMetro_mask
///////////////////////////////////////////////////////////
TMetro_mask::TMetro_mask(TMenu& menu) : TOutlook_mask(menu, true)
{
TWindow& bw = ((TWindowed_field&)book_field()).win();
_metro_menu.create(&bw, menu);
_main_mask = this;
}
TMetro_mask::~TMetro_mask()
{
_main_mask = NULL;
}