421 lines
11 KiB
C++
421 lines
11 KiB
C++
#pragma once
|
|
/************************************************************************
|
|
MeOS - Orienteering Software
|
|
Copyright (C) 2009-2022 Melin Software HB
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
Melin Software HB - software@melin.nu - www.melin.nu
|
|
Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
|
|
|
|
************************************************************************/
|
|
|
|
#include <vector>
|
|
#include <map>
|
|
#include <set>
|
|
#include "oBase.h"
|
|
#include "inthashmap.h"
|
|
|
|
#define TableXMargin 40
|
|
#define TableYMargin 30
|
|
|
|
enum CellType {cellEdit, cellSelection, cellAction, cellCombo};
|
|
enum KeyCommandCode;
|
|
|
|
class Table;
|
|
typedef void (*GENERATETABLEDATA)(Table &table, void *ptr);
|
|
|
|
|
|
struct TableUpdateInfo {
|
|
bool doAdd;
|
|
bool doRefresh;
|
|
oBase *object;
|
|
int id;
|
|
TableUpdateInfo() : doAdd(false), object(0), id(0), doRefresh(false) {}
|
|
};
|
|
|
|
|
|
class TableCell
|
|
{
|
|
wstring contents;
|
|
RECT absPos;
|
|
|
|
DWORD id;
|
|
|
|
bool hasOwner() const { return ownerRef && ownerRef->get() != nullptr; };
|
|
oBase *getOwner() const { return ownerRef ? ownerRef->get() : nullptr; }
|
|
shared_ptr<oBase::oBaseReference> ownerRef;
|
|
bool canEdit;
|
|
CellType type;
|
|
|
|
|
|
friend class TableRow;
|
|
friend class Table;
|
|
friend int tblSelectionCB(gdioutput *gdi, int type, void *data);
|
|
|
|
public:
|
|
void update(CellType t, const wstring &str) {
|
|
contents = str;
|
|
type = t;
|
|
}
|
|
};
|
|
|
|
class TableRow
|
|
{
|
|
protected:
|
|
wstring key;
|
|
int intKey;
|
|
|
|
vector<TableCell> cells;
|
|
int id;
|
|
|
|
wstring *SortString;
|
|
int sInt;
|
|
|
|
int ypos;
|
|
int height;
|
|
oBase *ob;
|
|
|
|
public:
|
|
oBase *getObject() const {return ob;}
|
|
void setObject(oBase &obj);
|
|
bool operator<(const TableRow &r){return *SortString<*r.SortString;}
|
|
static bool cmpint(const TableRow &r1, const TableRow &r2) {return r1.sInt<r2.sInt;}
|
|
|
|
CellType getCellType(int index) const { return cells[index].type; }
|
|
void updateCell(int index, CellType type, const wstring &str) { return cells[index].update(type, str); }
|
|
|
|
TableRow(int elem, oBase *object): sInt(0)
|
|
{
|
|
cells.resize(elem);
|
|
SortString=&cells[0].contents;
|
|
ob = object;
|
|
id = -1;
|
|
}
|
|
|
|
TableRow(const TableRow &t)
|
|
{
|
|
cells=t.cells;
|
|
SortString=&cells[0].contents;
|
|
ob = t.ob;
|
|
id = t.id;
|
|
}
|
|
friend class Table;
|
|
friend struct TableSortIndex;
|
|
|
|
};
|
|
|
|
class gdioutput;
|
|
class oDataDefiner;
|
|
|
|
struct ColInfo
|
|
{
|
|
wchar_t name[64];
|
|
mutable int width;
|
|
int baseWidth;
|
|
bool isnumeric;
|
|
int padWidthZeroSort;
|
|
bool formatRight;
|
|
RECT title;
|
|
RECT condition;
|
|
wstring filter;
|
|
};
|
|
|
|
struct TableSortIndex;
|
|
|
|
class Table
|
|
{
|
|
protected:
|
|
GENERATETABLEDATA generator;
|
|
void *generatorPtr;
|
|
|
|
bool doAutoSelectColumns;
|
|
|
|
int t_xpos;
|
|
int t_ypos;
|
|
int t_maxX;
|
|
int t_maxY;
|
|
|
|
static int uniqueId;
|
|
int id;
|
|
bool clearOnHide;
|
|
bool commandLock;
|
|
wstring tableName;
|
|
string internalName;
|
|
vector<ColInfo> Titles;
|
|
vector<int> xpos;
|
|
unsigned nTitles;
|
|
int PrevSort;
|
|
mutable int rowHeight;
|
|
int baseRowHeight;
|
|
vector<TableRow> Data;
|
|
size_t dataPointer; // Insertation pointer
|
|
vector<TableSortIndex> sortIndex;
|
|
vector<int> columns;
|
|
mutable vector<int> dataRowToIndex;
|
|
inthashmap idToRow;
|
|
int highRow;
|
|
int highCol;
|
|
|
|
bool isFullColumnSelected() const;
|
|
|
|
// Selected columns. For drag/drop and sort
|
|
int colSelected;
|
|
int startX;
|
|
int startY;
|
|
|
|
//Edit selection
|
|
int editRow;
|
|
int editCol;
|
|
|
|
// Selected rectangle
|
|
struct Range {
|
|
int upperRow;
|
|
int lowerRow;
|
|
int upperCol;
|
|
int lowerCol;
|
|
void reset() {
|
|
upperRow = -1;
|
|
lowerRow = -1;
|
|
upperCol = -1;
|
|
lowerCol = -1;
|
|
}
|
|
bool emptyRow() const { return upperRow < 0 || lowerRow < 0; }
|
|
bool emptyCol() const { return upperCol < 0 || lowerCol < 0; }
|
|
bool empty() const { return emptyRow() || emptyCol(); }
|
|
|
|
Range() { reset(); }
|
|
~Range() = default;
|
|
bool operator!=(const Range &other) const {
|
|
return upperRow != other.upperRow || lowerCol != other.lowerCol ||
|
|
lowerRow != other.lowerRow || upperCol != other.upperCol;
|
|
}
|
|
};
|
|
|
|
Range sel;
|
|
mutable Range selScreen;
|
|
Range oldSel;
|
|
/* int upperRowOld;
|
|
int lowerRowOld;
|
|
int upperColOld;
|
|
int lowerColOld;
|
|
*/
|
|
bool startSelect;
|
|
|
|
HWND hEdit;
|
|
|
|
//For moving objects
|
|
HDC hdcCompatible;
|
|
HBITMAP hbmStored;
|
|
int lastX;
|
|
int lastY;
|
|
|
|
// For cell seletion
|
|
HDC hdcCompatibleCell;
|
|
HBITMAP hbmStoredCell;
|
|
RECT lastCell;
|
|
bool partialCell;
|
|
|
|
//static bool filterMatchString(const string &c, const char *filt);
|
|
void highlightCell(HDC hDC, gdioutput &gdi, int col, const TableCell &cell, DWORD color, int dx, int dy);
|
|
|
|
void moveCell(HDC hDC, gdioutput &gdi, int col, const TableCell &cell, int dx, int dy);
|
|
void startMoveCell(HDC hDC, const TableCell &cell);
|
|
void stopMoveCell(HDC hDC, const TableCell &cell, int dx, int dy);
|
|
void restoreCell(HDC hDC, const TableCell &cell);
|
|
|
|
void moveColumn(int src, int target);
|
|
|
|
int tableWidth;
|
|
int tableHeight;
|
|
bool drawFilterLabel;
|
|
int currentSortColumn;
|
|
|
|
void initEmpty();
|
|
|
|
int getColumn(int x, bool limit = false) const;
|
|
int getRow(int y, bool limit = false) const;
|
|
|
|
void redrawCell(gdioutput &gdi, HDC hDC, int c, int r);
|
|
|
|
//Draw coordinates
|
|
int table_xp;
|
|
int table_yp;
|
|
|
|
oEvent *oe;
|
|
|
|
void clearSelectionBitmap(gdioutput *gdi, HDC hDC);
|
|
void restoreSelection(gdioutput &gdi, HDC hDC);
|
|
|
|
void drawSelection(gdioutput &gdi, HDC hDC, bool forceDraw);
|
|
TableCell &getCell(int row, int col) const; //Index as displayed
|
|
void scrollToCell(gdioutput &gdi, int row, int col);
|
|
|
|
bool destroyEditControl(gdioutput &gdi);
|
|
|
|
void getExportData(int col1, int col2, int row1, int row2,
|
|
wstring &html, wstring &txt) const;
|
|
|
|
// Delete rows in selected range. Return number of rows that could not be removed
|
|
int deleteRows(int row1, int row2);
|
|
|
|
void getRowRange(int &rowLo, int &rowHi) const;
|
|
void getColRange(int &colLo, int &colHi) const;
|
|
DWORD tableProp;
|
|
|
|
int selectionRow;
|
|
int selectionCol;
|
|
|
|
void getRowRect(int row, RECT &rc) const;
|
|
|
|
bool compareRow(int indexA, int indexB) const;
|
|
|
|
map<string, const oDataDefiner *> dataDefiners;
|
|
public:
|
|
void addDataDefiner(const string &key, const oDataDefiner *definer);
|
|
|
|
void setTableText(gdioutput &gdi, int editRow, int editCol, const wstring &bf);
|
|
const wstring &getTableText(gdioutput &gdi, int editRow, int editCol);
|
|
|
|
int getTableId() const {return id;}
|
|
static void resetTableIds() {uniqueId = 1;}
|
|
|
|
void setGenerator(GENERATETABLEDATA gen, void *genPtr) {
|
|
generatorPtr = genPtr;
|
|
generator = gen;
|
|
}
|
|
|
|
void clear();
|
|
void setClearOnHide(bool coh) {clearOnHide = coh;}
|
|
int getNumDataRows() const;
|
|
|
|
void clearCellSelection(gdioutput *gdi);
|
|
|
|
/// Return translated table name
|
|
const wstring& getTableName() const {return tableName;}
|
|
/// Get the internal identifier of the table
|
|
const string& getInternalName() const {return internalName;}
|
|
|
|
bool hasAutoSelect() const {return doAutoSelectColumns;}
|
|
|
|
void updateDimension(gdioutput &gdi);
|
|
void selection(gdioutput &gdi, const wstring &text, int data);
|
|
|
|
enum {
|
|
CAN_PASTE = 1,
|
|
CAN_INSERT = 2,
|
|
CAN_DELETE = 4,
|
|
};
|
|
|
|
bool canPaste() const {return (tableProp & CAN_PASTE) != 0;}
|
|
bool canInsert() const {return (tableProp & CAN_INSERT) != 0;}
|
|
bool canDelete() const {return (tableProp & CAN_DELETE) != 0;}
|
|
void setTableProp(DWORD w) {tableProp = w;}
|
|
|
|
void hide(gdioutput &gdi); //Ensure no edit contol is visible
|
|
|
|
void autoAdjust(gdioutput &gdi); // Adjust column widths
|
|
void autoSelectColumns();
|
|
|
|
void insertRow(gdioutput &gdi); // Insert a new row in the table
|
|
bool deleteSelection(gdioutput &gdi);
|
|
void setPosition(int x, int y, int maxX, int maxY) {t_xpos = x, t_ypos = y; t_maxX = maxX, t_maxY = maxY;}
|
|
void exportClipboard(gdioutput &gdi);
|
|
void importClipboard(gdioutput &gdi);
|
|
|
|
|
|
bool hasEditControl() {return hEdit!=0;}
|
|
|
|
struct ColSelection {
|
|
ColSelection() : selected(false), index(0) {}
|
|
wstring name;
|
|
bool selected;
|
|
int index;
|
|
};
|
|
|
|
vector< ColSelection > getColumns() const;
|
|
void selectColumns(const set<int> &sel);
|
|
|
|
oEvent *getEvent() const {return oe;}
|
|
void getDimension(gdioutput &gdi, int &dx, int &dy, bool filteredResult) const;
|
|
void draw(gdioutput &gdi, HDC hDC, int dx, int dy,
|
|
const RECT &screen);
|
|
|
|
void print(gdioutput &gdi, HDC hDC, int dx, int dy);
|
|
|
|
//Returns true if capture is taken
|
|
bool mouseMove(gdioutput &gdi, int x, int y);
|
|
bool mouseLeftDown(gdioutput &gdi, int x, int y);
|
|
bool mouseLeftUp(gdioutput &gdi, int x, int y);
|
|
bool mouseLeftDblClick(gdioutput &gdi, int x, int y);
|
|
|
|
bool mouseRightDown(gdioutput &gdi, int x, int y);
|
|
bool mouseRightUp(gdioutput &gdi, int x, int y);
|
|
bool mouseMidDown(gdioutput &gdi, int x, int y);
|
|
bool mouseMidUp(gdioutput &gdi, int x, int y);
|
|
|
|
|
|
bool editCell(gdioutput &gdi, int row, int col);
|
|
|
|
bool keyCommand(gdioutput &gdi, KeyCommandCode code);
|
|
void sort(int col, bool forceDirection);
|
|
void filter(int col, const wstring &filt, bool forceFilter=false);
|
|
|
|
void showFilter(gdioutput &gdi);
|
|
|
|
int addColumn(const string &Title, int width, bool isnum, bool formatRight = false);
|
|
int addColumn(const wstring &translatedTitle, int width, bool isnum, bool formatRight = false);
|
|
|
|
int addColumnPaddedSort(const string &title, int width, int padding, bool formatRight = false);
|
|
|
|
void reserve(size_t siz);
|
|
|
|
TableRow *getRowById(int rowId);
|
|
void addRow(int rowId, oBase *object);
|
|
void set(int column, oBase &owner, int id, const wstring &data,
|
|
bool canEdit=true, CellType type=cellEdit);
|
|
|
|
void markAll(bool doSelect);
|
|
|
|
//Reload a row from data
|
|
void reloadRow(int rowId);
|
|
|
|
bool upDown(gdioutput &gdi, int direction);
|
|
bool tabFocus(gdioutput &gdi, int direction);
|
|
bool enter(gdioutput &gdi);
|
|
void escape(gdioutput &gdi);
|
|
bool inputChange(gdioutput &gdi, HWND hEdit);
|
|
void resetColumns();
|
|
void update();
|
|
|
|
Table(oEvent *oe_, int rowHeight,
|
|
const wstring &name, const string &tname);
|
|
~Table(void);
|
|
|
|
friend struct TableSortIndex;
|
|
};
|
|
|
|
struct TableSortIndex {
|
|
const static Table *table;
|
|
int index;
|
|
bool operator<(const TableSortIndex &t) const {return table->compareRow(index,t.index);}
|
|
};
|
|
|
|
enum {TID_CLASSNAME, TID_COURSE, TID_NUM, TID_ID, TID_MODIFIED,
|
|
TID_RUNNER, TID_CLUB, TID_START, TID_TIME,
|
|
TID_FINISH, TID_STATUS, TID_RUNNINGTIME, TID_PLACE, TID_POINTS,
|
|
TID_CARD, TID_TEAM, TID_LEG, TID_CONTROL, TID_CODES, TID_FEE, TID_PAID,
|
|
TID_INPUTTIME, TID_INPUTSTATUS, TID_INPUTPOINTS, TID_INPUTPLACE,
|
|
TID_NAME, TID_NATIONAL, TID_SEX, TID_YEAR, TID_INDEX, TID_ENTER, TID_STARTNO, TID_VOLTAGE};
|