Transform to CMake project.
This commit is contained in:
881
LBoundGrid.cpp
Normal file
881
LBoundGrid.cpp
Normal file
@@ -0,0 +1,881 @@
|
||||
/*
|
||||
* File: LBoundGrid.cpp
|
||||
* Author: SET - nmset@yandex.com
|
||||
* License : LGPL version 2.1
|
||||
* Copyright SET, M. D. - © 2014
|
||||
*
|
||||
* Created on 9 juin 2014, 16:40
|
||||
*/
|
||||
|
||||
#include "LBoundGrid.h"
|
||||
#include "LGridCheckEditor.h"
|
||||
#include "LGridCheckRenderer.h"
|
||||
#include "LGridComboEditor.h"
|
||||
#include "LGridComboRenderer.h"
|
||||
#include "LGridDateEditor.h"
|
||||
#include "LGridDateRenderer.h"
|
||||
#include "LGridTextEditor.h"
|
||||
#include "LGridTextRenderer.h"
|
||||
#include "LGridSpinEditor.h"
|
||||
#include "LGridSpinRenderer.h"
|
||||
#include "special/LGridJsonCellRenderer.h"
|
||||
#include "special/LGridJsonCellEditor.h"
|
||||
#include "special/LGridXmlCellRenderer.h"
|
||||
#include "special/LGridXmlCellEditor.h"
|
||||
|
||||
LBoundGrid::LBoundGrid(wxWindow* parent, wxWindowID id)
|
||||
: wxGrid(parent, id, wxDefaultPosition, wxDefaultSize, wxHSCROLL | wxVSCROLL)
|
||||
{
|
||||
m_rs = NULL;
|
||||
m_formClientSizer = NULL;
|
||||
m_gridFormEVH = NULL;
|
||||
m_scaleFactor = (wxGetDisplayPPI().GetY() / 96.0);
|
||||
SetDefaultCellAlignment(wxALIGN_LEFT, wxALIGN_CENTRE);
|
||||
m_stringTable = new wxGridStringTable();
|
||||
m_stringTable->CanHaveAttributes();
|
||||
HideRowLabels();
|
||||
SetUseNativeColLabels();
|
||||
SetTable(m_stringTable);
|
||||
SetSelectionMode(wxGridSelectRows);
|
||||
CreateMenu();
|
||||
// These bindings must not propagate to the grid of BaseGridPicker !!!
|
||||
Bind(wxEVT_GRID_RANGE_SELECT, &LBoundGrid::ForceSingleLineRange, this, GetId(), GetId());
|
||||
Bind(wxEVT_GRID_SELECT_CELL, &LBoundGrid::CellSelected, this, GetId(), GetId());
|
||||
Bind(wxEVT_GRID_CELL_RIGHT_CLICK, &LBoundGrid::ShowMenu, this, GetId(), GetId());
|
||||
}
|
||||
|
||||
LBoundGrid::~LBoundGrid()
|
||||
{
|
||||
delete m_menu;
|
||||
delete m_formClientSizer;
|
||||
ClearGrid();
|
||||
}
|
||||
|
||||
void LBoundGrid::SetResultSet(LResultSet* newResultSet)
|
||||
{
|
||||
m_rs = newResultSet;
|
||||
if (m_rs == NULL) return;
|
||||
wxASSERT_MSG(m_rs->GetConnection() != NULL, _T("GetConnection() = NULL."));
|
||||
if (!m_menu) return;
|
||||
if (m_rs->GetConnection()->IsReadOnly() || m_rs->IsReadOnly())
|
||||
{
|
||||
m_menu->FindItemByPosition(0)->Enable(false);
|
||||
m_menu->FindItemByPosition(2)->Enable(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_menu->FindItemByPosition(0)->Enable(true);
|
||||
m_menu->FindItemByPosition(2)->Enable(true);
|
||||
}
|
||||
}
|
||||
|
||||
void LBoundGrid::ClearGrid()
|
||||
{
|
||||
Unbind(wxEVT_GRID_RANGE_SELECT, &LBoundGrid::ForceSingleLineRange, this, GetId(), GetId());
|
||||
Unbind(wxEVT_GRID_SELECT_CELL, &LBoundGrid::CellSelected, this, GetId(), GetId());
|
||||
if (GetNumberRows()) DeleteRows(0, GetNumberRows());
|
||||
if (GetNumberCols()) DeleteCols(0, GetNumberCols());
|
||||
}
|
||||
|
||||
void LBoundGrid::FillGrid()
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
wxASSERT_MSG(m_rs->GetConnection() != NULL, _T("GetConnection() = NULL."));
|
||||
wxGridUpdateLocker locker(this);
|
||||
// Starting again, the grid's resultset must free itself from any registered controls.
|
||||
RestoreEditorControls();
|
||||
Unbind(wxEVT_GRID_RANGE_SELECT, &LBoundGrid::ForceSingleLineRange, this, GetId(), GetId());
|
||||
Unbind(wxEVT_GRID_SELECT_CELL, &LBoundGrid::CellSelected, this, GetId(), GetId());
|
||||
// Remember some states
|
||||
const wxGridSizesInfo colSizes = GetColSizes();
|
||||
const int col = GetGridCursorCol() > -1 ? GetGridCursorCol() : 0;
|
||||
// Create enough cells
|
||||
if (GetNumberRows()) DeleteRows(0, GetNumberRows());
|
||||
const bool firstTime = (m_stringTable->GetNumberCols() == 0);
|
||||
const int nbCols = m_rs->GetColumnCount();
|
||||
if (firstTime) m_stringTable->AppendCols(nbCols);
|
||||
const int nbRows = m_rs->GetRowCount();
|
||||
m_stringTable->AppendRows(nbRows);
|
||||
// Add an insert row
|
||||
if (!m_rs->GetConnection()->IsReadOnly() && !m_rs->IsReadOnly())
|
||||
{
|
||||
m_stringTable->AppendRows(1);
|
||||
}
|
||||
// Grid header labels default to database table column names.
|
||||
if (firstTime)
|
||||
{
|
||||
for (unsigned int c = 0; c < nbCols; c++)
|
||||
{
|
||||
m_stringTable->SetColLabelValue(c, m_rs->GetColumnName(c));
|
||||
}
|
||||
}
|
||||
// Set each cell's value.
|
||||
for (unsigned int r = 0; r < nbRows; r++)
|
||||
{
|
||||
for (unsigned int c = 0; c < nbCols; c++)
|
||||
{
|
||||
m_stringTable->SetValue(r, c, (m_rs->GetData(r, c)).As<wxString>());
|
||||
}
|
||||
}
|
||||
Bind(wxEVT_GRID_SELECT_CELL, &LBoundGrid::CellSelected, this, GetId(), GetId());
|
||||
Bind(wxEVT_GRID_RANGE_SELECT, &LBoundGrid::ForceSingleLineRange, this, GetId(), GetId());
|
||||
// Restore
|
||||
SetColSizes(colSizes);
|
||||
// synchronize with the resultset
|
||||
const int targetRow = m_rs->GetRow() > -1 ? m_rs->GetRow() : 0;
|
||||
if (GetNumberRows())
|
||||
{
|
||||
// Triggers CellSelected event. If no data, we are on insert row, we must call LResultSet::AddNew()
|
||||
GoToCell(targetRow, col);
|
||||
SelectRow(targetRow);
|
||||
}
|
||||
}
|
||||
|
||||
void LBoundGrid::CreateCheckBoxColumn(const wxString& newColName,
|
||||
const wxString& newLabel,
|
||||
unsigned int width,
|
||||
bool readOnly,
|
||||
bool isDualstate,
|
||||
wxString newNullLabel)
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
const int col = m_rs->GetColumnIndex(newColName);
|
||||
wxASSERT_MSG(col > -1, _("Invalid column name : ") + newColName);
|
||||
wxGridCellAttr * colAtt = m_stringTable->GetAttr(GetGridCursorRow(), col, wxGridCellAttr::Col);
|
||||
if (colAtt == NULL) colAtt = new wxGridCellAttr();
|
||||
LGridCheckEditor * ed = new LGridCheckEditor(newColName, isDualstate, newNullLabel);
|
||||
colAtt->SetEditor(ed);
|
||||
LGridCheckRenderer * rn = new LGridCheckRenderer(isDualstate, newNullLabel);
|
||||
colAtt->SetRenderer(rn);
|
||||
colAtt->SetReadOnly(readOnly);
|
||||
m_stringTable->SetColAttr(colAtt, col);
|
||||
m_stringTable->SetColLabelValue(col, newLabel);
|
||||
SetColSize(col, width);
|
||||
}
|
||||
|
||||
void LBoundGrid::CreateComboBoxColumn(const wxString& newColName,
|
||||
const wxString& newLabel,
|
||||
unsigned int width,
|
||||
bool readOnly)
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
const int col = m_rs->GetColumnIndex(newColName);
|
||||
wxASSERT_MSG(col > -1, _("Invalid column name : ") + newColName);
|
||||
wxGridCellAttr * colAtt = m_stringTable->GetAttr(GetGridCursorRow(), col, wxGridCellAttr::Col);
|
||||
if (colAtt == NULL) colAtt = new wxGridCellAttr();
|
||||
LGridComboEditor * ed = new LGridComboEditor(newColName);
|
||||
colAtt->SetEditor(ed);
|
||||
LGridComboRenderer * rn = new LGridComboRenderer;
|
||||
colAtt->SetRenderer(rn);
|
||||
colAtt->SetReadOnly(readOnly);
|
||||
m_stringTable->SetColAttr(colAtt, col);
|
||||
m_stringTable->SetColLabelValue(col, newLabel);
|
||||
SetColSize(col, width);
|
||||
}
|
||||
|
||||
void LBoundGrid::CreateDateColumn(const wxString& newColName,
|
||||
const wxString& newLabel,
|
||||
unsigned int width,
|
||||
bool readOnly)
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
const int col = m_rs->GetColumnIndex(newColName);
|
||||
wxASSERT_MSG(col > -1, _("Invalid column name : ") + newColName);
|
||||
wxGridCellAttr * colAtt = m_stringTable->GetAttr(GetGridCursorRow(), col, wxGridCellAttr::Col);
|
||||
if (colAtt == NULL) colAtt = new wxGridCellAttr();
|
||||
LGridDateEditor * ed = new LGridDateEditor(newColName);
|
||||
colAtt->SetEditor(ed);
|
||||
LGridDateRenderer * rn = new LGridDateRenderer();
|
||||
colAtt->SetRenderer(rn);
|
||||
colAtt->SetReadOnly(readOnly);
|
||||
colAtt->SetAlignment(wxALIGN_RIGHT, wxALIGN_CENTRE);
|
||||
m_stringTable->SetColAttr(colAtt, col);
|
||||
m_stringTable->SetColLabelValue(col, newLabel);
|
||||
SetColSize(col, width);
|
||||
}
|
||||
|
||||
void LBoundGrid::CreateTextColumn(const wxString& newColName,
|
||||
const wxString& newLabel,
|
||||
unsigned int width,
|
||||
bool newMultiline,
|
||||
bool readOnly)
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
const int col = m_rs->GetColumnIndex(newColName);
|
||||
wxASSERT_MSG(col > -1, _("Invalid column name : ") + newColName);
|
||||
wxGridCellAttr * colAtt = m_stringTable->GetAttr(GetGridCursorRow(), col, wxGridCellAttr::Col);
|
||||
if (colAtt == NULL) colAtt = new wxGridCellAttr();
|
||||
LGridTextEditor * ed = new LGridTextEditor(newColName, newMultiline);
|
||||
colAtt->SetEditor(ed);
|
||||
LGridTextRenderer * rn = new LGridTextRenderer();
|
||||
colAtt->SetRenderer(rn);
|
||||
colAtt->SetReadOnly(readOnly);
|
||||
m_stringTable->SetColAttr(colAtt, col);
|
||||
m_stringTable->SetColLabelValue(col, newLabel);
|
||||
SetColSize(col, width);
|
||||
}
|
||||
|
||||
void LBoundGrid::CreateSpinColumn(const wxString& newColName,
|
||||
const wxString& newLabel,
|
||||
unsigned int width,
|
||||
int newMin,
|
||||
int newMax,
|
||||
int newInitial,
|
||||
bool readOnly)
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
const int col = m_rs->GetColumnIndex(newColName);
|
||||
wxASSERT_MSG(col > -1, _("Invalid column name : ") + newColName);
|
||||
wxGridCellAttr * colAtt = m_stringTable->GetAttr(GetGridCursorRow(), col, wxGridCellAttr::Col);
|
||||
if (colAtt == NULL) colAtt = new wxGridCellAttr();
|
||||
LGridSpinEditor * ed = new LGridSpinEditor(newColName, newMin, newMax, newInitial);
|
||||
colAtt->SetEditor(ed);
|
||||
LGridSpinRenderer * rn = new LGridSpinRenderer();
|
||||
colAtt->SetRenderer(rn);
|
||||
colAtt->SetReadOnly(readOnly);
|
||||
colAtt->SetAlignment(wxALIGN_RIGHT, wxALIGN_CENTRE);
|
||||
m_stringTable->SetColAttr(colAtt, col);
|
||||
m_stringTable->SetColLabelValue(col, newLabel);
|
||||
SetColSize(col, width);
|
||||
}
|
||||
|
||||
void LBoundGrid::CreateJsonGridColumn(const wxString& newColName,
|
||||
const wxString& newLabel,
|
||||
unsigned int width,
|
||||
const wxString& intentLabel,
|
||||
const wxArrayString& types,
|
||||
wxSize popupSize,
|
||||
bool readOnly)
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
const int col = m_rs->GetColumnIndex(newColName);
|
||||
wxASSERT_MSG(col > -1, _("Invalid column name : ") + newColName);
|
||||
wxGridCellAttr * colAtt = m_stringTable->GetAttr(GetGridCursorRow(), col, wxGridCellAttr::Col);
|
||||
if (colAtt == NULL) colAtt = new wxGridCellAttr();
|
||||
LGridJsonCellEditor * ed = new LGridJsonCellEditor(newColName, intentLabel, types, popupSize);
|
||||
colAtt->SetEditor(ed);
|
||||
LGridJsonCellRenderer * rn = new LGridJsonCellRenderer();
|
||||
colAtt->SetRenderer(rn);
|
||||
colAtt->SetReadOnly(readOnly);
|
||||
colAtt->SetAlignment(wxALIGN_RIGHT, wxALIGN_CENTRE);
|
||||
m_stringTable->SetColAttr(colAtt, col);
|
||||
m_stringTable->SetColLabelValue(col, newLabel);
|
||||
SetColSize(col, width);
|
||||
}
|
||||
|
||||
void LBoundGrid::CreateXmlGridColumn(const wxString& newColName,
|
||||
const wxString& newLabel,
|
||||
unsigned int width,
|
||||
const wxString& intentLabel,
|
||||
const wxArrayString& types,
|
||||
wxSize popupSize,
|
||||
bool readOnly)
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
const int col = m_rs->GetColumnIndex(newColName);
|
||||
wxASSERT_MSG(col > -1, _("Invalid column name : ") + newColName);
|
||||
wxGridCellAttr * colAtt = m_stringTable->GetAttr(GetGridCursorRow(), col, wxGridCellAttr::Col);
|
||||
if (colAtt == NULL) colAtt = new wxGridCellAttr();
|
||||
LGridXmlCellEditor * ed = new LGridXmlCellEditor(newColName, intentLabel, types, popupSize);
|
||||
colAtt->SetEditor(ed);
|
||||
LGridXmlCellRenderer * rn = new LGridXmlCellRenderer();
|
||||
colAtt->SetRenderer(rn);
|
||||
colAtt->SetReadOnly(readOnly);
|
||||
colAtt->SetAlignment(wxALIGN_RIGHT, wxALIGN_CENTRE);
|
||||
m_stringTable->SetColAttr(colAtt, col);
|
||||
m_stringTable->SetColLabelValue(col, newLabel);
|
||||
SetColSize(col, width);
|
||||
}
|
||||
|
||||
const wxString LBoundGrid::GetColName(const unsigned int col)
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
InitEditor(GetGridCursorRow(), col, false);
|
||||
LGridColEditor * gce = GetColEditor(GetGridCursorRow(), col);
|
||||
if (gce == NULL) return wxEmptyString;
|
||||
return gce->GetColumnName();
|
||||
}
|
||||
|
||||
int LBoundGrid::GetColIndex(const wxString& colName)
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
for (unsigned int col = 0; col < GetNumberCols(); col++)
|
||||
{
|
||||
LGridColEditor * gce = GetColEditor(GetGridCursorRow(), col);
|
||||
if (gce == NULL) continue;
|
||||
if (gce->GetColumnName().Lower() == colName.Lower()) return col;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
LBoundControl* LBoundGrid::GetBoundControl(const unsigned int row,
|
||||
const unsigned int col,
|
||||
bool keepRegistered)
|
||||
{
|
||||
wxASSERT_MSG(row >= 0 && row < GetNumberRows(), _("Invalid row parameter"));
|
||||
wxASSERT_MSG(col >= 0 && col < GetNumberCols(), _("Invalid col parameter"));
|
||||
wxObjectDataPtr<wxGridCellAttr> cellAttr;
|
||||
cellAttr = m_stringTable->GetAttr(row, col, wxGridCellAttr::Col);
|
||||
if (cellAttr.get() == NULL) return NULL;
|
||||
wxObjectDataPtr<wxGridCellEditor> ed;
|
||||
ed = cellAttr->GetEditor(this, row, col);
|
||||
if (ed.get() == NULL) return NULL;
|
||||
ed->BeginEdit(row, col, this);
|
||||
ed->Show(false);
|
||||
LGridColEditor* gce = dynamic_cast<LGridColEditor*> (ed.get()); // CROSS CASTING
|
||||
if (!gce) return NULL; // APP CAN ADD AN UNBOUND COLUMN
|
||||
if (!keepRegistered)
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
m_rs->UnRegisterControl(gce->GetBoundControl());
|
||||
}
|
||||
return gce->GetBoundControl();
|
||||
}
|
||||
|
||||
LBoundControl* LBoundGrid::GetBoundControl(const unsigned int row,
|
||||
const wxString& colName,
|
||||
bool keepRegistered)
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
wxASSERT_MSG(row >= 0 && row < GetNumberRows(), _("Invalid row parameter"));
|
||||
for (int col = 0; col < GetNumberCols(); col++)
|
||||
{
|
||||
LGridColEditor * gce = GetColEditor(row, col);
|
||||
if (gce == NULL) continue;
|
||||
if (gce->GetColumnName().Lower() == colName.Lower())
|
||||
{
|
||||
InitEditor(row, col, keepRegistered);
|
||||
return gce->GetBoundControl();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LGridColEditor* LBoundGrid::GetColEditor(const unsigned int row, const unsigned int col) const
|
||||
{
|
||||
wxASSERT_MSG(row >= 0 && row < GetNumberRows(), _("Invalid row parameter"));
|
||||
wxASSERT_MSG(col >= 0 && col < GetNumberCols(), _("Invalid col parameter"));
|
||||
wxObjectDataPtr<wxGridCellAttr> cellAttr;
|
||||
cellAttr = m_stringTable->GetAttr(row, col, wxGridCellAttr::Col);
|
||||
if (cellAttr.get() == NULL) return NULL;
|
||||
wxObjectDataPtr<wxGridCellEditor> ed;
|
||||
ed = cellAttr->GetEditor(this, row, col);
|
||||
if (ed.get() == NULL) return NULL;
|
||||
return dynamic_cast<LGridColEditor*> (ed.get());
|
||||
}
|
||||
|
||||
wxControl* LBoundGrid::GetFormEditor(const unsigned int col) const
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
wxASSERT_MSG(col >= 0 && col < GetNumberCols(), _("Invalid col parameter"));
|
||||
int row = m_rs->GetRow();
|
||||
if (m_rs->IsInserting()) row = m_rs->GetRowCount();
|
||||
LGridColEditor* gce = GetColEditor(row, col);
|
||||
if (!gce) return NULL;
|
||||
return gce->GetFormEditor();
|
||||
}
|
||||
|
||||
wxControl* LBoundGrid::GetFormEditor(const wxString& colName)
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
int row = m_rs->GetRow();
|
||||
if (m_rs->IsInserting()) row = m_rs->GetRowCount();
|
||||
for (int col = 0; col < GetNumberCols(); col++)
|
||||
{
|
||||
LGridColEditor * gce = GetColEditor(row, col);
|
||||
if (gce == NULL) continue;
|
||||
if (gce->GetColumnName().Lower() == colName.Lower())
|
||||
return gce->GetFormEditor();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool LBoundGrid::InitEditor(const unsigned int row,
|
||||
const unsigned int col,
|
||||
bool keepRegistered)
|
||||
{
|
||||
wxASSERT_MSG(row >= 0 && row < GetNumberRows(), _("Invalid row parameter"));
|
||||
wxASSERT_MSG(col >= 0 && col < GetNumberCols(), _("Invalid col parameter"));
|
||||
wxObjectDataPtr<wxGridCellAttr> cellAttr;
|
||||
cellAttr = m_stringTable->GetAttr(row, col, wxGridCellAttr::Col);
|
||||
if (cellAttr.get() == NULL) return false;
|
||||
wxObjectDataPtr<wxGridCellEditor> ed;
|
||||
ed = cellAttr->GetEditor(this, row, col);
|
||||
if (ed.get() == NULL) return false;
|
||||
// That's what we want to do.
|
||||
ed->BeginEdit(row, col, this);
|
||||
ed->Show(false);
|
||||
if (!keepRegistered)
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
LGridColEditor* gce = dynamic_cast<LGridColEditor*> (ed.get());
|
||||
if (!gce) return false;
|
||||
m_rs->UnRegisterControl(gce->GetBoundControl());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LBoundGrid::InitAllEditors(const unsigned int row, bool keepRegistered)
|
||||
{
|
||||
wxASSERT_MSG(row >= 0 && row < GetNumberRows(), _("Invalid row parameter"));
|
||||
if (m_stringTable == NULL) return;
|
||||
if (GetNumberCols() > 0)
|
||||
{
|
||||
for (int col = 0; col < GetNumberCols(); col++)
|
||||
{
|
||||
InitEditor(row, col, keepRegistered);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LBoundGrid::AddMenuSeparator()
|
||||
{
|
||||
m_menu->AppendSeparator();
|
||||
}
|
||||
|
||||
void LBoundGrid::AddMenuItem(wxMenuItem* newItem)
|
||||
{
|
||||
wxASSERT_MSG(newItem != NULL, _("Menu item is NULL"));
|
||||
if (m_menu->FindItem(newItem->GetItemLabelText()) != wxNOT_FOUND) return;
|
||||
m_menu->Append(newItem);
|
||||
}
|
||||
|
||||
void LBoundGrid::AddSubMenu(wxMenu* newSubMenu, const wxString& label)
|
||||
{
|
||||
wxASSERT_MSG(newSubMenu != NULL, _("Submenu is NULL"));
|
||||
if (m_menu->FindItem(newSubMenu->GetTitle()) != wxNOT_FOUND) return;
|
||||
m_menu->AppendSubMenu(newSubMenu, label);
|
||||
}
|
||||
|
||||
void LBoundGrid::RemoveMenuItem(const wxString& newItemLabelText)
|
||||
{
|
||||
if (m_menu->FindItem(newItemLabelText) == wxNOT_FOUND) return;
|
||||
m_menu->Remove(m_menu->FindChildItem(m_menu->FindItem(newItemLabelText)));
|
||||
}
|
||||
|
||||
void LBoundGrid::RemoveAllExternalMenuItems()
|
||||
{
|
||||
if (m_menu->GetMenuItemCount() < 8) return;
|
||||
do
|
||||
{
|
||||
m_menu->Remove(m_menu->GetMenuItems()[7]);
|
||||
}
|
||||
while (m_menu->GetMenuItemCount() > 7);
|
||||
}
|
||||
|
||||
void LBoundGrid::EnableMenuItem(int id, bool enable)
|
||||
{
|
||||
if (m_menu->FindChildItem(id)) m_menu->Enable(id, enable);
|
||||
}
|
||||
|
||||
/*
|
||||
* Only one single row must be selected at a time.
|
||||
* Even if multiple selections do not affect the grid row and col cursor values,
|
||||
* selecting only one row may avoid confusion.
|
||||
* And the library is not designed to account for edits on multiple rows.
|
||||
*/
|
||||
void LBoundGrid::ForceSingleLineRange(wxGridRangeSelectEvent& evt)
|
||||
{
|
||||
if ((evt.Selecting()))
|
||||
{
|
||||
wxASSERT_MSG(GetSelectionMode() == wxGridSelectRows, "Selection mode is not wxGridSelectRows.");
|
||||
if (evt.ControlDown() == true
|
||||
|| evt.GetTopRow() != evt.GetBottomRow())
|
||||
{
|
||||
SelectRow(GetGridCursorRow());
|
||||
evt.Veto();
|
||||
}
|
||||
}
|
||||
evt.Skip();
|
||||
}
|
||||
|
||||
void LBoundGrid::CellSelected(wxGridEvent& evt)
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
// The insert row is somehow un-natural, it exists in the grid but not in the resultset, we manage it separately.
|
||||
if (!m_rs->IsInserting())
|
||||
{
|
||||
// The user wants to change row.
|
||||
if ((evt.GetRow() != m_rs->GetRow()))
|
||||
{
|
||||
// If there have been no edits in therow we are leaving, we must unregister all controls in the resultset.
|
||||
if (!m_rs->IsDirty() && m_rs->HasData()) RestoreEditorControls();
|
||||
// The user doesn't want to go on insert row.
|
||||
if (evt.GetRow() < m_rs->GetRowCount())
|
||||
{
|
||||
// Absolute() will fail if there are edits
|
||||
if (!m_rs->Absolute(evt.GetRow()))
|
||||
{
|
||||
evt.Veto(); // Doesn't seem to do anything
|
||||
// Absolute() failed, get back to where we were.
|
||||
GoToCell(m_rs->GetRow(), GetGridCursorCol());
|
||||
SelectRow(m_rs->GetRow());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The user wants to go on insert row, call AddNe(). Will fail if there are edits.
|
||||
if (!m_rs->AddNew())
|
||||
{
|
||||
evt.Veto();
|
||||
// AddNew() failed, get back to where we were.
|
||||
GoToCell(m_rs->GetRow(), GetGridCursorCol());
|
||||
SelectRow(m_rs->GetRow());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
// We are inserting, on insert row.
|
||||
{
|
||||
// The user want to go above (if there is saved data).
|
||||
if (evt.GetRow() < m_rs->GetRowCount())
|
||||
{
|
||||
// There are no edits on the insert row.
|
||||
if (!m_rs->IsDirty())
|
||||
{
|
||||
RestoreEditorControls();
|
||||
m_rs->Cancel();
|
||||
// Synchronize the resultset with the grid.
|
||||
m_rs->Absolute(evt.GetRow());
|
||||
}
|
||||
else
|
||||
{
|
||||
// There are edits on the insert row.
|
||||
m_rs->InformInserting();
|
||||
evt.Veto();
|
||||
// Get back.
|
||||
GoToCell(m_rs->GetRowCount(), GetGridCursorCol());
|
||||
SelectRow(m_rs->GetRowCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
evt.Skip();
|
||||
}
|
||||
|
||||
void LBoundGrid::CreateMenu()
|
||||
{
|
||||
m_menu = new wxMenu(0);
|
||||
wxMenuItem * item = new wxMenuItem(m_menu, ID_MNU_SAVE, _("Save"));
|
||||
m_menu->Append(item);
|
||||
item = new wxMenuItem(m_menu, ID_MNU_CANCEL, _("Cancel"));
|
||||
m_menu->Append(item);
|
||||
item = new wxMenuItem(m_menu, ID_MNU_DELETE, _("Delete"));
|
||||
m_menu->Append(item);
|
||||
item = new wxMenuItem(m_menu);
|
||||
m_menu->Append(item);
|
||||
item = new wxMenuItem(m_menu, ID_MNU_REFRESH, _("Refresh"));
|
||||
m_menu->Append(item);
|
||||
item = new wxMenuItem(m_menu);
|
||||
m_menu->Append(item);
|
||||
item = new wxMenuItem(m_menu, ID_MNU_FORMVIEW, _("Form view"));
|
||||
m_menu->Append(item);
|
||||
m_menu->Bind(wxEVT_COMMAND_MENU_SELECTED, &LBoundGrid::MenuAction, this);
|
||||
}
|
||||
|
||||
void LBoundGrid::ShowMenu(wxGridEvent& evt)
|
||||
{
|
||||
GetGridWindow()->PopupMenu(m_menu);
|
||||
}
|
||||
|
||||
void LBoundGrid::MenuAction(wxCommandEvent& evt)
|
||||
{
|
||||
switch (evt.GetId())
|
||||
{
|
||||
case ID_MNU_SAVE:
|
||||
if (m_rs)
|
||||
{
|
||||
int row = m_rs->GetRow();
|
||||
if (m_rs->IsInserting()) row = m_rs->GetRowCount();
|
||||
InitPKEditor(row);
|
||||
if (m_rs->Save())
|
||||
{
|
||||
RestoreEditorControls();
|
||||
FillGrid();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ID_MNU_CANCEL:
|
||||
if (m_rs)
|
||||
{
|
||||
HideCellEditControl();
|
||||
const unsigned int nbCols = m_rs->GetColumnCount();
|
||||
int row = m_rs->GetRow();
|
||||
if (m_rs->IsInserting()) row = m_rs->GetRowCount();
|
||||
for (int c = 0; c < nbCols; c++)
|
||||
{
|
||||
wxAny data = wxEmptyString;
|
||||
if (!m_rs->IsInserting())
|
||||
data = (m_rs->GetData(row, c));
|
||||
m_stringTable->SetValue(row, c, data.As<wxString>());
|
||||
}
|
||||
m_rs->Cancel();
|
||||
RestoreEditorControls();
|
||||
row = m_rs->HasData() ? m_rs->GetRow() : 0;
|
||||
GoToCell(row, GetGridCursorCol());
|
||||
SelectRow(row);
|
||||
ForceRefresh();
|
||||
}
|
||||
break;
|
||||
case ID_MNU_REFRESH:
|
||||
// If there's no data, the grid is on insert row and AddNew() has been called.
|
||||
if (!m_rs->HasData()) m_rs->Cancel();
|
||||
RestoreEditorControls();
|
||||
m_rs->Refresh();
|
||||
FillGrid();
|
||||
break;
|
||||
case ID_MNU_DELETE:
|
||||
if (m_rs)
|
||||
{
|
||||
if (m_rs->GetRowCount() < 1) return;
|
||||
InitPKEditor(m_rs->GetRow());
|
||||
if (m_rs->Delete())
|
||||
{
|
||||
RestoreEditorControls();
|
||||
FillGrid();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ID_MNU_FORMVIEW:
|
||||
ShowFormView();
|
||||
break;
|
||||
}
|
||||
GetGridWindow()->SetFocus();
|
||||
}
|
||||
|
||||
bool LBoundGrid::InitPKEditor(const int row)
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
for (int c = 0; c < GetNumberCols(); c++)
|
||||
{
|
||||
wxObjectDataPtr<wxGridCellAttr> cellAttr;
|
||||
cellAttr = m_stringTable->GetAttr(row, c, wxGridCellAttr::Col);
|
||||
if (cellAttr.get() == NULL) continue;
|
||||
wxObjectDataPtr<wxGridCellEditor> ed;
|
||||
ed = cellAttr->GetEditor(this, row, c);
|
||||
if (ed.get() == NULL) continue;
|
||||
LGridColEditor * gce = dynamic_cast<LGridColEditor*> (ed.get());
|
||||
if (gce == NULL) continue;
|
||||
if (gce->GetColumnName().Lower() == m_rs->GetPKColumnName().Lower())
|
||||
{
|
||||
ed->BeginEdit(row, c, this);
|
||||
ed->Show(false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LBoundGrid::ShowFormView()
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
wxDialog * dlg = new wxDialog(this, wxID_ANY, _("Form view"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxMAXIMIZE_BOX | wxRESIZE_BORDER);
|
||||
unsigned int row = m_rs->GetRow();
|
||||
if (m_rs->IsInserting()) row = m_rs->GetRowCount();
|
||||
// We want to ignore hidden columns.
|
||||
unsigned int visibleCol = 0;
|
||||
// Multiline wxTextCtrl must be able to expand vertically.
|
||||
bool hasMultiline = false;
|
||||
|
||||
// ScrolledWindow/VerticalSizer/Panel/VerticalSizer/FlexGridSizer
|
||||
// /ClientSizer
|
||||
wxScrolledWindow * swMain = new wxScrolledWindow(dlg, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER | wxHSCROLL | wxVSCROLL);
|
||||
swMain->SetScrollbars(1, 1, 0, 0);
|
||||
wxBoxSizer* vsz0 = new wxBoxSizer(wxVERTICAL);
|
||||
swMain->SetSizer(vsz0);
|
||||
wxPanel * pan0 = new wxPanel(swMain, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER | wxHSCROLL | wxVSCROLL | wxTAB_TRAVERSAL);
|
||||
vsz0->Add(pan0, 1, wxEXPAND);
|
||||
wxBoxSizer * vsz = new wxBoxSizer(wxVERTICAL);
|
||||
wxFlexGridSizer * flxsz = new wxFlexGridSizer(0, 2, 0, 0);
|
||||
pan0->SetSizer(vsz);
|
||||
vsz->Add(flxsz, 1, wxGROW | wxGROW | wxALL);
|
||||
flxsz->AddGrowableCol(1);
|
||||
m_formClientSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
vsz->Add(m_formClientSizer, 0, wxGROW, 1);
|
||||
|
||||
for (unsigned int col = 0; col < GetNumberCols(); col++)
|
||||
{
|
||||
if (GetColSize(col) == 0) continue;
|
||||
InitEditor(row, col, true);
|
||||
LGridColEditor * gce = GetColEditor(row, col);
|
||||
if (gce == NULL) continue;
|
||||
int type = gce->GetType();
|
||||
// Receive the form editor from LGridColEditor::ProvideFormEditor
|
||||
wxControl * fEditor = NULL;
|
||||
// One more pointer to a text control
|
||||
wxTextCtrl * txtCtrl = NULL;
|
||||
switch (type)
|
||||
{
|
||||
case LGridColEditor::TEXT:
|
||||
fEditor = static_cast<wxTextCtrl*> (gce->ProvideFormEditor(pan0));
|
||||
txtCtrl = static_cast<wxTextCtrl*> (fEditor);
|
||||
break;
|
||||
case LGridColEditor::CHECK:
|
||||
fEditor = static_cast<wxCheckBox*> (gce->ProvideFormEditor(pan0));
|
||||
break;
|
||||
case LGridColEditor::COMBO:
|
||||
fEditor = static_cast<wxComboBox*> (gce->ProvideFormEditor(pan0));
|
||||
break;
|
||||
case LGridColEditor::DATE:
|
||||
fEditor = static_cast<wxDatePickerCtrl*> (gce->ProvideFormEditor(pan0));
|
||||
break;
|
||||
case LGridColEditor::SPIN:
|
||||
fEditor = static_cast<wxSpinCtrl*> (gce->ProvideFormEditor(pan0));
|
||||
break;
|
||||
case LGridColEditor::JSON_GRID:
|
||||
fEditor = static_cast<JsonGridPickerCtrl*> (gce->ProvideFormEditor(pan0));
|
||||
break;
|
||||
case LGridColEditor::XML_GRID:
|
||||
fEditor = static_cast<XmlGridPickerCtrl*> (gce->ProvideFormEditor(pan0));
|
||||
break;
|
||||
}
|
||||
// A label corresponding to the grid column header
|
||||
wxStaticText * lbl = new wxStaticText(pan0, wxID_ANY, m_stringTable->GetColLabelValue(col), wxDefaultPosition, wxDefaultSize, 0);
|
||||
flxsz->Add(lbl, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 0);
|
||||
if (txtCtrl && txtCtrl->IsMultiLine())
|
||||
{
|
||||
flxsz->Add(fEditor, 0, wxGROW | wxGROW | wxALL, 0);
|
||||
txtCtrl = NULL;
|
||||
// The multiline text control must expand.
|
||||
flxsz->AddGrowableRow(visibleCol);
|
||||
hasMultiline = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
flxsz->Add(fEditor, 0, wxGROW | wxALIGN_CENTER_VERTICAL | wxALL, 0);
|
||||
}
|
||||
wxObjectDataPtr<wxGridCellAttr> cellAttr;
|
||||
cellAttr = m_stringTable->GetAttr(row, col, wxGridCellAttr::Col);
|
||||
if (cellAttr.get() != NULL)
|
||||
{
|
||||
// read only columns must not be edited
|
||||
fEditor->Enable(!cellAttr->IsReadOnly());
|
||||
}
|
||||
fEditor->Show(true);
|
||||
// visibleCol <> col
|
||||
visibleCol++;
|
||||
}
|
||||
|
||||
wxSize dSize = wxDefaultSize;
|
||||
if (hasMultiline)
|
||||
{
|
||||
// Some arbitrary values
|
||||
wxSize screen = wxGetDisplaySize();
|
||||
dSize.SetWidth(screen.GetWidth() * 0.4);
|
||||
dSize.SetHeight(screen.GetHeight() * 0.75);
|
||||
}
|
||||
// Let the application do something with the dialog before we show it
|
||||
if (m_gridFormEVH) m_gridFormEVH->BeforeFormShown(this, m_formClientSizer);
|
||||
vsz->SetSizeHints(pan0); // here
|
||||
dlg->SetSize(dSize);
|
||||
dlg->CentreOnScreen();
|
||||
swMain->FitInside();
|
||||
int res = dlg->ShowModal();
|
||||
// Sync back any edits. Here we don't care about visible columns.
|
||||
for (int col = 0; col < GetNumberCols(); col++)
|
||||
{
|
||||
LGridColEditor * dce = GetColEditor(row, col);
|
||||
if (dce == NULL) continue;
|
||||
dce->SyncBack(row, col, this);
|
||||
}
|
||||
// Let the application complete whatever.
|
||||
if (m_gridFormEVH) m_gridFormEVH->AfterFormHidden(this, m_formClientSizer);
|
||||
SetFocus();
|
||||
dlg->Destroy();
|
||||
wxDELETE(dlg); // ??
|
||||
m_formClientSizer = NULL;
|
||||
// Last information. But it's not idle time yet; this may be a source of unexpected trouble.
|
||||
if (m_gridFormEVH) m_gridFormEVH->AfterFormDestroyed(this);
|
||||
}
|
||||
|
||||
void LBoundGrid::RestoreEditorControls()
|
||||
{
|
||||
wxASSERT_MSG(m_rs != NULL, _("RS = NULL"));
|
||||
while (m_rs->GetRegisteredControls().GetCount())
|
||||
{
|
||||
LBoundControl * ctrl = static_cast<LBoundControl*> (m_rs->GetRegisteredControls().Item(0));
|
||||
m_rs->UnRegisterControl(ctrl);
|
||||
ctrl->SetNull();
|
||||
}
|
||||
}
|
||||
|
||||
void LBoundGrid::ResetColEditor(const int col)
|
||||
{
|
||||
wxObjectDataPtr<wxGridCellAttr> cellAttr;
|
||||
cellAttr = m_stringTable->GetAttr(GetGridCursorRow(), col, wxGridCellAttr::Col);
|
||||
if (cellAttr == NULL) return;
|
||||
wxObjectDataPtr<wxGridCellEditor> ed;
|
||||
ed = cellAttr->GetEditor(this, GetGridCursorRow(), col);
|
||||
// This deletes the editor (m_control).
|
||||
if (ed.get()) ed->Reset();
|
||||
}
|
||||
|
||||
void LBoundGrid::SetDefaultRowSize(int height, bool resizeExistingRows)
|
||||
{
|
||||
wxGrid::SetDefaultRowSize(((wxDouble) height) * m_scaleFactor, resizeExistingRows);
|
||||
}
|
||||
|
||||
void LBoundGrid::SetColMinimalAcceptableWidth(int width)
|
||||
{
|
||||
wxGrid::SetColMinimalAcceptableWidth(((wxDouble) width) * m_scaleFactor);
|
||||
}
|
||||
|
||||
void LBoundGrid::SetColMinimalWidth(int col, int width)
|
||||
{
|
||||
wxGrid::SetColMinimalWidth(col, ((wxDouble) width) * m_scaleFactor);
|
||||
}
|
||||
|
||||
void LBoundGrid::SetColSize(int col, int width)
|
||||
{
|
||||
wxGrid::SetColSize(col, ((wxDouble) width) * m_scaleFactor);
|
||||
}
|
||||
|
||||
void LBoundGrid::SetDefaultColSize(int width, bool resizeExistingCols)
|
||||
{
|
||||
wxGrid::SetDefaultColSize(((wxDouble) width) * m_scaleFactor, resizeExistingCols);
|
||||
}
|
||||
|
||||
void LBoundGrid::SetRowLabelSize(int width)
|
||||
{
|
||||
wxGrid::SetRowLabelSize(((wxDouble) width) * m_scaleFactor);
|
||||
}
|
||||
|
||||
void LBoundGrid::SetRowMinimalAcceptableHeight(int height)
|
||||
{
|
||||
wxGrid::SetRowMinimalAcceptableHeight(((wxDouble) height) * m_scaleFactor);
|
||||
}
|
||||
|
||||
void LBoundGrid::SetRowMinimalHeight(int row, int height)
|
||||
{
|
||||
wxGrid::SetRowMinimalHeight(row, ((wxDouble) height) * m_scaleFactor);
|
||||
}
|
||||
|
||||
void LBoundGrid::SetRowSize(int row, int height)
|
||||
{
|
||||
wxGrid::SetRowSize(row, ((wxDouble) height) * m_scaleFactor);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LBoundGridFormEvent::LBoundGridFormEvent()
|
||||
{
|
||||
}
|
||||
|
||||
LBoundGridFormEvent::~LBoundGridFormEvent()
|
||||
{
|
||||
}
|
||||
|
||||
void LBoundGridFormEvent::BeforeFormShown(const LBoundGrid * origin, wxBoxSizer* clientSizer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LBoundGridFormEvent::AfterFormHidden(const LBoundGrid * origin, wxBoxSizer* clientSizer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LBoundGridFormEvent::AfterFormDestroyed(const LBoundGrid * origin)
|
||||
{
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user