campo-sirio/db/db1300.cpp

857 lines
21 KiB
C++
Raw Normal View History

#include <applicat.h>
#include <defmask.h>
#include <sheet.h>
#include <automask.h>
#include <printer.h>
#include <progind.h>
#include <relation.h>
#include <sheet.h>
#include "dblib.h"
#include "db1300a.h"
#include "db0500a.h"
///////////////////////////////////////////////////////////
// TXmas_tree
///////////////////////////////////////////////////////////
class TXmas_tree : public TDistinta_tree
{
TIsamtempfile *_dist, *_rdist;
TRecord_cache *_cache_dist, *_cache_rdist;
protected:
virtual const TRectype& find_head(const TCodice_articolo& art) const;
virtual const TRectype* find_child(const TCodice_articolo& art, int child) const;
public:
bool add_head(const TCodice_articolo& art);
bool add_child(const TRectype& rec);
void add_branch(TDistinta_tree& dt);
TXmas_tree();
virtual ~TXmas_tree();
};
HIDDEN bool _ignore_zero = TRUE;
const TRectype& TXmas_tree::find_head(const TCodice_articolo& art) const
{
const TRectype& rec = _cache_dist->get(art);
return rec;
}
const TRectype* TXmas_tree::find_child(const TCodice_articolo& art, int child) const
{
TString80 key; key.format("%s|%d", (const char*)art, child);
const TRectype& rec = _cache_rdist->get(key);
return rec.empty() ? NULL : &rec;
}
bool TXmas_tree::add_head(const TCodice_articolo& art)
{
bool added = FALSE;
if (find_head(art).empty())
{
TRectype& rec = _dist->curr();
rec = cache().get(LF_DIST, art);
if (rec.empty())
rec.put("CODDIST", art);
const int err = rec.write(*_dist);
_cache_dist->discard(art);
added = err == NOERR;
}
return added;
}
bool TXmas_tree::add_child(const TRectype& rec)
{
int err = rec.write(*_rdist);
return err == NOERR;
}
void TXmas_tree::add_branch(TDistinta_tree& dt)
{
TString old_node; dt.curr_id(old_node); // Memorizza posizione
while (dt.has_father())
{
const real qta = dt.last_qta();
if (::_ignore_zero && qta.is_zero())
break; // Inutile proseguire
TCodice_um um; dt.curr_um(um);
TCodice_articolo art; dt.curr_code(art);
add_head(art);
dt.goto_father();
TCodice_articolo father; dt.curr_code(father);
TString80 level; dt.curr_giaclev(level);
const TRectype* child = NULL;
int c;
for (c = 1; ; c++)
{
child = find_child(art, c);
if (child == NULL)
break;
if (child->get("CODCOMP") != father)
continue;
if (!level.blank() && child->get("LIVELLO") != level)
continue;
if (child->get_real("EXPR") == qta)
break;
}
if (child == NULL)
{
TRectype& curr = _rdist->curr();
curr.put("CODDIST", art);
curr.put("NRIG", c);
curr.put("TIPO", "A");
curr.put("CODCOMP", father);
curr.put("LIVELLO", level);
curr.put("UM", um);
curr.put("EXPR", qta);
int err = curr.write(*_rdist);
TString k;
k.format("%s|%d", (const char *) art, c);
_cache_rdist->discard(k);
CHECKD(err == NOERR, "Rdist write error ", err);
}
}
dt.goto_node(old_node); // Ripristina posizione
}
TXmas_tree::TXmas_tree()
{
_dist = new TIsamtempfile(LF_DIST, NULL, TRUE, TRUE);
_cache_dist = new TRecord_cache(_dist);
_cache_dist->test_file_changes(TRUE);
_rdist = new TIsamtempfile(LF_RDIST, NULL, TRUE, TRUE);
_cache_rdist = new TRecord_cache(_rdist);
_cache_rdist->test_file_changes(TRUE);
set_qta_on_descr(TRUE); // Stampa anche le quantita
}
TXmas_tree::~TXmas_tree()
{
// I file temporanei vengono cancellati dai distruttori
// delle record cache che li contengono
delete _cache_dist;
delete _cache_rdist;
}
///////////////////////////////////////////////////////////
// TDistinta_sheet
///////////////////////////////////////////////////////////
class TDistinta_sheet : public TSheet
{
TCodgiac_livelli _livgiac;
TArray _data;
protected:
virtual void get_row(long n, TToken_string& row);
virtual long get_items() const { return _data.items(); }
public:
TArray& rows_array() { return _data; }
TDistinta_sheet(int numlev);
virtual ~TDistinta_sheet() { }
};
void TDistinta_sheet::get_row(long n, TToken_string& row)
{
const TRiga_esplosione& re = (const TRiga_esplosione&)_data[int(n)];
row.cut(0);
row.add(re.tipo());
row.add(re.articolo());
if (_livgiac.enabled(1))
row.add(_livgiac.unpack_grpcode(re.giacenza(),1));
if (_livgiac.enabled(2))
row.add(_livgiac.unpack_grpcode(re.giacenza(),2));
if (_livgiac.enabled(3))
row.add(_livgiac.unpack_grpcode(re.giacenza(),3));
if (_livgiac.enabled(4))
row.add(_livgiac.unpack_grpcode(re.giacenza(),4));
row.add(re.um());
row.add(re.val().string(0, 5));
row.add(re.livello());
row.add(re.ordinamento());
}
TDistinta_sheet::TDistinta_sheet(int numlev)
: TSheet(-1, -1, 76, 20, TR("Implosione"),
numlev == 4 ? HR("Tipo|Codice@20|Liv.1@10|Liv.2@6|Liv.3@6|Liv.4@6|UM|Quantita'@18R|Liv.@R|Sort@8R") :
numlev == 3 ? HR("Tipo|Codice@20|Liv.1@10|Liv.2@6|Liv.3@6|UM|Quantita'@18R|Liv.@R|Sort@8R") :
numlev == 2 ? HR("Tipo|Codice@20|Liv.1@10|Liv.2@6|UM|Quantita'@18R|Liv.@R|Sort@8R") :
numlev == 1 ? HR("Tipo|Codice@20|Liv.1@10|UM|Quantita'@18R|Liv.@R|Sort@8R") :
HR("Tipo|Codice@20|UM|Quantita'@18R|Liv.@R|Sort@8R"))
{
}
///////////////////////////////////////////////////////////
// Display_mask
///////////////////////////////////////////////////////////
class TDisplay_mask : public TAutomask
{
TAssoc_array& _xmas;
protected:
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
void print_tree(TXmas_tree& tree);
public:
TDisplay_mask(TAssoc_array& xmas);
virtual ~TDisplay_mask() { }
};
static bool print_node(TTree& t, void* p, word flags)
{
TXmas_tree& tree = (TXmas_tree&)t;
TBit_array& righette = *(TBit_array*)p;
const int depth = tree.curr_depth();
const int tab = (depth-1)*3;
TString descr;
tree.get_description(descr);
TPrintrow row;
if (tab >= 0)
row.put("+--", tab);
row.put(descr);
for (int d = 1; d < depth; d++)
if (righette[d]) row.put("!", (d-1)*3);
printer().print(row);
righette.set(depth, tree.has_rbrother());
return FALSE;
}
void TDisplay_mask::print_tree(TXmas_tree& tree)
{
TPrinter& p = printer();
p.resetheader();
p.resetfooter();
TCodice_articolo art;
TString descr;
tree.goto_root();
tree.curr_code(art);
tree.describe(art, descr);
TPrintrow header;
header.put(FR("@bSTAMPA IMPLOSIONE "));
header.put(art);
header.put(" - ");
header.put(descr);
p.setheaderline(0, header);
p.setheaderline(1, NULL);
TPrintrow footer;
footer.put(FR("Pag.@#"), 36);
p.setfooterline(0, NULL);
p.setfooterline(1, footer);
p.setfooterline(2, NULL);
p.open();
TBit_array righette;
tree.scan_depth_first(print_node, &righette);
p.formfeed();
p.close();
}
bool TDisplay_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
switch (o.dlg())
{
case F_CODICE:
if (e == fe_modify)
{
TTree_field& tf = tfield(F_TREE);
const int code = atoi(o.get());
TXmas_tree* tree = (TXmas_tree*)_xmas.first_item();
for (int i = 1; i < code; i++)
tree = (TXmas_tree*)_xmas.succ_item();
if (tf.tree() != tree)
{
tf.set_tree(tree);
tf.win().force_update();
}
}
break;
case F_EXPLODE:
if (e == fe_button)
{
TXmas_tree* t = (TXmas_tree*)tfield(F_TREE).tree();
if (t && t->goto_root())
{
TXmas_tree& tree = *t;
TCodice_articolo art; tree.curr_code(art);
TString80 caption; caption << TR("Lista d'implosione ") << art;
TMask m("db0500c");
m.set_caption(caption);
m.set(F_ARTICOLI, "X");
m.set(F_LAVORAZIONI, "X");
m.set(F_VIRTUALI, "X");
if (m.run() == K_ENTER)
{
TCodgiac_livelli livgiac;
TDistinta_sheet a(livgiac.last_level());
a.set_caption(caption);
int sk = m.get_int(F_SORT);
int md = m.get_int(F_MAXDEPTH);
TExplosion_grouping gr = TExplosion_grouping(m.get_int(F_GROUPMODE));
bool mb = m.get_bool(F_MATBASE);
TString16 fi;
if (m.get_bool(F_ARTICOLI)) fi << 'A';
if (m.get_bool(F_LAVORAZIONI)) fi << 'L';
if (m.get_bool(F_VIRTUALI)) fi << 'V';
if (m.get_bool(F_GHOST)) fi << 'G';
if (tree.goto_root())
{
TIndwin iw(0, TR("Elaborazione in corso..."), FALSE, FALSE);
tree.explode(a.rows_array(), mb, gr, md, fi, sk);
}
a.run();
}
}
}
break;
case DLG_PRINT:
if (e == fe_button)
{
TXmas_tree* t = (TXmas_tree*)tfield(F_TREE).tree();
if (t)
print_tree(*t);
return FALSE; // Non chiudere la maschera!
}
break;
default:
break;
}
return TRUE;
}
TDisplay_mask::TDisplay_mask(TAssoc_array& xmas)
: TAutomask("db1300b"), _xmas(xmas)
{
TTree_field& tf = tfield(F_TREE);
TList_sheet* ls = efield(F_CODICE).sheet();
TString_array& rows = ls->rows_array();
rows.destroy();
TString16 code;
TString str;
TToken_string disp;
int i = 0;
FOR_EACH_ASSOC_OBJECT(_xmas, obj, key, item) if (item != NULL)
{
code.format("%03d", ++i);
disp = key; disp.replace('|', ' ');
disp.insert("|", 0); disp.insert(code, 0);
TXmas_tree* albero = (TXmas_tree*)item;
albero->goto_root();
albero->get_description(str);
disp.add(str);
rows.add(disp);
if (item && tf.tree() == NULL)
{
tf.set_tree(albero);
set(F_CODICE, code);
}
}
}
///////////////////////////////////////////////////////////
// Implosion_mask
///////////////////////////////////////////////////////////
class TImplosion_mask : public TAutomask
{
TAssoc_array _xmas;
protected:
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
int find_roots(const char* articolo, TAssoc_array& roots) const;
void implode_slow();
void implode_medium();
void implode_fast();
public:
void implode();
void display();
TImplosion_mask();
virtual ~TImplosion_mask();
};
bool TImplosion_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
return TRUE;
}
HIDDEN bool implode_callback(TTree& tree, void* jolly, word flags)
{
if (flags == SCAN_PRE_ORDER)
{
TDistinta_tree& dt = (TDistinta_tree&)tree;
TAssoc_array* a = (TAssoc_array*)jolly;
TCodice_articolo code; dt.curr_code(code);
if (a->is_key(code)) // Cerca articolo senza livello
{
TXmas_tree* x = (TXmas_tree*)a->objptr(code);
if (x == NULL)
{
x = new TXmas_tree;
a->add(code, x, TRUE);
}
x->add_branch(dt);
}
TString80 curliv; dt.curr_giaclev(curliv);
if (!curliv.blank())
{
TString80 key = code; key << '|' << curliv;
if (a->is_key(key))
{
TXmas_tree* x = (TXmas_tree*)a->objptr(key);
if (x == NULL)
{
x = new TXmas_tree;
a->add(key, x, TRUE);
}
x->add_branch(dt);
}
}
}
return FALSE;
}
int TImplosion_mask::find_roots(const char* articolo, TAssoc_array& roots) const
{
TRelation rel(LF_RDIST);
TCursor cur(&rel, "", 2);
TRectype only(LF_RDIST);
TAssoc_array ass[2];
int c = 0; // Array dei children = 0; fathers = 1
ass[c].add(articolo, NULL);
const char* cap = FR("Livello %d - Articoli %ld");
TString caption; caption.format(cap, 0, 0L);
TIndwin iw(0, caption, TRUE, FALSE);
for (int loop = 0; ass[c].items() > 0 && loop < 50; loop++)
{
if (iw.iscancelled())
break;
caption.format(cap, loop, ass[c].items());
iw.set_text(caption);
FOR_EACH_ASSOC_OBJECT(ass[c], obj, key, item)
{
only.put("CODCOMP", key);
cur.setregion(only, only);
const TRecnotype items = cur.items();
if (items > 0)
{
cur.freeze(TRUE);
for (cur = 0L; cur.pos() < cur.items(); ++cur)
{
const TString& father = cur.curr().get("CODDIST");
ass[!c].add(father, NULL);
}
cur.freeze(FALSE);
}
else
roots.add(key);
}
ass[c].destroy(); // Distruggi i children
c = !c; // Scambia i children coi fathers
}
return roots.items();
}
void TImplosion_mask::implode_slow()
{
TRelation rel(LF_DIST);
TRectype dist_f(LF_DIST), dist_t(LF_DIST);
dist_f.put("CODDIST", get(F_DA_ARTICOLO));
dist_t.put("CODDIST", get(F_AD_ARTICOLO));
TCursor cur(&rel, "", 1, &dist_f, &dist_t);
long items = 0;
if (get_bool(F_USECATMER))
{
rel.add(LF_ANAMAG, "CODART==CODDIST");
TString filter;
for (int f = 0; f < 2; f++)
{
const TString& cm = get(F_DA_CATMER+f);
const int cmlen = cm.len();
if (cmlen > 0)
{
if (filter.not_empty()) filter << "&&";
filter << '(' << LF_ANAMAG << "->" << ANAMAG_GRMERC;
if (cmlen < 5)
filter << "[1," << cmlen << ']';
filter << (f ? '<' : '>') << "=\"" << cm << "\")";
}
}
cur.setfilter(filter, TRUE);
TIndwin iw(0, TR("Creazione lista articoli da esplodere..."), FALSE, FALSE);
items = cur.items();
}
else
{
TWait_cursor hourglass;
items = cur.items();
}
cur.freeze();
TString caption;
caption << TR("Esplosione di ") << items << TR(" articoli in corso...");
TProgind pi(items, caption, TRUE, TRUE);
TSheet_field& vars = sfield(F_VARS);
if (vars.items() == 0) vars.row(-1); // Crea almeno una riga vuota
const TRectype& curr = cur.curr();
TCodice_articolo articolo;
TString livello;
TCodgiac_livelli livgiac;
TDistinta_tree dt;
TSheet_field& a = sfield(F_ARTS);
TString80 key;
FOR_EACH_SHEET_ROW(a, r, row)
{
key = row->get(1);
if (!key.blank())
{
if (row->get_char(3) > ' ')
{
key << '|' << row->get(3);
key << row->get();
key << row->get();
key << row->get();
key.rtrim();
}
_xmas.add(key, NULL);
}
}
for (cur = 0L; cur.pos() < items; ++cur)
{
#ifdef DBG
if (pi.addstatus(1))
{
unsigned long h, m;
TFile_cache::stats(h, m);
TString80 msg;
msg.format("Hits %lu - Misses %lu", h, m);
xvtil_statbar_set(msg);
}
#else
pi.addstatus(1);
#endif
if (pi.iscancelled()) break;
// Scansione di tutte le righe abilitate
FOR_EACH_SHEET_ROW(vars, r, row)
{
dt.clear_globals();
dt.set_global("_IMPIANTO", row->get(0));
dt.set_global("_LINEA", row->get(1));
dt.set_global("_MAGAZZINO", row->get(2));
dt.set_global("_DEPOSITO", row->get(3));
vars.check_row(r);
livgiac.pack_maskgrpcodes(livello, vars.sheet_mask(), 105, 4);
articolo = curr.get("CODDIST");
dt.set_root(articolo, "", 1.0, livello);
dt.scan_depth_first(implode_callback, &_xmas);
}
}
}
void TImplosion_mask::implode_medium()
{
const TCodice_articolo da_art = get(F_DA_ARTICOLO);
const TCodice_articolo ad_art = get(F_AD_ARTICOLO);
TSheet_field& a = sfield(F_ARTS);
FOR_EACH_SHEET_ROW(a, r, row)
{
const TCodice_articolo articolo = row->get(1);
if (articolo.blank())
continue;
TString livello;
if (row->get_char(3) > ' ')
{
livello = row->get(3);
livello << row->get();
livello << row->get();
livello << row->get();
livello.rtrim();
}
TString key;
key = articolo;
if (livello.not_empty())
key << '|' << livello;
_xmas.add(key, NULL);
TAssoc_array roots;
const long items = find_roots(articolo, roots);
if (items > 0)
{
TString caption;
caption << TR("Esplosione di ") << items << TR(" articoli in corso...");
TProgind pi(items, caption, TRUE, TRUE);
TSheet_field& vars = sfield(F_VARS);
if (vars.items() == 0) vars.row(-1); // Crea almeno una riga vuota
TDistinta_tree dt;
TCodgiac_livelli livgiac;
FOR_EACH_ASSOC_OBJECT(roots, obj, key, item)
{
if (pi.addstatus(1))
{
#ifdef DBG
unsigned long h, m;
TFile_cache::stats(h, m);
TString80 msg;
msg.format("Hits %lu - Misses %lu", h, m);
xvtil_statbar_set(msg);
#endif
}
else
break;
const TCodice_articolo articolo = key;
if (articolo < da_art)
continue;
if (ad_art.not_empty() && articolo > ad_art)
continue;
// Scansione di tutte le righe abilitate
FOR_EACH_SHEET_ROW(vars, r, row)
{
dt.clear_globals();
dt.set_global("_IMPIANTO", row->get(0));
dt.set_global("_LINEA", row->get(1));
dt.set_global("_MAGAZZINO", row->get(2));
dt.set_global("_DEPOSITO", row->get(3));
vars.check_row(r);
livgiac.pack_maskgrpcodes(livello, vars.sheet_mask(), 105, 4);
dt.set_root(articolo, "", 1.0, livello);
dt.scan_depth_first(implode_callback, &_xmas);
}
}
}
}
}
void TImplosion_mask::implode_fast()
{
TRelation rel(LF_RDIST);
TRectype only(LF_RDIST);
TSheet_field& a = sfield(F_ARTS);
FOR_EACH_SHEET_ROW(a, r, row)
{
const TCodice_articolo articolo = row->get(1);
if (articolo.blank())
continue;
TString livello;
if (row->get_char(3) > ' ')
{
livello = row->get(3);
livello << row->get();
livello << row->get();
livello << row->get();
livello.rtrim();
}
only.put("CODCOMP", articolo);
TCursor cur(&rel, "", 2, &only, &only);
const TRecnotype items = cur.items();
if (items > 0)
{
cur.freeze();
TXmas_tree* tree = new TXmas_tree;
int child = 0;
for (cur = 0L; cur.pos() < items; ++cur)
{
TRectype& curr = cur.curr();
if (livello.not_empty() && curr.get("LIVELLO") != livello)
continue;
const TCodice_articolo father = curr.get("CODDIST");
curr.put("CODDIST", articolo);
curr.put("NRIG", ++child);
curr.put("TIPO", "A");
curr.put("CODCOMP", father);
tree->add_child(curr);
}
if (child > 0)
{
tree->add_head(articolo);
tree->set_root(articolo);
TString80 key = articolo;
if (livello.not_empty())
key << '|' << livello;
_xmas.add(key, tree);
}
else
delete tree;
}
}
}
void TImplosion_mask::implode()
{
_xmas.destroy();
_ignore_zero = !get_bool(F_DISPLAY_ZERO);
if (get_bool(F_FASTIMPLODE))
{
if (get_bool(F_ONLYONE))
implode_fast();
else
implode_medium();
}
else
implode_slow();
TProgind pi(_xmas.items(), TR("Espansione albero di implosione..."));
TCodice_articolo articolo;
TString livello;
FOR_EACH_ASSOC_OBJECT(_xmas, obj, key, item) if (item != NULL)
{
pi.addstatus(1);
TToken_string row(key);
articolo = row.get(0);
livello = row.get();
TXmas_tree* x = (TXmas_tree*)item;
x->set_root(articolo, "", 1.0, livello);
x->expand_all();
}
}
void TImplosion_mask::display()
{
TDisplay_mask* m = new TDisplay_mask(_xmas);
m->run();
delete m;
}
TImplosion_mask::TImplosion_mask() : TAutomask("db1300a")
{
TCodgiac_livelli liv;
TSheet_field& a = sfield(F_ARTS);
liv.set_sheet_columns(a, F_LEV1);
a.row(0);
TSheet_field& v = sfield(F_VARS);
liv.set_sheet_columns(v, 105);
v.row(0);
}
TImplosion_mask::~TImplosion_mask()
{
}
///////////////////////////////////////////////////////////
// Implosion Application
///////////////////////////////////////////////////////////
class TImplosion : public TSkeleton_application
{
TImplosion_mask* _impl;
public:
virtual bool create();
virtual void main_loop();
virtual bool destroy();
void reset_tree();
};
bool TImplosion::create()
{
open_files(LF_TAB, LF_TABCOM, LF_DIST, LF_RDIST, LF_ANAMAG, LF_UMART, NULL);
_impl = new TImplosion_mask;
// Inutile testare i cambiamenti dei file
rec_cache(LF_TAB).test_file_changes(FALSE);
const int lf[] = { LF_UMART, LF_ANAMAG, LF_DIST, LF_RDIST, 0 };
for (int i = 0; lf[i]; i++)
{
int maxsize = 4096;
if (lf[i] == LF_RDIST)
maxsize *= 4;
rec_cache(lf[i]).set_items_limit(maxsize);
rec_cache(lf[i]).test_file_changes(FALSE);
}
return TSkeleton_application::create();
}
void TImplosion::main_loop()
{
while (_impl->run() != K_QUIT)
{
_impl->implode();
_impl->display();
}
}
bool TImplosion::destroy()
{
delete _impl;
return TSkeleton_application::destroy();
}
int db1300(int argc, char* argv[])
{
TImplosion bum;
bum.run(argc, argv, TR("Implosione"));
return 0;
}