Files correlati : cg2.exe tutti i programmi Ricompilazione Demo : [ ] Commento : Bug 0000837 Sto cambiando data ad un gruppo di registrazioni fatture di vendita manuale, per far rigenerare le scadenze metto reg. di pura iva prima si e poi no, non mi ricrea le righe di contabilità quindi mi appresto ad inserirle io, ricerco quindi il cliente ma la barra di ricerca nasconde l'imbuto di ricerca, ed il campo della ragione sociale viene accorpato al campo alla destra. git-svn-id: svn://10.65.10.50/trunk@16972 c028cbd2-c16b-5b4b-a496-9718f37d4682
1966 lines
51 KiB
C++
Executable File
1966 lines
51 KiB
C++
Executable File
#define XI_INTERNAL
|
|
#include <xinclude.h>
|
|
#include <statbar.h>
|
|
|
|
#include <applicat.h>
|
|
#include <colors.h>
|
|
#include <config.h>
|
|
#include <controls.h>
|
|
#include <relation.h>
|
|
#include <sheet.h>
|
|
#include <toolfld.h>
|
|
#include <urldefid.h>
|
|
#include <utility.h>
|
|
#include <xvtility.h>
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TSheet_control
|
|
///////////////////////////////////////////////////////////
|
|
|
|
class TSheet_control : public TControl
|
|
{
|
|
enum { FIRST_FIELD = 101, MAX_COL = 256 };
|
|
|
|
TSheet* _sheet;
|
|
long _cur_rec;
|
|
|
|
// @cmember:(INTERNAL) Tipo di ogni colonna
|
|
byte _type[MAX_COL];
|
|
|
|
// @cmember:(INTERNAL) Indica se e attivata la gestione dei check delle righe
|
|
bool _check_enabled;
|
|
|
|
// @cmember:(INTERNAL) Array di righe attivate
|
|
TBit_array _checked;
|
|
|
|
// @cmember:(INTERNAL) Array di righe disabilitate
|
|
TBit_array _disabled;
|
|
|
|
// @cmember:(INTERNAL) Array delle largezze standard
|
|
int _default_width[MAX_COL];
|
|
|
|
byte _save_columns_order;
|
|
|
|
protected: // TControl
|
|
//@cmember Gestisce gli eventi delle celle
|
|
virtual bool event_handler(XI_OBJ* itf, XI_EVENT* xiev);
|
|
|
|
protected:
|
|
long items() const { return _sheet->items(); }
|
|
TToken_string& row(long n) const { return _sheet->row(n); }
|
|
|
|
int rec2row(long rec) const;
|
|
long row2rec(int row) const;
|
|
|
|
void make_current(long rec);
|
|
XI_OBJ* find_column(int col) const;
|
|
XI_OBJ* find_column(const char* head) const;
|
|
|
|
public: // TControl
|
|
virtual void set_rect(const RCT& r);
|
|
|
|
public:
|
|
long selected() const { return _cur_rec; }
|
|
void select(long n);
|
|
void set_focus_rec(long rec);
|
|
|
|
void enable_check(bool on);
|
|
bool check_enabled() const { return _check_enabled; }
|
|
void check(long n, bool on);
|
|
void toggle(long n);
|
|
bool checked(long n) const { return _checked[n]; }
|
|
long checked() const { return _checked.ones(); }
|
|
bool one_checked() const;
|
|
|
|
int visible_rows() const;
|
|
|
|
void enable_row(long r, bool on);
|
|
void disable_row(long r);
|
|
bool row_enabled(long n) const { return _disabled[n] == FALSE; }
|
|
bool one_enabled() const { return _disabled.ones() < _sheet->items(); }
|
|
|
|
byte column_type(int c) const { CHECKD(c >= 0 && c < MAX_COL, "Bad column ", c); return _type[c]; }
|
|
void align_column(int c, bool right);
|
|
|
|
void set_columns_order(TToken_string* order);
|
|
void save_columns_order(const TEdit_field& f) const;
|
|
void load_columns_order(const TEdit_field& f);
|
|
|
|
void update(long n = -1);
|
|
bool head(int c, TString& str) const;
|
|
|
|
TSheet_control(WINDOW sheet, short cid, short x, short y, short dx, short dy,
|
|
const char* flags, const char* head);
|
|
virtual ~TSheet_control() {}
|
|
};
|
|
|
|
|
|
TSheet_control::TSheet_control(
|
|
WINDOW parent, // @parm Finestra alla quale appartiene lo spreadsheet
|
|
short cid, // @parm Identificatore
|
|
short x, // @parm Coordinata x (in caratteri) nel quale posizionare lo spreadsheet
|
|
short y, // @parm Coordinata y (in caratteri) nel quale posizionare lo spreadsheet
|
|
short dx, // @parm Larghezza (in caratteri) dello spreasheet
|
|
short dy, // @parm Lunghezza (in caratteri) dello spreasheet
|
|
const char* flags, // @parm Flags di abilitazione
|
|
const char* head) // @parm Titolo delle colonne
|
|
: _sheet(NULL), _cur_rec(0), _check_enabled(FALSE),
|
|
_save_columns_order(FALSE)
|
|
|
|
{
|
|
const int NUMBER_WIDTH = 7;
|
|
short v_width[MAX_COL];
|
|
short m_width[MAX_COL];
|
|
int fixed_columns = 1; // Number of fixed columns
|
|
int lines_in_cell = 1;
|
|
|
|
_sheet = (TSheet*)xvt_vobj_get_data(parent);
|
|
|
|
// Calcolo larghezza massima tabella
|
|
|
|
TToken_string header(head);
|
|
TToken_string new_header(header.size());
|
|
int f_width = NUMBER_WIDTH; // Stima larghezza colonne fisse
|
|
int max_width = f_width; // Stima larghezza della colonna piu' grande
|
|
int lines_in_header = 1;
|
|
const char * h;
|
|
|
|
int i = 0;
|
|
for (h = header.get(); h && i < MAX_COL; h = header.get(), i++)
|
|
{
|
|
_type[i] = ' ';
|
|
TString testa(h);
|
|
|
|
char* t = testa.get_buffer();
|
|
for (int c = 0; t[c]; c++)
|
|
{
|
|
if (t[c] == '\\' && (t[c+1] == 'n' || t[c+1] == 'r'))
|
|
{
|
|
t[c] = '\n';
|
|
strcpy(t+c+1, t+c+2);
|
|
}
|
|
if (t[c] == '\n')
|
|
lines_in_header = 2;
|
|
}
|
|
|
|
const int at = testa.rfind('@');
|
|
int v = testa.len(); // Video width
|
|
if (at >= 0)
|
|
{
|
|
const TString& wi = testa.mid(at+1);
|
|
v = atoi(wi);
|
|
if (wi.find('F') >= 0)
|
|
{
|
|
fixed_columns++;
|
|
f_width += v+1;
|
|
}
|
|
if (wi.find('R') >= 0)
|
|
_type[i] = 'R'; else
|
|
if (wi.find('V') >= 0)
|
|
_type[i] = 'V'; else
|
|
if (wi.find('P') >= 0)
|
|
_type[i] = 'P'; else
|
|
if (wi.find('M') >= 0)
|
|
_type[i] = 'M'; else
|
|
if (wi.find('C') >= 0)
|
|
_type[i] = 'C';
|
|
|
|
if (i == 0 && v <= 1)
|
|
{
|
|
_type[i] = 'C';
|
|
_check_enabled = TRUE;
|
|
fixed_columns++;
|
|
f_width += v+1;
|
|
}
|
|
|
|
testa.cut(at);
|
|
if (v == 0) v = at;
|
|
}
|
|
|
|
if (v > 64)
|
|
{
|
|
lines_in_cell = (v-1) / 64 + 1;
|
|
v = 64;
|
|
}
|
|
m_width[i] = v*lines_in_cell + 1;
|
|
v_width[i] = v+1;
|
|
if (v > max_width)
|
|
max_width = v;
|
|
|
|
new_header.add(testa);
|
|
}
|
|
|
|
// Calcola rettangolo massimo per lo sheet
|
|
// RCT rct; coord2rct(parent, x, y, dx, dy, rct);
|
|
// rct.right -= 2*XI_FU_MULTIPLE; // toglie scroll-bar
|
|
RCT rct; coord2rct(parent, x, y, -2, -2, rct);
|
|
|
|
// Controlla se ci sono troppe colonne fisse
|
|
if ((f_width+max_width)*XI_FU_MULTIPLE > rct.right)
|
|
fixed_columns = 1;
|
|
|
|
XI_OBJ* itf = get_interface(parent);
|
|
|
|
XI_OBJ_DEF* listdef = xi_add_list_def(NULL, cid,
|
|
rct.top, rct.left, rct.bottom-rct.top,
|
|
XI_ATR_ENABLED | XI_ATR_VISIBLE | XI_ATR_NAVIGATE,
|
|
NORMAL_COLOR, NORMAL_BACK_COLOR, // normal
|
|
NORMAL_COLOR, DISABLED_BACK_COLOR, // disabled
|
|
FOCUS_COLOR, // active
|
|
0);
|
|
|
|
listdef->app_data = (long)this;
|
|
|
|
XI_LIST_DEF* l = listdef->v.list;
|
|
l->min_heading_height = xi_button_calc_height_font(xi_get_system_font()) * lines_in_header;
|
|
// l->min_heading_height = xi_button_calc_height_font_id(xvt_default_font()) * lines_in_header;
|
|
l->max_lines_in_cell = lines_in_cell;
|
|
l->sizable_columns = TRUE;
|
|
l->movable_columns = TRUE;
|
|
l->fixed_columns = fixed_columns;
|
|
l->scroll_bar = TRUE;
|
|
l->scroll_bar_button = TRUE;
|
|
l->white_space_color = MASK_DARK_COLOR;
|
|
l->rule_color = MASK_DARK_COLOR;
|
|
#ifdef LINUX
|
|
l->scroll_on_thumb_track = TRUE;
|
|
#endif
|
|
|
|
// Definizione della prima colonna (numero di riga)
|
|
const long attr = XI_ATR_VISIBLE | XI_ATR_RJUST | XI_ATR_SELECTABLE;
|
|
XI_OBJ_DEF* coldef = xi_add_column_def(listdef, FIRST_FIELD+1000-1, attr, 0,
|
|
2 * XI_FU_MULTIPLE, NUMBER_WIDTH , "");
|
|
|
|
coldef->app_data = (long)this;
|
|
coldef->v.column->heading_platform = TRUE;
|
|
coldef->v.column->column_platform = TRUE;
|
|
coldef->v.column->center_heading = TRUE;
|
|
|
|
for (h = new_header.get(0), i = 0; h && i < MAX_COL; h = new_header.get(), i++)
|
|
{
|
|
long attr = XI_ATR_VISIBLE | XI_ATR_ENABLED | XI_ATR_AUTOSCROLL | XI_ATR_READONLY;
|
|
if (_type[i] == 'C')
|
|
attr |= XI_ATR_SELECTABLE;
|
|
if (_type[i] == 'R' || _type[i] == 'V' || _type[i] == 'P') // Right, Currency, Price
|
|
attr |= XI_ATR_RJUST;
|
|
coldef = xi_add_column_def(listdef, FIRST_FIELD+i+1000, attr, i+1,
|
|
v_width[i] * XI_FU_MULTIPLE, m_width[i], (char*)h);
|
|
|
|
coldef->app_data = (long)this;
|
|
coldef->v.column->heading_platform = TRUE;
|
|
coldef->v.column->center_heading = TRUE;
|
|
if (m_width[i] > 64)
|
|
coldef->v.column->wrap_text = TRUE;
|
|
|
|
if (i == 0 && _type[i] == 'C')
|
|
{
|
|
coldef->v.column->icon_rid = ICO_CHECK_ON;
|
|
coldef->v.column->icon_mode = XIM_ICON_HAS_PRIORITY;
|
|
if (l->min_heading_height < 20)
|
|
l->min_heading_height = 20;
|
|
}
|
|
}
|
|
|
|
RCT rd; xi_get_def_rect(listdef, (XinRect *) &rd);
|
|
if ((rd.right - rd.left) > (rct.right - rct.left))
|
|
l->width = rct.right - rct.left;
|
|
|
|
_obj = xi_create(itf, listdef); // Create the whole thing!
|
|
xi_dequeue(); // Flush events in XOL
|
|
xi_tree_free(listdef); // Free definitions
|
|
|
|
CHECKD(_obj, "Can't create spreadsheet ", cid);
|
|
update_tab_cid();
|
|
|
|
// Se la finestra e' troppo grande riducila
|
|
RCT cli; xvt_vobj_get_client_rect(parent, &cli);
|
|
xi_get_rect(_obj, (XinRect*)&rct);
|
|
|
|
const int extra = (cli.right - (rct.right-rct.left+2*XI_FU_MULTIPLE)) / 2;
|
|
if (extra > XI_FU_MULTIPLE)
|
|
{
|
|
WINDOW main_win = _sheet->win();
|
|
xvt_vobj_get_outer_rect(main_win, &cli);
|
|
cli.left += extra;
|
|
cli.right -= extra;
|
|
xvt_vobj_move(main_win, &cli);
|
|
xvt_vobj_get_client_rect(parent, &cli);
|
|
}
|
|
|
|
int num;
|
|
XI_OBJ** column = xi_get_member_list(_obj, &num);
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
RCT rct; xi_get_rect(column[i], (XinRect *) &rct);
|
|
_default_width[i] = rct.right - rct.left;
|
|
}
|
|
}
|
|
|
|
void TSheet_control::set_rect(const RCT& r)
|
|
{
|
|
const int width = r.right - r.left - 2*XI_FU_MULTIPLE;
|
|
const int height = r.bottom - r.top;
|
|
xi_set_list_size(_obj, height, width);
|
|
}
|
|
|
|
// Converts a row number in the correspondig record number
|
|
int TSheet_control::rec2row(long record) const
|
|
{
|
|
int rows;
|
|
const long* rec = xi_get_list_info(_obj, &rows);
|
|
int r = int(record - rec[0]);
|
|
if (r < 0 || r >= rows)
|
|
r = -1;
|
|
return r;
|
|
}
|
|
|
|
// Converts a row number in the correspondig record number
|
|
long TSheet_control::row2rec(int row) const
|
|
{
|
|
int rows;
|
|
const long* handle = xi_get_list_info(_obj, &rows);
|
|
|
|
if (row < 0)
|
|
row = 0;
|
|
else
|
|
{
|
|
if (row >= rows)
|
|
row = rows-1;
|
|
}
|
|
const long r = handle[row];
|
|
CHECKD(r >= 0 && r < items(), "Sheet line out of range: ", row);
|
|
|
|
return r;
|
|
}
|
|
|
|
int TSheet_control::visible_rows() const
|
|
{
|
|
return xi_get_visible_rows(_obj, NULL, NULL);
|
|
}
|
|
|
|
void TSheet_control::update(long n)
|
|
{
|
|
if (n >= 0)
|
|
{
|
|
const int riga = rec2row(n);
|
|
if (riga >= 0)
|
|
{
|
|
XI_OBJ row;
|
|
XI_MAKE_ROW(&row, _obj, riga);
|
|
xi_cell_request(&row);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// xi_cell_request(_obj);
|
|
int num = 0;
|
|
const long* handle = xi_get_list_info(_obj, &num);
|
|
|
|
bool scroll_first = items() == 0; // || !owner().mask().is_running();
|
|
if (!scroll_first)
|
|
{
|
|
int first = 0, last = 0;
|
|
xi_get_visible_rows(_obj, &first, &last);
|
|
n = handle[first];
|
|
scroll_first = n > items();
|
|
}
|
|
|
|
if (scroll_first)
|
|
xi_scroll(_obj, XI_SCROLL_FIRST);
|
|
else
|
|
xi_scroll_rec(_obj, n, NORMAL_COLOR, XI_ATR_ENABLED, 0);
|
|
}
|
|
}
|
|
|
|
void TSheet_control::make_current(long rec)
|
|
{
|
|
const long old = _cur_rec;
|
|
_cur_rec = rec;
|
|
|
|
XI_OBJ o;
|
|
const int oldrow = rec2row(old);
|
|
if (oldrow >= 0)
|
|
{
|
|
XI_MAKE_ROW(&o, _obj, oldrow);
|
|
xi_cell_request(&o);
|
|
}
|
|
const int newrow = rec2row(rec);
|
|
if (newrow >= 0 && newrow != oldrow)
|
|
{
|
|
XI_MAKE_ROW(&o, _obj, newrow);
|
|
xi_cell_request(&o);
|
|
}
|
|
}
|
|
|
|
void TSheet_control::select(long rec)
|
|
{
|
|
if (rec >= 0 && rec < items())
|
|
{
|
|
int rows;
|
|
const long* handle = xi_get_list_info(_obj, &rows);
|
|
|
|
int first = 0, last = 0;
|
|
xi_get_visible_rows(_obj, &first, &last);
|
|
|
|
if (rec < handle[first] || rec > handle[last])
|
|
xi_scroll_rec(_obj, rec, NORMAL_COLOR, XI_ATR_ENABLED, 0);
|
|
}
|
|
make_current(rec);
|
|
}
|
|
|
|
void TSheet_control::set_focus_rec(long rec)
|
|
{
|
|
if (rec < 0)
|
|
rec = selected();
|
|
int r = rec2row(rec);
|
|
if (r < 0)
|
|
{
|
|
select(rec);
|
|
r = rec2row(rec);
|
|
}
|
|
|
|
const int c = _type[0] == 'C' ? 2 : 1;
|
|
XI_OBJ cell; XI_MAKE_CELL(&cell, _obj, r, c);
|
|
xi_set_focus(&cell);
|
|
}
|
|
|
|
XI_OBJ* TSheet_control::find_column(
|
|
int col) const // @parm Indice o identificatore colonna
|
|
{
|
|
CHECKD(col >= 0, "Bad column ", col);
|
|
if (col < FIRST_FIELD) // Se e' un indice trasformalo in identificatore
|
|
col += FIRST_FIELD + 1000;
|
|
|
|
int num;
|
|
XI_OBJ** columns = xi_get_member_list(_obj, &num);
|
|
int c;
|
|
|
|
for (c = num-1; c >= 0; c--)
|
|
{
|
|
if (columns[c]->cid == col)
|
|
break;
|
|
}
|
|
return c >= 0 ? columns[c] : NULL;
|
|
}
|
|
|
|
XI_OBJ* TSheet_control::find_column(
|
|
const char* head) const // @parm testata colonna
|
|
{
|
|
int num;
|
|
XI_OBJ** column = xi_get_member_list(_obj, &num);
|
|
int c;
|
|
|
|
for (c = num-1; c >= 0; c--)
|
|
{
|
|
char str[80];
|
|
xi_get_text(column[c], str, sizeof(str));
|
|
if (strcmp(str, head) == 0)
|
|
break;
|
|
}
|
|
return c >= 0 ? column[c] : NULL;
|
|
}
|
|
|
|
bool TSheet_control::head(int c, TString& str) const
|
|
{
|
|
XI_OBJ* col = find_column(c);
|
|
if (col != NULL)
|
|
xi_get_text(col, str.get_buffer(80), 80);
|
|
else
|
|
str.cut(0);
|
|
return col != NULL;
|
|
}
|
|
|
|
void TSheet_control::enable_check(bool on)
|
|
{
|
|
_check_enabled = on && _type[0] == 'C';
|
|
if (_type[0] == 'C')
|
|
{
|
|
XI_OBJ* column = find_column(1101);
|
|
CHECK(column, "Can't find checkable column");
|
|
dword attr = xi_get_attrib(column);
|
|
if (_check_enabled) attr |= XI_ATR_ENABLED;
|
|
else attr &= ~XI_ATR_ENABLED;
|
|
|
|
xi_set_attrib(column, attr); // Set new attributes
|
|
}
|
|
}
|
|
|
|
bool TSheet_control::one_checked() const
|
|
{
|
|
bool yes = FALSE;
|
|
if (check_enabled())
|
|
{
|
|
const long first = _checked.first_one();
|
|
yes = first >= 0;
|
|
}
|
|
return yes;
|
|
}
|
|
|
|
// @mfunc Permette di attivare/disattivare una riga
|
|
void TSheet_control::check(
|
|
long n, // @parm Numero della riga da attivare/disattivare
|
|
bool on) // @parm Operazione da effettuare sulla riga:
|
|
//
|
|
// @flag TRUE | Attiva la riga <p n>.esima (default)
|
|
// @flag FALSE | Disattiva la riga <p n>.esima
|
|
{
|
|
if (n < 0)
|
|
{
|
|
if (on)
|
|
{
|
|
const long tot = items()-1;
|
|
if (tot >= 0)
|
|
{
|
|
_checked.set(tot); // Forza le dimensioni del bit array
|
|
_checked.set(); // Setta tutti i bit
|
|
|
|
// Elimina i bit in eccesso alla fine dell'array
|
|
for (long i = _checked.items()-1; i > tot; i--)
|
|
_checked.reset(i);
|
|
|
|
// Elimina i bit corrispondenti a righe disabilitate
|
|
if (_disabled.first_one() >= 0)
|
|
{
|
|
for (long i = tot; i >= 0; i--)
|
|
if (_disabled[i]) _checked.reset(i);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
_checked.reset();
|
|
|
|
// Aggiorna tutta la prima colonna
|
|
XI_OBJ* column = xi_get_obj(_obj, FIRST_FIELD+1000);
|
|
xi_cell_request(column);
|
|
}
|
|
else
|
|
{
|
|
if (!_disabled[n])
|
|
{
|
|
_checked.set(n, on);
|
|
// Aggiorna la riga
|
|
if (_sheet->is_running())
|
|
{
|
|
XI_OBJ cell; XI_MAKE_CELL(&cell, _obj, rec2row(n), 1);
|
|
xi_cell_request(&cell);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void TSheet_control::toggle(long n)
|
|
{
|
|
check(n, !checked(n));
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @mfunc Abilita/disabilita una riga
|
|
void TSheet_control::enable_row(
|
|
long n, // @parm Numero della riga da abilitare/diabilitare (default -1)
|
|
bool on) // @parm Operazione da svolgere sulla riga
|
|
//
|
|
// @flag TRUE | Abilita la riga <p n>-esima (default)
|
|
// @flag FALSE | Disabilita la riga <p n>-esima
|
|
|
|
// @comm Se <p n> e' minore di 0 allora vengono abilitate/disabilitate tutte le righe
|
|
{
|
|
if (n >= 0)
|
|
{
|
|
_disabled.set(n, !on);
|
|
}
|
|
else
|
|
{
|
|
if (on)
|
|
_disabled.reset();
|
|
else
|
|
{
|
|
const long tot = items()-1;
|
|
_disabled.set(tot); // Forza le dimensioni del bit-array
|
|
_disabled.set(); // Disabilita tutte le righe
|
|
|
|
// Resetta i bit in ecesso alla fine del bit-array
|
|
for (long i = _disabled.items()-1; i > tot; i--)
|
|
_disabled.reset(i);
|
|
}
|
|
}
|
|
update(n);
|
|
}
|
|
|
|
void TSheet_control::save_columns_order(const TEdit_field& field) const
|
|
{
|
|
if (_save_columns_order)
|
|
{
|
|
TString parag;
|
|
if (_sheet->get_ini_paragraph(field, parag))
|
|
{
|
|
TConfig config(CONFIG_USER, parag); // Apre il file di configurazione
|
|
|
|
TToken_string order(127); // Nuovo ordine delle colonne
|
|
if (_save_columns_order == TRUE) // Se vale 3 devo solo resettare
|
|
{
|
|
int num;
|
|
XI_OBJ** column = xi_get_member_list(_obj, &num);
|
|
for (int i = 0; i < num; i++) // Scorre tutte le colonne
|
|
{
|
|
TString h;
|
|
char head[80];
|
|
|
|
xi_get_text(column[i], head, sizeof(head));
|
|
for (const char * s = head; *s; s++)
|
|
{
|
|
if (*s == '\n')
|
|
h << "\\n";
|
|
else
|
|
h << *s;
|
|
}
|
|
order.add(h);
|
|
RCT rct; xi_get_rect(column[i], (XinRect *) &rct);
|
|
order << ',' << rct.right - rct.left;
|
|
}
|
|
config.set("Browse", order, NULL, TRUE, field.dlg());
|
|
}
|
|
else
|
|
config.remove("Browse", field.dlg());
|
|
}
|
|
}
|
|
}
|
|
|
|
void TSheet_control::load_columns_order(const TEdit_field& field)
|
|
{
|
|
TFilename parag;
|
|
if (_sheet->get_ini_paragraph(field, parag))
|
|
{
|
|
TConfig config(CONFIG_USER, parag);
|
|
const int index = field.dlg();
|
|
TToken_string order(esc(config.get("Browse", NULL, index)));
|
|
if (order.empty_items())
|
|
config.remove("Browse", index);
|
|
else
|
|
set_columns_order(&order);
|
|
}
|
|
_save_columns_order = FALSE;
|
|
}
|
|
|
|
void TSheet_control::align_column(int c, bool right)
|
|
{
|
|
XI_OBJ* column = find_column(c);
|
|
CHECKD(column, "Can't find numeric column ", c);
|
|
dword attr = xi_get_attrib(column);
|
|
if (right)
|
|
attr |= XI_ATR_RJUST;
|
|
else
|
|
attr &= ~XI_ATR_RJUST;
|
|
xi_set_attrib(column, attr);
|
|
_type[c] = right ? 'R' : ' ';
|
|
}
|
|
|
|
void TSheet_control::set_columns_order(TToken_string* order)
|
|
{
|
|
XI_OBJ* itf = get_interface();
|
|
XI_OBJ* focus = xi_get_focus(itf);
|
|
xi_set_focus(itf);
|
|
|
|
int num_cols;
|
|
xi_get_member_list(_obj, &num_cols); //verificare
|
|
|
|
// Costante da sottrarre nella xi_column_set_pixel_width altrimenti la somma due volte!
|
|
const int offset = 2 * (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
|
|
|
|
if (order == NULL)
|
|
{
|
|
for (int index = 0; index < num_cols; index++)
|
|
{
|
|
const short cid = FIRST_FIELD + 1000 + index - 1;
|
|
XI_OBJ* col = find_column(cid);
|
|
if (col)
|
|
{
|
|
xi_move_column(col, index);
|
|
RCT rct; xi_get_rect(col, (XinRect*)&rct);
|
|
if (_default_width[index] != rct.right - rct.left)
|
|
xi_column_set_pixel_width(col, _default_width[index]-offset);
|
|
}
|
|
}
|
|
_save_columns_order = 0x3;
|
|
}
|
|
else
|
|
{
|
|
TString head(23);
|
|
TToken_string col(8, ',');
|
|
int pos = 0;
|
|
for (col = order->get(0); !col.blank(); col = order->get(), pos++)
|
|
{
|
|
head = col.get(0);
|
|
const int width = col.get_int();
|
|
XI_OBJ* column = find_column(head);
|
|
if (column) // Controlla che esista ancora
|
|
{
|
|
if (pos > 0 && pos < num_cols)
|
|
xi_move_column(column, pos); // Sposta la colonna se possibile
|
|
if (width > XI_FU_MULTIPLE) // Se ha una larghezza valida
|
|
xi_column_set_pixel_width(column, width - offset);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (focus)
|
|
xi_set_focus(focus);
|
|
}
|
|
|
|
HIDDEN long _rec_to_select = -1;
|
|
// Certified 75%
|
|
bool TSheet_control::event_handler(XI_OBJ* itf, XI_EVENT *xiev)
|
|
{
|
|
BOOLEAN& refused = xiev->refused;
|
|
|
|
switch (xiev->type)
|
|
{
|
|
case XIE_GET_FIRST:
|
|
if (items() > 0L)
|
|
{
|
|
long n = items() * (long)xiev->v.rec_request.percent / 100L;
|
|
if (n < 0L) n = 0L;
|
|
xiev->v.rec_request.data_rec = n;
|
|
}
|
|
else
|
|
refused = TRUE;
|
|
break;
|
|
case XIE_GET_LAST:
|
|
xiev->v.rec_request.data_rec = items()-1;
|
|
break;
|
|
case XIE_GET_PREV:
|
|
case XIE_GET_NEXT:
|
|
{
|
|
const long n = xiev->v.rec_request.spec_rec + (xiev->type == XIE_GET_NEXT ? +1 : -1) ;
|
|
if (n < 0 || n >= items())
|
|
refused = TRUE;
|
|
else
|
|
xiev->v.rec_request.data_rec = n;
|
|
}
|
|
break;
|
|
case XIE_CELL_REQUEST:
|
|
{
|
|
const long rec = xiev->v.cell_request.rec;
|
|
const char* src = NULL;
|
|
int nm;
|
|
XI_OBJ** obj = xi_get_member_list(xiev->v.cell_request.list, &nm);
|
|
const int num = xiev->v.cell_request.col_nbr;
|
|
const int cid = obj[num]->cid - 1000;
|
|
|
|
if (cid >= FIRST_FIELD)
|
|
{
|
|
if (rec >= 0 && rec < items())
|
|
{
|
|
const int col = cid - FIRST_FIELD;
|
|
switch (_type[col])
|
|
{
|
|
case 'C': // Set value for "checkable" cell
|
|
{
|
|
const bool on = checked(rec);
|
|
xiev->v.cell_request.icon_rid = on ? ICO_CHECK_ON : ICO_CHECK_OFF;
|
|
}
|
|
break;
|
|
case 'M': // Set value for "roman" cell
|
|
src = itor(atoi(row(rec).get(col)));
|
|
break;
|
|
case 'V': // Set value for "value" cell
|
|
{
|
|
const real r = row(rec).get(col);
|
|
TCurrency c(r);
|
|
src = c.string(TRUE);
|
|
}
|
|
break;
|
|
case 'P': // Set value for "price" cell
|
|
{
|
|
const real r = row(rec).get(col);
|
|
TPrice c(r);
|
|
src = c.string(TRUE);
|
|
}
|
|
break;
|
|
default: // Set value for "normal" cell
|
|
src = row(rec).get(col);
|
|
break;
|
|
}
|
|
|
|
if (_disabled[rec])
|
|
{
|
|
xiev->v.cell_request.color = DISABLED_COLOR;
|
|
xiev->v.cell_request.back_color = DISABLED_BACK_COLOR;
|
|
}
|
|
else
|
|
if (rec == _cur_rec)
|
|
{
|
|
xiev->v.cell_request.color = FOCUS_COLOR;
|
|
xiev->v.cell_request.back_color = FOCUS_BACK_COLOR;
|
|
}
|
|
else
|
|
_sheet->get_cell_colors(rec, col, xiev->v.cell_request.color, xiev->v.cell_request.back_color);
|
|
}
|
|
else
|
|
refused = TRUE;
|
|
}
|
|
else
|
|
{
|
|
xiev->v.cell_request.color = NORMAL_COLOR;
|
|
// src = format("%ld", rec+1); // Niente piu' numeri di riga!
|
|
}
|
|
|
|
char* dst = xiev->v.cell_request.s;
|
|
if (src && *src)
|
|
{
|
|
const int len = xiev->v.cell_request.len;
|
|
strncpy(dst, src, len);
|
|
dst[len-1] = '\0';
|
|
}
|
|
else
|
|
*dst = '\0';
|
|
}
|
|
break;
|
|
case XIE_DBL_CELL:
|
|
{
|
|
const long rec = row2rec(xiev->v.xi_obj->v.cell.row);
|
|
if (!_disabled[rec])
|
|
{
|
|
make_current(rec);
|
|
_sheet->stop_run(K_ENTER);
|
|
}
|
|
else
|
|
refused = TRUE;
|
|
}
|
|
break;
|
|
case XIE_ON_LIST:
|
|
_sheet->notify_focus_field(id());
|
|
break;
|
|
case XIE_ON_ROW:
|
|
{
|
|
const long rec = row2rec(xiev->v.xi_obj->v.row);
|
|
if (_disabled[rec])
|
|
{
|
|
refused = TRUE;
|
|
// Cerca la prossima riga abilitata e valida
|
|
const int dir = rec > selected() ? +1: -1;
|
|
const long max = items();
|
|
for (long r = rec+dir; r >= 0 && r < max; r += dir) if (!_disabled[r])
|
|
{
|
|
_sheet->post_select(r);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_sheet->_select_row < 0)
|
|
make_current(rec);
|
|
else
|
|
_rec_to_select = rec;
|
|
}
|
|
}
|
|
break;
|
|
case XIE_GET_PERCENT:
|
|
{
|
|
const long rec = xiev->v.get_percent.record;
|
|
long n = items(); if (n <= 0) n = 1;
|
|
xiev->v.get_percent.percent = int(rec * 100L / n);
|
|
}
|
|
break;
|
|
case XIE_SELECT:
|
|
if (xiev->v.xi_obj->type == XIT_ROW)
|
|
{
|
|
const int row = xiev->v.select.xi_obj->v.row;
|
|
const long rec = row2rec(row);
|
|
if (row_enabled(rec))
|
|
{
|
|
int num;
|
|
XI_OBJ** column = xi_get_member_list(_obj, &num);
|
|
const int col = xiev->v.select.column;
|
|
|
|
const short cid = column[col]->cid - 1000;
|
|
if (cid >= FIRST_FIELD)
|
|
{
|
|
if (check_enabled())
|
|
toggle(rec);
|
|
}
|
|
else
|
|
{
|
|
if (_cur_rec == rec)
|
|
_sheet->on_key(K_CTRL+'G');
|
|
}
|
|
const int c = _type[0] == 'C' ? 2 : 1;
|
|
XI_OBJ cell; XI_MAKE_CELL(&cell, _obj, row, c);
|
|
xi_set_focus(&cell);
|
|
make_current(rec);
|
|
}
|
|
}
|
|
refused = TRUE;
|
|
break;
|
|
case XIE_COL_MOVE:
|
|
if (xiev->v.column.in_fixed ||
|
|
xiev->v.column.col_nbr < xi_get_fixed_columns(xiev->v.column.list))
|
|
refused = TRUE;
|
|
else
|
|
_save_columns_order = TRUE;
|
|
break;
|
|
case XIE_COL_SIZE:
|
|
{
|
|
if (_obj->v.list->hsb_win)
|
|
_save_columns_order = TRUE;
|
|
else
|
|
refused = TRUE; // Non permetto il resize in assenza di scroll bar orizzontale
|
|
}
|
|
break;
|
|
case XIE_BUTTON:
|
|
if (xiev->v.xi_obj->type == XIT_LIST)
|
|
_sheet->on_key(K_CTRL+'N');
|
|
break;
|
|
case XIE_XVT_EVENT:
|
|
if (xiev->v.xvte.type == E_CHAR)
|
|
{
|
|
const KEY k = e_char_to_key(&xiev->v.xvte);
|
|
long rec = -1;
|
|
switch (k)
|
|
{
|
|
|
|
case K_SPACE:
|
|
if (_check_enabled)
|
|
check(selected(), !checked(selected()));
|
|
break;
|
|
case K_ENTER:
|
|
if (_disabled[_cur_rec])
|
|
break;
|
|
case K_ESC:
|
|
_sheet->stop_run(k);
|
|
break;
|
|
case K_LHOME:
|
|
rec = 0;
|
|
break;
|
|
case K_PREV:
|
|
rec = _cur_rec - visible_rows();
|
|
if (rec < 0) rec = 0;
|
|
break;
|
|
case K_NEXT:
|
|
rec = _cur_rec + visible_rows();
|
|
if (rec >= items())
|
|
rec = items()-1;
|
|
break;
|
|
case K_LEND:
|
|
rec = items()-1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (rec >= 0)
|
|
{
|
|
_sheet->post_select(rec);
|
|
refused = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return !refused;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TQuery_field
|
|
///////////////////////////////////////////////////////////
|
|
|
|
class TQuery_field : public TOperable_field
|
|
{
|
|
protected:
|
|
virtual void create(WINDOW parent);
|
|
|
|
public:
|
|
TSheet_control* sheet() const { return (TSheet_control*)_ctl; }
|
|
|
|
TQuery_field(TMask* m) : TOperable_field(m) { }
|
|
virtual ~TQuery_field() { }
|
|
};
|
|
|
|
void TQuery_field::create(WINDOW parent)
|
|
{
|
|
_ctl = new TSheet_control(parent, dlg(),
|
|
_ctl_data._x, _ctl_data._y,
|
|
_ctl_data._width, (int)_ctl_data._size,
|
|
_ctl_data._flags, _ctl_data._prompt);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TSheet
|
|
///////////////////////////////////////////////////////////
|
|
|
|
#define DLG_QUERY 25883
|
|
|
|
TSheet::TSheet(short x, short y, short dx, short dy,
|
|
const char* title, const char* head,
|
|
byte buttons, short sht_y, WINDOW parent)
|
|
: TMask(title, 1, dx, dy, x, y, parent),
|
|
_sheet(NULL), _select_row(-1), _parked(-1)
|
|
{
|
|
#ifdef OLD_FASHIONED_BROWSE
|
|
if (sht_y > 0) // Crea notebook se TBrowse_sheet
|
|
{
|
|
create_book(false); // Crea notebook e poi ...
|
|
create_page(title, 0); // ... la sua prima pagina
|
|
}
|
|
#endif
|
|
create_bar(1); // Crea toolbar in alto
|
|
|
|
TQuery_field* qf = new TQuery_field(this);
|
|
qf->construct(DLG_QUERY, head, 1, sht_y, 0, page_win(0), "", 0);
|
|
fields_array().add(qf);
|
|
_sheet = qf->sheet();
|
|
|
|
if (!(buttons & 0x10))
|
|
add_button(DLG_SELECT, TR("~Selezione"), K_ENTER, BMP_OK);
|
|
|
|
if (check_enabled())
|
|
{
|
|
add_button(DLG_USER, TR("~Tutti"), 0, BMP_SELECT);
|
|
set_handler(DLG_USER, tutti_handler);
|
|
}
|
|
|
|
if (buttons & 0x01) add_button(DLG_LINK, TR("Colle~ga"), K_CTRL+'G', BMP_LINK);
|
|
if (buttons & 0x02) add_button(DLG_NEWREC, TR("~Nuovo"), K_INS, BMP_NEWREC);
|
|
if (buttons & 0x04) add_button(DLG_DELREC, "~Elimina", K_DEL, BMP_DELREC);
|
|
|
|
add_button(DLG_SAVEREC, TR("~Esporta"), 0, TOOL_EXPORT);
|
|
set_handler(DLG_SAVEREC, export_handler);
|
|
|
|
if (buttons & 0x08) add_button(DLG_QUIT, "Fine", K_ESC, BMP_QUIT);
|
|
else add_button(DLG_CANCEL, "Annulla", K_ESC, BMP_CANCEL);
|
|
|
|
xvt_toolbar_realize(toolbar()); // Necessario per calcolare dimensioni corrette dello sheet
|
|
}
|
|
|
|
TSheet::~TSheet()
|
|
{
|
|
// delete _sheet; // Guy bestia: Already deleted by TMask!
|
|
}
|
|
|
|
TSheet_control& TSheet::sheet()
|
|
{ return *_sheet; }
|
|
|
|
// Costruisce l'identificatore del paragrafo contenente la disposizione
|
|
// delle colonne del campo f
|
|
bool TSheet::get_ini_paragraph(const TEdit_field& f, TString& name) const
|
|
{
|
|
const TMask& m = f.mask();
|
|
name = m.source_file().name();
|
|
if (name.blank()) // Maschera dinamica
|
|
name = main_app().name();
|
|
else
|
|
name = name.before("."); // Nome della maschera senza estensione
|
|
const int index = m.number();
|
|
CHECKD(index >= 0 && index <= 8, "Bad mask index:", index);
|
|
if (index > 0) // Aggiunge l'eventuale numero di sotto-maschera
|
|
name << '(' << index << ')';
|
|
return true;
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @mfunc Aggiunge un bottone nella finestra
|
|
void TSheet::add_button(
|
|
short id, // @parm Identificatore del bottone da aggiungere
|
|
const char* caption, // @parm Testo del bottone da aggiungere
|
|
KEY key, // @parm Combinazione di tasti corrispondente
|
|
short bmp_up, // @parm Bitmap normale
|
|
short bmp_dn) // @parm Bitmap premuta
|
|
{
|
|
if (bmp_up <= 0)
|
|
{
|
|
if (toolwin() == NULL_WIN)
|
|
create_bar(-2); // Forza la creazione della bottom bar
|
|
TButton_field& butt = TMask::add_button(id, MAX_PAGES, caption, 0, -1, 11, 2);
|
|
butt.set_exit_key(key);
|
|
}
|
|
else
|
|
{
|
|
TButton_tool& butt = add_button_tool(id, caption, bmp_up);
|
|
butt.set_exit_key(key);
|
|
}
|
|
}
|
|
|
|
bool TSheet::get_cell_colors(int row, int col, COLOR& fore, COLOR& back) const
|
|
{
|
|
fore = back = 0; // Default colors
|
|
if (EASY_RIDER && (row & 1))
|
|
back = EASY_RIDER_COLOR;
|
|
return false; // Not assigned
|
|
}
|
|
|
|
void TSheet::repos_buttons() const
|
|
{
|
|
if (_sheet == NULL)
|
|
return; // Sono ancora in fase di creazione: aspetta!
|
|
|
|
WINDOW btnwin = toolwin(); // was win()
|
|
RCT br, wr;
|
|
int buttons = 0;
|
|
FOR_EACH_MASK_FIELD((*this), f, c)
|
|
{
|
|
if (c->parent() == btnwin && c->is_kind_of(CLASS_BUTTON_FIELD))
|
|
{
|
|
if (buttons == 0)
|
|
c->get_rect(br);
|
|
buttons++;
|
|
}
|
|
}
|
|
|
|
if (buttons > 0)
|
|
{
|
|
xvt_vobj_get_client_rect(btnwin, &wr);
|
|
const short width = br.right - br.left;
|
|
const short height = br.bottom - br.top;
|
|
|
|
int space = (wr.right - buttons * width) / (buttons+1);
|
|
if (space < 0) space = 0;
|
|
int x = space;
|
|
const int y = (wr.bottom - height) / 2;
|
|
|
|
FOR_EACH_MASK_FIELD((*this), f, c)
|
|
{
|
|
if (c->parent() == btnwin && c->is_kind_of(CLASS_BUTTON_FIELD))
|
|
{
|
|
buttons--;
|
|
const PNT p = { y, x };
|
|
xvt_rect_set_pos(&br, p);
|
|
c->set_rect(br);
|
|
x += space+width;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Aggiusta anche lo spreadsheet se necessario
|
|
TMask_field& s = field(DLG_QUERY);
|
|
xvt_vobj_get_client_rect(s.parent(), &wr);
|
|
s.get_rect(br);
|
|
if (br.bottom > wr.bottom || (wr.bottom-br.bottom) > 48)
|
|
{
|
|
br.bottom = wr.bottom - br.left; // Lascio uno spazio in fondo pari al bordo sinistro
|
|
s.set_rect(br);
|
|
}
|
|
}
|
|
|
|
void TSheet::force_update(int r)
|
|
{
|
|
_sheet->update(r);
|
|
}
|
|
|
|
void TSheet::start_run()
|
|
{
|
|
const bool on = items() > 0 && _sheet->one_enabled();
|
|
|
|
// Abilita selezione se c'e' almeno un elemento
|
|
int pos = id2pos(DLG_SELECT);
|
|
if (pos >= 0)
|
|
fld(pos).enable(on);
|
|
|
|
pos = id2pos(DLG_LINK);
|
|
if (pos >= 0)
|
|
fld(pos).enable(on);
|
|
|
|
reset_parked();
|
|
|
|
repos_buttons();
|
|
force_update();
|
|
|
|
if (on)
|
|
{
|
|
long i = selected();
|
|
if (i < 0 || i >= items())
|
|
i = 0;
|
|
if (row_disabled(i))
|
|
for (i = 0; row_disabled(i); i++);
|
|
post_select(i);
|
|
}
|
|
}
|
|
|
|
long TSheet::selected() const
|
|
{ return _sheet->selected(); }
|
|
|
|
bool TSheet::check_enabled() const
|
|
{ return _sheet->check_enabled(); }
|
|
|
|
void TSheet::enable_check(bool on)
|
|
{ _sheet->enable_check(on); }
|
|
|
|
void TSheet::check(long n, bool on)
|
|
{ _sheet->check(n, on); }
|
|
|
|
bool TSheet::checked(long n) const
|
|
{ return _sheet->checked(n); }
|
|
|
|
long TSheet::checked() const
|
|
{ return _sheet->checked(); }
|
|
|
|
bool TSheet::one_checked() const
|
|
{ return _sheet->one_checked(); }
|
|
|
|
void TSheet::enable_row(long r, bool on)
|
|
{ _sheet->enable_row(r, on); }
|
|
|
|
bool TSheet::row_enabled(long r) const
|
|
{ return _sheet->row_enabled(r); }
|
|
|
|
bool TSheet::on_key(KEY key)
|
|
{
|
|
switch(key)
|
|
{
|
|
case K_ESC:
|
|
stop_run(key);
|
|
break;
|
|
case K_CTRL+'E':
|
|
case K_DEL:
|
|
if (items() && id2pos(DLG_DELREC) >= 0)
|
|
stop_run(K_DEL);
|
|
break;
|
|
case K_CTRL+'N':
|
|
if (id2pos(DLG_NEWREC) >= 0)
|
|
stop_run(K_INS);
|
|
break;
|
|
case K_CTRL+'G':
|
|
if (id2pos(DLG_LINK) >= 0)
|
|
stop_run(key);
|
|
break;
|
|
case K_CTRL+'S':
|
|
if (id2pos(DLG_SELECT) >= 0)
|
|
stop_run(K_ENTER);
|
|
break;
|
|
default:
|
|
key -= K_CTRL;
|
|
if (key >= 'A' && key <= 'Z')
|
|
{
|
|
for (int i = fields()-1; i >= 0; i--)
|
|
{
|
|
TMask_field& f = fld(i);
|
|
if (f.active() && f.is_kind_of(CLASS_BUTTON_FIELD))
|
|
{
|
|
TButton_field& b = (TButton_field&)f;
|
|
if (b.virtual_key() == key)
|
|
{
|
|
f.on_key(K_SPACE);
|
|
if (b.exit_key() > 0)
|
|
stop_run(b.exit_key());
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (check_enabled() && items() > 0)
|
|
{
|
|
switch(key)
|
|
{
|
|
case K_CTRL+'E':
|
|
export_handler(field(DLG_SAVEREC), K_SPACE);
|
|
break;
|
|
case K_CTRL+'T':
|
|
tutti_handler(field(DLG_USER), K_SPACE);
|
|
break;
|
|
case K_F7:
|
|
uncheck(-1);
|
|
break;
|
|
case K_F8:
|
|
check(-1);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @mfunc Seleziona una riga facendola diventare corrente
|
|
void TSheet::select(
|
|
long n) // @parm Riga da selezionare
|
|
{
|
|
_sheet->select(n);
|
|
}
|
|
|
|
void TSheet::post_select(long rec)
|
|
{
|
|
_select_row = rec;
|
|
}
|
|
|
|
void TSheet::on_idle()
|
|
{
|
|
if (_select_row >= 0)
|
|
{
|
|
const short focus_id = low_get_focus_id(win());
|
|
_sheet->select(_select_row);
|
|
if (focus_id == _sheet->id())
|
|
_sheet->set_focus_rec(-1);
|
|
_select_row = -1;
|
|
}
|
|
TMask::on_idle();
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @mfunc Ritorna il contenuto di una riga
|
|
//
|
|
// @rdesc Ritorna la <c TToken_string> con tutti gli elemnti della riga
|
|
TToken_string& TSheet::row(
|
|
long n) // @parm Riga di cui ritorna il contenuto (default -1)
|
|
|
|
// @comm Se viene passato un numero di riga minore di 1 viene ritornato il contenuto della riga
|
|
// selezionata.
|
|
{
|
|
if (n < 0)
|
|
n = selected();
|
|
if (n != _parked)
|
|
get_row(_parked = n, _park);
|
|
return _park;
|
|
}
|
|
|
|
bool TSheet::tutti_handler(TMask_field& f, KEY k)
|
|
{
|
|
if (k == K_SPACE)
|
|
{
|
|
TSheet& s = (TSheet&)f.mask();
|
|
if (s.check_enabled())
|
|
s.check(-1, !s.one_checked());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool TSheet::export_handler(TMask_field& f, KEY k)
|
|
{
|
|
if (k == K_SPACE)
|
|
{
|
|
TSheet& s = (TSheet&)f.mask();
|
|
FILE_SPEC fs;
|
|
TFilename name;
|
|
s.get_caption(name); name.ext("xls");
|
|
xvt_fsys_convert_str_to_fspec(name, &fs);
|
|
if (xvt_dm_post_file_save(&fs, TR("Selezionare il file di destinazione")) == FL_OK)
|
|
{
|
|
xvt_fsys_convert_fspec_to_str(&fs, name.get_buffer(), name.size());
|
|
ofstream xls(name);
|
|
const char sep = '\t';
|
|
TToken_string tab(128, sep);
|
|
|
|
TString80 str;
|
|
int columns = 0;
|
|
for (columns = 0; ; columns++)
|
|
{
|
|
if (s._sheet->head(columns, str))
|
|
tab.add(str);
|
|
else
|
|
break;
|
|
}
|
|
xls << tab << endl;
|
|
|
|
for (long n = 0; n < s.items(); n++)
|
|
{
|
|
const TToken_string& r = s.row(n);
|
|
tab = r;
|
|
tab.replace(r.separator(), sep);
|
|
tab.separator(sep);
|
|
for (int c = 0; c < columns; c++)
|
|
{
|
|
const char ct = s._sheet->column_type(c);
|
|
if (ct == 'P' || ct == 'V')
|
|
{
|
|
tab.get(c, str);
|
|
xvt_str_number_format(str.get_buffer(), str.size());
|
|
tab.add(str, c);
|
|
}
|
|
}
|
|
xls << tab << endl;
|
|
}
|
|
xls.close();
|
|
xvt_sys_goto_url(name, "open");
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void TSheet::save_columns_order(const TEdit_field& field)
|
|
{ sheet().save_columns_order(field); }
|
|
|
|
void TSheet::set_columns_order(TToken_string* col)
|
|
{ sheet().set_columns_order(col); }
|
|
|
|
void TSheet::load_columns_order(const TEdit_field& field)
|
|
{ sheet().load_columns_order(field); }
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TArray_sheet
|
|
///////////////////////////////////////////////////////////
|
|
|
|
TArray_sheet::TArray_sheet(short x, short y, short dx, short dy, const char* caption,
|
|
const char* head, byte buttons, short sht_y)
|
|
: TSheet(x, y, dx, dy, caption, head, buttons, sht_y)
|
|
{
|
|
TToken_string cap(caption);
|
|
if (cap.items() > 1)
|
|
{
|
|
cap.get(0);
|
|
FOR_EACH_TOKEN(cap, tok)
|
|
create_page(tok, 0);
|
|
}
|
|
}
|
|
|
|
// Certified 99%
|
|
bool TArray_sheet::destroy(int i)
|
|
{
|
|
uncheck(-1);
|
|
enable_row(-1);
|
|
reset_parked();
|
|
return _data.destroy(i, TRUE);
|
|
}
|
|
|
|
// @doc EXTERNAL
|
|
|
|
// @mfunc Aggiunge un elemento allo sheet
|
|
//
|
|
// @rdesc Ritorna il numero di elementi presenti nello sheet
|
|
long TArray_sheet::add(
|
|
const TToken_string& s) // @parm Oggetto da aggiungere
|
|
// @parm const TToken_string | *s | Oggetto da aggiungere passato per indirizzo
|
|
|
|
// @syntax add(const TToken_string& s)
|
|
// @syntax add(const TToken_string* s)
|
|
{
|
|
const long n = _data.add(s);
|
|
return n;
|
|
}
|
|
|
|
long TArray_sheet::add(TToken_string* s)
|
|
{
|
|
const long n = _data.add(s);
|
|
return n;
|
|
}
|
|
|
|
long TArray_sheet::insert(const TToken_string& s, long n)
|
|
{
|
|
_data.insert(s, (int)n);
|
|
const int maxrows=int(items());
|
|
for (int r = maxrows-1; r >n ; r--)
|
|
{
|
|
const bool enab= row_enabled(r);
|
|
enable_row(r,row_enabled(r+1));
|
|
enable_row(r+1,enab);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TCursor_sheet
|
|
///////////////////////////////////////////////////////////
|
|
|
|
bool TCursor_sheet::in_key(const TFieldref& fr) const
|
|
{
|
|
const int logic = _cursor->file().num();
|
|
if (fr.file() != 0 && fr.file() != logic)
|
|
return false;
|
|
|
|
const RecDes& rd = prefix().get_recdes(logic);
|
|
|
|
const int key = _cursor->key();
|
|
const KeyDes& kd = rd.Ky[key-1];
|
|
|
|
for (int i = 0; i < kd.NkFields; i++)
|
|
{
|
|
const int n = kd.FieldSeq[i] % MaxFields;
|
|
if (strcmp(rd.Fd[n].Name, fr.name()) == 0)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
TCursor_sheet::TCursor_sheet(TCursor* cursor, const char* fields,
|
|
const char* title, const char* head,
|
|
byte buttons, short sht_y, WINDOW parent)
|
|
: TSheet(sht_y ? 2 : 0, sht_y ? 2 : 0, sht_y ? -2 : 0, sht_y ? -2 : 0,
|
|
title, head, buttons, sht_y, parent), _cursor(cursor)
|
|
{
|
|
TToken_string fldlst(fields);
|
|
int campo = 0;
|
|
for (const char* t = fldlst.get(0); t; t = fldlst.get(), campo++)
|
|
{
|
|
if (*t > ' ' && *t != '"')
|
|
{
|
|
const TFieldref fr(t, 0);
|
|
TRecfield* rf = new TRecfield(_cursor->curr(fr.file()),
|
|
fr.name(), fr.from(), fr.to() - 1);
|
|
_fields.add(rf, campo);
|
|
|
|
const TFieldtypes tipo = rf->type();
|
|
if (tipo == _intfld || tipo == _longfld || tipo == _realfld)
|
|
{
|
|
byte c = sheet().column_type(campo);
|
|
if (c == ' ')
|
|
sheet().align_column(campo, TRUE);
|
|
}
|
|
|
|
_key_cols.set(campo, in_key(fr));
|
|
}
|
|
}
|
|
}
|
|
|
|
HIDDEN bool _can_post = FALSE;
|
|
|
|
KEY TCursor_sheet::run()
|
|
{
|
|
_cursor->freeze(TRUE);
|
|
|
|
select(_cursor->pos());
|
|
_can_post = TRUE;
|
|
|
|
const KEY k = TSheet::run();
|
|
_cursor->freeze(FALSE);
|
|
return k;
|
|
}
|
|
|
|
long TCursor_sheet::get_items() const
|
|
{ return _cursor ? _cursor->items() : 0; }
|
|
|
|
void TCursor_sheet::get_row(long row, TToken_string& l)
|
|
{
|
|
*_cursor = (TRecnotype)row;
|
|
l.cut(0);
|
|
const int last = _fields.last();
|
|
for (int i = 0; i <= last; i++)
|
|
{
|
|
const TRecfield* rf = (TRecfield*)_fields.objptr(i);
|
|
const char* s = rf ? (const char*)*rf : "";
|
|
l.add(s);
|
|
}
|
|
}
|
|
|
|
bool TCursor_sheet::get_cell_colors(int row, int col, COLOR& fore, COLOR& back) const
|
|
{
|
|
if (_key_cols[col])
|
|
{
|
|
fore = 0;
|
|
back = REQUIRED_BACK_COLOR; // Evidenzia i campi chiave
|
|
return true;
|
|
}
|
|
return TSheet::get_cell_colors(row, col, fore, back);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TBrowse_sheet
|
|
///////////////////////////////////////////////////////////
|
|
|
|
HIDDEN TBrowse_sheet* _cur_browse = NULL;
|
|
|
|
void TBrowse_sheet::add_custom_filter(const char* regexp)
|
|
{
|
|
TString filter = _original_filter; // Costruisco il nuovo filtro per estensione del vecchio
|
|
if (regexp && *regexp)
|
|
{
|
|
if (_original_filter.not_empty())
|
|
{
|
|
filter.insert("(");
|
|
filter << ")&&(";
|
|
}
|
|
filter << regexp;
|
|
if (_original_filter.not_empty())
|
|
filter << ')';
|
|
}
|
|
|
|
TCursor& c = *cursor();
|
|
if (filter != c.filter()) // Cambio il filtro se necessario :-)
|
|
{
|
|
c.freeze(false);
|
|
c.setfilter(filter, true);
|
|
c.items(); // Forzo la ricostruzione del cursore
|
|
c.freeze(true);
|
|
|
|
// Forzo un aggiornamento a basso livello
|
|
TQuery_field& qf = (TQuery_field&)TMask::field(DLG_QUERY);
|
|
XI_OBJ* obj = qf.sheet()->xi_object();
|
|
xi_scroll_percent(obj, 100);
|
|
xi_scroll_percent(obj, 0);
|
|
|
|
_sel = 0;
|
|
}
|
|
}
|
|
|
|
bool TBrowse_sheet::browse_field_handler(TMask_field& f, KEY k)
|
|
{
|
|
long rec = -1;
|
|
|
|
if (k == K_F2)
|
|
{
|
|
f.reset();
|
|
k = K_SPACE;
|
|
}
|
|
|
|
if (k == K_SPACE)
|
|
{
|
|
TEdit_field& e = _cur_browse->field(); // Campo padre dello sheet
|
|
TMask& m = e.mask(); // Maschera che contiene lo sheet
|
|
TMask_field& c = m.field(f.dlg()); // Campo corrispondente sulla maschera
|
|
|
|
// Ricopia su campo maschera
|
|
if (f.is_edit())
|
|
{
|
|
TEdit_field& ef = (TEdit_field&)f;
|
|
const TString& wd = ef.get_window_data();
|
|
c.set(wd);
|
|
}
|
|
else
|
|
c.set(f.get());
|
|
|
|
TBrowse* b = e.browse();
|
|
if (b != NULL)
|
|
{
|
|
b->do_input(FALSE);
|
|
rec = b->cursor()->read(_isgteq);
|
|
}
|
|
}
|
|
|
|
if (rec >= 0 && rec != _cur_browse->selected())
|
|
{
|
|
_cur_browse->select(rec); // Non mettere post_select
|
|
_can_post = TRUE;
|
|
|
|
RCT r; f.get_rect(r);
|
|
xvt_dwin_invalidate_rect(f.parent(), &r); // Non ricordo a cosa serva aggiornare il campo di testo
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
bool TBrowse_sheet::last_browse_field_handler(TMask_field& f, KEY k)
|
|
{
|
|
const bool ok = browse_field_handler(f, k);
|
|
if (ok)
|
|
{
|
|
if (k == K_TAB && _can_post)
|
|
{
|
|
_cur_browse->post_select(_cur_browse->selected());
|
|
_can_post = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (k == K_CTRL+K_TAB)
|
|
{
|
|
RCT r; f.get_rect(r);
|
|
xvt_dwin_invalidate_rect(f.parent(), &r);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ok;
|
|
}
|
|
|
|
bool TBrowse_sheet::filter_handler(TMask_field& f, KEY k)
|
|
{
|
|
if (k == K_SPACE)
|
|
{
|
|
TString expr; // Espressione di filtro complessiva
|
|
if (!f.get().empty()) // Filtro attivato!
|
|
{
|
|
const short id = f.dlg()-500;
|
|
TString e = f.mask().get(id); // Espressione regolare
|
|
e.strip("\"'"); // Tolgo caratteri che potrebbero dare problemi
|
|
if (!e.blank())
|
|
{
|
|
const TBrowse& b = *_cur_browse->field().browse();
|
|
TToken_string ids = b.get_input_fields();
|
|
const int pos = ids.get_pos(id);
|
|
if (pos >= 0)
|
|
{
|
|
TToken_string fns = b.get_input_field_names();
|
|
expr << fns.get(pos) << "?=\"" << e << '"';
|
|
}
|
|
}
|
|
if (expr.empty())
|
|
f.reset();
|
|
}
|
|
_cur_browse->add_custom_filter(expr);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// @doc EXTERNAL
|
|
|
|
// @mfunc Gestisce l'handler della finestra
|
|
void TBrowse_sheet::handler(
|
|
WINDOW win, // @parm Finestra da gestire
|
|
EVENT* ep) // @parm Evento da gestire nella finestra
|
|
{
|
|
switch (ep->type)
|
|
{
|
|
case E_MOUSE_DOWN:
|
|
switch (ep->v.mouse.button )
|
|
{
|
|
case 1:
|
|
{
|
|
MENU_ITEM* menu = xvt_res_get_menu(BROWSE_BAR);
|
|
if (menu)
|
|
{
|
|
dictionary_translate_menu(menu);
|
|
const PNT& p = ep->v.mouse.where;
|
|
RCT cr; xvt_vobj_get_client_rect(win, &cr);
|
|
XVT_POPUP_ALIGNMENT pa = XVT_POPUP_CENTER;
|
|
if (p.h < cr.right / 3)
|
|
pa = XVT_POPUP_LEFT_ALIGN;
|
|
else
|
|
if (p.h > 2 * cr.right / 3)
|
|
pa = XVT_POPUP_RIGHT_ALIGN;
|
|
|
|
xvt_menu_popup(menu->child, win, p, pa, NULL);
|
|
xvt_res_free_menu_tree(menu);
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
RCT r; sheet().get_rect(r);
|
|
if (xvt_rect_has_point(&r, ep->v.mouse.where) && _rec_to_select >= 0)
|
|
{
|
|
post_select(_rec_to_select);
|
|
_rec_to_select = -1;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case E_COMMAND:
|
|
switch (ep->v.cmd.tag)
|
|
{
|
|
case BROWSE_BAR + 1:
|
|
save_columns_order(field());
|
|
return;
|
|
case BROWSE_BAR + 2:
|
|
set_columns_order(NULL);
|
|
return;
|
|
case BROWSE_BAR + 3:
|
|
fld(0).on_key(K_F11);
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case E_CONTROL:
|
|
if (ep->v.ctl.ci.type == WC_NOTEBK)
|
|
{
|
|
const int new_search = ep->v.ctl.ci.v.notebk.tab_no;
|
|
on_key(K_CTRL+K_F1+new_search);
|
|
return;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
TCursor_sheet::handler(win, ep);
|
|
}
|
|
|
|
#ifndef OLD_FASHIONED_BROWSE
|
|
bool lst_handler(TMask_field& lst, KEY k)
|
|
{
|
|
if (k == K_SPACE)
|
|
{
|
|
TMask& m = lst.mask();
|
|
if (m.is_running())
|
|
{
|
|
const int sel = atoi(lst.get());
|
|
m.on_key(K_CTRL + K_F1 + sel);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
void TBrowse_sheet::create_key_selector(TToken_string& ca)
|
|
{
|
|
#ifdef OLD_FASHIONED_BROWSE
|
|
set_tab_buttons(ca); // Non funziona piu' bene: cambiamo strada
|
|
#else
|
|
const int items = ca.items();
|
|
if (items > 1)
|
|
{
|
|
TToken_string co;
|
|
for (int i = 0; i < items; i++)
|
|
co.add(i);
|
|
|
|
TList_field& lst = add_list(69, 0, PR("Ordinamento per "), 1, 0, 16, "", co, ca);
|
|
lst.set_handler(lst_handler);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void TBrowse_sheet::update_key_selector(int sel)
|
|
{
|
|
#ifdef OLD_FASHIONED_BROWSE
|
|
show_page(sel);
|
|
#else
|
|
if (id2pos(69) >= 0) // Has been created?
|
|
set(69, sel, 0); // Don't fire any events!
|
|
#endif
|
|
}
|
|
|
|
TBrowse_sheet::TBrowse_sheet(TCursor* cursor, const char* fields,
|
|
const char* title, const char* head, byte buttons,
|
|
TEdit_field& f, TToken_string& sibling)
|
|
: TCursor_sheet(cursor, fields, title, head, buttons,
|
|
f.browse() ? f.browse()->input_fields()+1 : 1),
|
|
_field(f), _sel(0), _original_filter(cursor->filter())
|
|
{
|
|
const bool normal = f.browse() != NULL && sibling.full();
|
|
|
|
TToken_string ca; // Tag buttons
|
|
if (normal) // normal mask query
|
|
{
|
|
int n = 0;
|
|
for (const char* s = sibling.get(0); s && *s; s = sibling.get(), n++)
|
|
{
|
|
const short id = f.atodlg(s);
|
|
const char* pr = sibling.get();
|
|
if (id == f.dlg())
|
|
_sel = n;
|
|
ca.add(pr);
|
|
}
|
|
}
|
|
else // ABnormal application query: F9 or F8 handler!
|
|
{
|
|
ca = f.prompt();
|
|
if (ca.blank())
|
|
ca = TR("Codice");
|
|
}
|
|
create_key_selector(ca);
|
|
|
|
TToken_string tids = head;
|
|
TToken_string tfns = fields;
|
|
TToken_string ids, fns;
|
|
if (f.browse() != NULL)
|
|
{
|
|
ids = f.browse()->get_input_fields();
|
|
fns = f.browse()->get_input_field_names();
|
|
}
|
|
|
|
TEditable_field* e = NULL;
|
|
#ifdef OLD_FASHIONED_BROWSE
|
|
int y = 0;
|
|
#else
|
|
int y = 1;
|
|
#endif
|
|
|
|
bool first = true;
|
|
|
|
for (const char* i = ids.get(0); i; i = ids.get())
|
|
{
|
|
if (*i != '\0' && *i != '"' && strchr(i, '@') == NULL)
|
|
{
|
|
const short id = f.atodlg(i);
|
|
const TMask_field& c = f.mask().field(id);
|
|
if (c.is_editable() && c.active())
|
|
{
|
|
int pos = ids.get_pos(id);
|
|
CHECK(pos >= 0, "Invalid input field");
|
|
TString80 p = fns.get(pos);
|
|
pos = tfns.get_pos(p);
|
|
if (pos >= 0)
|
|
{
|
|
p = tids.get(pos);
|
|
pos = p.find('@');
|
|
if (pos >= 0)
|
|
p.cut(pos);
|
|
}
|
|
else
|
|
p.cut(0);
|
|
|
|
if (p.empty())
|
|
{
|
|
p = c.prompt();
|
|
int a;
|
|
// Toglie spazi e simboli iniziali dal prompt
|
|
for (a = 0; p[a] && !isalnum(p[a]); a++);
|
|
p.ltrim(a);
|
|
}
|
|
p.left_just(16);
|
|
|
|
TString8 flags;
|
|
|
|
if (c.roman()) flags << 'M';
|
|
if (c.right_justified()) flags << 'R';
|
|
if (c.uppercase()) flags << 'U';
|
|
if (c.zerofilled()) flags << 'Z';
|
|
if (!normal) flags << 'D'; // Disable ABnormal fields
|
|
|
|
const int csize = c.size();
|
|
|
|
switch (c.class_id())
|
|
{
|
|
case CLASS_EDIT_FIELD:
|
|
{
|
|
const int sz = csize > 50 ? 50 : csize; // Dimensione del campo di ricerca
|
|
e = &add_string(c.dlg(), 0, p, 1, y++, csize, flags, sz);
|
|
// Aggiunge campo con le icone di filtraggio
|
|
add_checkbutton(c.dlg()+500, 0, "", sz+strlen(p)+ 2, y-1, 2, 1, "", 10112, 10113).set_handler(filter_handler);
|
|
}
|
|
break;
|
|
case CLASS_ZOOM_FIELD:
|
|
{
|
|
e = &add_string(c.dlg(), 0, p, 1, y++, 32000, flags, 50);
|
|
// Aggiunge campo con le icone di filtraggio
|
|
add_checkbutton(c.dlg()+500, 0, "", 52 + strlen(p), y-1, 2, 1, "", 10112, 10113).set_handler(filter_handler);
|
|
}
|
|
break;
|
|
case CLASS_REAL_FIELD:
|
|
e = &add_number(c.dlg(), 0, p, 1, y++, csize, flags);
|
|
break;
|
|
case CLASS_DATE_FIELD:
|
|
e = &add_date(c.dlg(), 0, p, 1, y++, flags);
|
|
break;
|
|
default:
|
|
e = NULL;
|
|
break;
|
|
}
|
|
if (e != NULL && normal)
|
|
{
|
|
e->set_handler(browse_field_handler);
|
|
e->set(c.get());
|
|
if (e->dlg() == f.dlg() || first)
|
|
{
|
|
first_focus(e->dlg());
|
|
first = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (e != NULL && normal)
|
|
e->set_handler(last_browse_field_handler);
|
|
|
|
// carica ordine colonne anche per ricerche costruite run-time
|
|
load_columns_order(f);
|
|
}
|
|
|
|
bool TBrowse_sheet::on_key(KEY k)
|
|
{
|
|
if (k >= K_CTRL+K_F1 && k < K_CTRL+K_F10)
|
|
{
|
|
const int what = k - K_CTRL - K_F1;
|
|
if (what >= 0 && what != _sel)
|
|
TWindow::stop_run(k);
|
|
return true;
|
|
}
|
|
return TSheet::on_key(k);
|
|
}
|
|
|
|
KEY TBrowse_sheet::run()
|
|
{
|
|
_cur_browse = this;
|
|
update_key_selector(_sel);
|
|
const KEY key = TCursor_sheet::run();
|
|
_cur_browse = NULL;
|
|
return key;
|
|
}
|