Code: Select all
#ifndef DISPLAYDATASIZER_H
#define DISPLAYDATASIZER_H
#pragma once
#include <wx/sizer.h>
class TXMLDataForm;
class TItemDef;
class TDisplayDataSizer;
enum
{
POP_RESTORE = 3000,
POP_MOVE_TO_TOP,
POP_SHOW_DEF
};
class MyTextCtrl : public wxTextCtrl
{
private:
TXMLDataForm *FDataForm;
TItemDef *FItemDef;
TDisplayDataSizer *FDisplaySizer;
public:
MyTextCtrl(wxWindow *parent, wxWindowID id, const wxString &value,
const wxPoint &pos, const wxSize &size, int style = 0, TDisplayDataSizer *display_sizer = NULL)
: wxTextCtrl(parent, id, value, pos, size, style)
{
FDataForm = NULL;
FItemDef = NULL;
FDisplaySizer = display_sizer; // needed for OnMoveSizerToTop
}
void SetDataForm(TXMLDataForm* data_form) { FDataForm = data_form; }
void SetItemDef(TItemDef* item_def) { FItemDef = item_def; }
void OnExitTextCtrl(wxFocusEvent& event); // for FValueText on DisplayDataSizer
void OnPopupMenu(wxContextMenuEvent& event);
void OnRestoreOriginal(wxCommandEvent& event);
void OnMoveSizerToTop(wxCommandEvent& event);
wxDECLARE_EVENT_TABLE();
};
class TDisplayDataSizer : public wxBoxSizer
{
public:
TDisplayDataSizer(wxScrolledWindow* parent, int orient, TItemDef* item_def, TXMLDataForm* data_form);
~TDisplayDataSizer() { ; }
// getters and setters
wxBoxSizer* GetItemNameSizer() { return FItemNameSizer; }
wxBoxSizer* GetNumIdSizer() { return FNumIdSizer; }
wxBoxSizer* GetValueSizer() { return FValueSizer; }
wxPanel* GetPanel() { return FPanel; }
TItemDef* GetItemDef() { return FItemDef; }
MyTextCtrl* GetMyTextCtrl() { return FValueText; }
wxString GetNaaccrNameLabel() { return FNaaccrNameLabel->GetLabel(); }
wxString GetNaaccrNumLabel() { return FNaaccrNumLabel->GetLabel(); }
wxString GetNaaccrIdLabel() { return FNaaccrIdLabel->GetLabel(); }
wxString GetValueText() { return FValueText->GetValue(); }
void SetNaaccrNameLabel(wxString label) { FNaaccrNameLabel->SetLabel(label); }
void SetNaaccrNumLabel(wxString label) { FNaaccrNumLabel->SetLabel(label); }
void SetNaaccrIdLabel(wxString label) { FNaaccrIdLabel->SetLabel(label); }
void SetValueText(wxString text) { FValueText->ChangeValue(text); }
void SetValueTextForegroundColour(bool is_original)
{
if (is_original)
FValueText->SetForegroundColour(*wxBLACK);
else
FValueText->SetForegroundColour(*wxRED);
}
private:
wxScrolledWindow *FParent;
TXMLDataForm *FDataForm;
TItemDef *FItemDef;
wxPanel *FPanel;
wxBoxSizer *FPanelSizer;
wxBoxSizer *FItemNameSizer; // Horizontal with two static texts "Item: naaccrName"
wxBoxSizer *FNumIdSizer; // Horizontal with two static texts "Number: naaccrNum Id: naaccrId
wxBoxSizer *FValueSizer; // Horizontal with one text ctrl "Original value"
wxStaticText *FNaaccrNameLabel; // i.e., "Date of Diagnosis", not "Item:"
wxStaticText *FNaaccrNumLabel; // i.e., "390", not "Num:"
wxStaticText *FNaaccrIdLabel; // i.e., "dateOfDiagnosis", not "Id:"
MyTextCtrl *FValueText;
wxString stringReplace(const wxString instring, wxString oldpatt, wxString newpatt);
};
#endif
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/string.h>
#include <wx/colour.h>
//#include <wx/textctrl.h>
//#include <wx/window.h>
#include "DisplayDataSizer.h"
#include "XMLDataForm.h"
//--------------------------------------------------------------------
// MyTextCtrl
//--------------------------------------------------------------------
wxBEGIN_EVENT_TABLE(MyTextCtrl, wxTextCtrl)
EVT_KILL_FOCUS(MyTextCtrl::OnExitTextCtrl)
EVT_CONTEXT_MENU(MyTextCtrl::OnPopupMenu)
EVT_MENU(POP_RESTORE, MyTextCtrl::OnRestoreOriginal)
EVT_MENU(POP_MOVE_TO_TOP, MyTextCtrl::OnMoveSizerToTop)
wxEND_EVENT_TABLE()
void MyTextCtrl::OnExitTextCtrl(wxFocusEvent& event)
{
if (this->FDataForm && this->FItemDef)
{
bool t_changed = false;
wxString t_value = this->GetValue();
FDataForm->UpdateOnExitTextCtrl(t_value, FItemDef, t_changed);
if (t_changed)
{
this->SetForegroundColour(*wxRED);
}
}
event.Skip();
} // OnExitTextCtrl
void MyTextCtrl::OnPopupMenu(wxContextMenuEvent& event)
{
wxMenu menu;
menu.Append(POP_RESTORE, "&Restore original value");
menu.Append(POP_MOVE_TO_TOP, "Move item to top of display");
menu.Append(POP_SHOW_DEF, "Show dictionary definition");
PopupMenu(&menu, ScreenToClient(event.GetPosition()));
// Do not call event.Skip(), because for some reason
// in this situation, it goes ahead and calls up the chain.
// Isn't that what Skip() is intended to prevent?
// Anyway, this is what doublemax told me to do, and it works.
//event.Skip();
} // OnPopupMenu
void MyTextCtrl::OnRestoreOriginal(wxCommandEvent& event)
{
wxString t_value = this->GetValue();
if (FDataForm->RestoreOriginalValue(FItemDef, t_value))
{
this->ChangeValue(t_value);
this->SetForegroundColour(*wxBLACK);
}
event.Skip();
}
void MyTextCtrl::OnMoveSizerToTop(wxCommandEvent& event)
{
FDataForm->MoveSizerToTop(FDisplaySizer);
event.Skip();
}
//--------------------------------------------------------------------
// TDisplayDataSizer
//--------------------------------------------------------------------
TDisplayDataSizer::TDisplayDataSizer(wxScrolledWindow* parent, int orient, TItemDef* item_def, TXMLDataForm* data_form)
: wxBoxSizer(orient)
{
FParent = parent;
FItemDef = item_def;
FDataForm = data_form;
FPanel = new wxPanel(FParent);
FPanelSizer = new wxBoxSizer(orient); // wxVERTICAL
FPanel->SetSizer(FPanelSizer);
this->Add(FPanel, 0, wxEXPAND | wxALL, 5);
wxColour my_dim_gray = wxColour(66, 66, 66);
wxColour my_cadet_blue = wxColour(37, 62, 63);
wxColour my_cornflower_blue = wxColour(39, 58, 93);
wxColour my_dark_cyan = wxColour(0, 55, 55);
wxColour my_brown = wxColour(55, 0, 0);
// assemble the sizer
FItemNameSizer = new wxBoxSizer(wxHORIZONTAL);
wxStaticText *t_label = new wxStaticText(FPanel, wxID_ANY, "Item:");
t_label->SetForegroundColour(my_brown);
FItemNameSizer->Add(t_label, 0, wxRIGHT, 5);
FItemNameSizer->AddSpacer(8);
FNaaccrNameLabel = new wxStaticText(FPanel, wxID_ANY, FItemDef->FieldName);
FItemNameSizer->Add(FNaaccrNameLabel, 1, wxEXPAND | wxLEFT | wxRIGHT, 5);
FPanelSizer->Add(FItemNameSizer);
FNumIdSizer = new wxBoxSizer(wxHORIZONTAL);
t_label = new wxStaticText(FPanel, wxID_ANY, "Number:");
t_label->SetForegroundColour(my_brown);
FNumIdSizer->Add(t_label, wxRIGHT, 5);
FNumIdSizer->AddSpacer(8);
FNaaccrNumLabel = new wxStaticText(FPanel, wxID_ANY, wxString::Format("%i", FItemDef->FieldNumber));
FNumIdSizer->Add(FNaaccrNumLabel);
FNumIdSizer->AddSpacer(16);
t_label = new wxStaticText(FPanel, wxID_ANY, "NaaccrId:");
t_label->SetForegroundColour(my_brown);
FNumIdSizer->Add(t_label, 0, wxRIGHT, 5);
FNumIdSizer->AddSpacer(8);
FNaaccrIdLabel = new wxStaticText(FPanel, wxID_ANY, FItemDef->NaaccrId);
FNumIdSizer->Add(FNaaccrIdLabel);
FPanelSizer->Add(FNumIdSizer);
FValueSizer = new wxBoxSizer(wxHORIZONTAL);
FValueText = new MyTextCtrl(FPanel, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER, this);
wxString t_sizer(FItemDef->Length, 'W');
FValueText->SetInitialSize(
FValueText->GetSizeFromTextSize(
FValueText->GetTextExtent(t_sizer)));
FValueText->SetMaxLength(FItemDef->Length);
FValueText->SetDataForm(FDataForm);
FValueText->SetItemDef(FItemDef);
FValueSizer->Add(FValueText, 1, wxEXPAND | wxLEFT | wxRIGHT, 5);
FPanelSizer->Add(FValueSizer);
} // ctor with ItemDef
This is the code for the wxMDIChildFrame containing the custom sizers (amidst a bunch of other stuff):
Code: Select all
#ifndef XMLDATAFORM_H
#define XMLDATAFORM_H
#pragma once
#include <wx/event.h>
#include <map>
#include <vector>
#include "MDIChildForm.h"
class TItemDef : public wxObject
{
public:
TItemDef() : wxObject() { ; }
~TItemDef() { ; }
wxString NaaccrId;
int FieldNumber;
wxString FieldName;
wxString ParentXMLElement;
wxString RecordTypes;
int StartPos;
int Length;
int AllowUnlimitedText;
wxString Contains;
wxString DataType;
wxString DictionaryUri;
wxString Padding;
wxString Trim;
};
typedef struct
{
bool IsBase;
wxString Uri;
wxString Version;
wxString Specification;
wxString Description;
wxString Xmlns;
} TDictionaryDef;
class TDataItem : public wxObject
{
public:
TDataItem() : wxObject() { ; }
TDataItem(TItemDef* item_def) : wxObject() { ItemDef = item_def; }
~TDataItem() { ; }
TItemDef *ItemDef;
wxString OriginalValue;
wxString ModifiedValue;
};
class TPatient : public wxObject
{
public:
TPatient() : wxObject() { ; }
virtual ~TPatient();
unsigned int PatientOrdinal;
bool IsHidden;
bool IsModified;
// These vectors will hold entries for only those ItemDefs for which
// this patient has non-blank data.
std::vector<TDataItem*> FPatientItems; // sort by TDataItem->ItemDef->FieldNumber
// FTumorItems is a vector of vectors because a Patient record can have 0-to-many Tumors
std::vector<std::vector<TDataItem*> > FTumorItems; // sort by TDataItem->ItemDef->FieldNumber
TDataItem* FindPatientItem(int FieldNumber);
TDataItem* FindTumorItem(int tumor_ordinal, int FieldNumber);
TDataItem* FindFirstModifiedDataItem();
};
// forward declarations
class TXmlInterface;
class TDisplayDataSizer;
class TXMLDataForm : public TMDIChildForm
{
private:
TXmlInterface* FXmlInterface;
wxBoxSizer *FFormSizer; // wxHORIZONTAL, listbox to left, TDisplayDataSizers to the right
wxBoxSizer *FListBoxSizer; // wxVERTICAL
wxBoxSizer *FDisplaySizer; // wxVERTICAL
wxRadioBox *FDataRadioBox;
bool FShowAllPanels;
wxSpinButton *FTumorSpinButton;
wxStaticText *FSpinLabel;
int FCurrentTumorOrdinal;
wxNotebook *FNotebook;
wxScrolledWindow *FPatientPage;
wxScrolledWindow *FTumorPage;
wxScrolledWindow *FNaaccrDataPage;
wxBoxSizer *FPatientSizer;
wxBoxSizer *FTumorSizer;
wxBoxSizer *FNaaccrDataSizer;
std::vector<TPatient*> FPatients;
size_t FMaxSize;
wxListBox *FPatientsListBox;
std::vector<TDataItem*> FNaaccrDataItems; // contains the editable values for NaaccrData items
std::map<int, TDictionaryDef*> FDictionaryDefs;
std::map<int, TItemDef*> FItemDefsByNaaccrNum;
std::map<wxString, TItemDef*> FItemDefsByNaaccrId;
// I need to read the data according to ParentLevel, so
// we'll put these into vectors for reading by SetUpPatients()
std::vector<TItemDef*> FNaaccrDataItemDefs;
std::vector<TItemDef*> FPatientDataItemDefs;
std::vector<TItemDef*> FTumorDataItemDefs;
bool GetDictionariesFromXmlDataFile(wxString dictionaries_folder, wxString xml_file, wxString& base, wxString& user);
bool SetUpPatients();
void CreateDisplayPanels();
void UpdateNaaccrDataControls(bool show_all = false);
TDataItem* FindNaaccrDataItem(int FieldNumber);
void UpdatePatientControls(TPatient* patient, bool show_all = false);
void UpdateTumorControls(TPatient* patient, int tumor_ordinal, bool show_all = false);
wxPanel* CreateDataControlPanel(TXMLDataForm *parent);
public:
TXMLDataForm();
TXMLDataForm(wxMDIParentFrame *parent, wxString filename, wxString dictionaries_dir, TXmlInterface* xml_interface);
~TXMLDataForm();
wxString FXmlFileName;
wxString FDictionariesDir;
bool FIsModified;
TPatient* FCurrentPatient; // for use by callback to OpenXmlDataFile
void AddToPatient(TItemDef* item_def, int tumor_ordinal, wxString value);
bool Initialize();
void GetMenuCaps(TMenuCaps&);
// make the FItemDefs available to the callback
std::map<int, TItemDef*>& GetItemDefsByNaaccrNum() { return FItemDefsByNaaccrNum; }
std::map<wxString, TItemDef*>& GetItemDefsByNaaccrId() { return FItemDefsByNaaccrId; }
static void ShowItemDef(
void* owner,
const char* NaaccrId,
const int NaaccrNum,
const char* NaaccrName,
const int StartColumn,
const int Length,
const int AllowUnlimitedText,
const char* Contains,
const char* RecordTypes,
const char* ParentXmlElement,
const char* DataType,
const char* DictionaryUri,
const char* Padding,
const char* Trim);
static void ReadItemByNaaccrId(
void* owner,
const int patient_ordinal, // the nth Patient
const int tumor_ordinal, // the 1st, 2nd, etc. Tumor for the nth Patient
const char* NaaccrId,
const int NaaccrNum,
const char* value);
void UpdateOnExitTextCtrl(wxString current_value, TItemDef *item_def, bool& is_changed);
bool RestoreOriginalValue(TItemDef *item_def, wxString& value);
void MoveSizerToTop(TDisplayDataSizer *display_sizer);
void OnSetFilter(wxCommandEvent& event);
void OnClearFilter(wxCommandEvent& event);
void OnSave(wxCommandEvent& event);
void OnSaveAs(wxCommandEvent& event);
void OnRunEDITS(wxCommandEvent& event);
void OnSelListBox(wxCommandEvent& event);
void OnDataRadioBox(wxCommandEvent& event);
void OnSpinTumor(wxCommandEvent& event);
wxDECLARE_EVENT_TABLE();
};
#endif
// For compilers that support precompilation, includes "wx/wx.h".
#include <wx/wxprec.h>
#include <memory> // std::unique_ptr
#include <fstream>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/notebook.h>
#include <wx/radiobox.h>
#include <wx/spinbutt.h>
#include <wx/busyinfo.h>
#include <wx/evtloop.h>
#include <wx/colour.h>
#include "XMLDataForm.h"
#include "MainFrm.h"
#include "XmlInterface.h"
#include "DisplayDataSizer.h"
#include "ProgressDialog.h"
wxBEGIN_EVENT_TABLE(TXMLDataForm, wxMDIChildFrame)
EVT_MENU(ID_SetFilter, TXMLDataForm::OnSetFilter)
EVT_MENU(ID_ClearFilter, TXMLDataForm::OnClearFilter)
EVT_MENU(ID_Save, TXMLDataForm::OnSave)
EVT_MENU(ID_SaveAs, TXMLDataForm::OnSaveAs)
EVT_MENU(ID_RunEDITS, TXMLDataForm::OnRunEDITS)
wxEND_EVENT_TABLE()
TPatient::~TPatient()
{
std::vector<TDataItem*>::iterator pit = FPatientItems.begin();
while (pit != FPatientItems.end())
{
delete (*pit);
pit++;
}
for (size_t t_idx = 0; t_idx < FTumorItems.size(); t_idx++)
{
std::vector<TDataItem*>::iterator tit = FTumorItems[t_idx].begin();
while (tit != FTumorItems[t_idx].end())
{
delete (*tit);
tit++;
}
}
} // TPatient dtor
TDataItem* TPatient::FindPatientItem(int FieldNumber)
{
TDataItem* t_patient_item = NULL;
int t_low = 0,
t_high = FPatientItems.size() - 1,
t_mid;
while (t_low <= t_high)
{
t_mid = (t_low + t_high) / 2;
if (FPatientItems[t_mid]->ItemDef->FieldNumber == FieldNumber)
return FPatientItems[t_mid];
else if (FPatientItems[t_mid]->ItemDef->FieldNumber > FieldNumber)
t_high = t_mid - 1;
else
t_low = t_mid + 1;
}
return t_patient_item;
} // FindPatientItem
TDataItem* TPatient::FindTumorItem(int tumor_ordinal, int FieldNumber)
{
TDataItem* t_patient_item = NULL;
if (tumor_ordinal < (int)FTumorItems.size())
{
std::vector<TDataItem*> t_tumors = FTumorItems[tumor_ordinal];
int t_low = 0,
t_high = t_tumors.size() - 1,
t_mid;
while (t_low <= t_high)
{
t_mid = (t_low + t_high) / 2;
if (t_tumors[t_mid]->ItemDef->FieldNumber == FieldNumber)
return t_tumors[t_mid];
else if (t_tumors[t_mid]->ItemDef->FieldNumber > FieldNumber)
t_high = t_mid - 1;
else
t_low = t_mid + 1;
}
}
return t_patient_item;
} // FindTumorItem
TDataItem* TPatient::FindFirstModifiedDataItem()
{
TDataItem* t_data_item = NULL;
std::vector<TDataItem*>::iterator pit = FPatientItems.begin();
while (pit != FPatientItems.end())
{
if (!(*pit)->ModifiedValue.empty())
{
t_data_item = (*pit);
return t_data_item;
}
pit++;
}
for (size_t t_idx = 0; t_idx < FTumorItems.size(); t_idx++)
{
std::vector<TDataItem*>::iterator tit = FTumorItems[t_idx].begin();
while (tit != FTumorItems[t_idx].end())
{
if (!(*tit)->ModifiedValue.empty())
{
t_data_item = (*tit);
return t_data_item;
}
tit++;
}
}
return t_data_item;
} // FindFirstModifiedDataItem
TXMLDataForm::TXMLDataForm(wxMDIParentFrame *parent, wxString filename, wxString dictionaries_dir, TXmlInterface* xml_interface)
: TMDIChildForm(parent, filename)
{
FXmlFileName = filename;
FDictionariesDir = dictionaries_dir;
FIsModified = false;
FXmlInterface = xml_interface;
// FIX ME: TESTING
FMaxSize = 10000;
FPatients.reserve(FMaxSize);
} // ctor
TXMLDataForm::~TXMLDataForm()
{
{
if (FPatientsListBox)
FPatientsListBox->Clear();
std::vector<TPatient*>::iterator itx = FPatients.begin();
while (itx != FPatients.end())
{
TPatient* t_temp = (*itx);
delete t_temp;
itx++;
}
}
{
std::map<int, TDictionaryDef*>::iterator itx = FDictionaryDefs.begin();
while (itx != FDictionaryDefs.end())
{
delete (*itx).second;
itx++;
}
}
{
// We stored the collection of ItemDefs in two maps; just
// free the objects from one of them.
std::map<int, TItemDef*>::iterator itx = FItemDefsByNaaccrNum.begin();
while (itx != FItemDefsByNaaccrNum.end())
{
delete (*itx).second;
itx++;
}
}
} // dtor
void TXMLDataForm::GetMenuCaps(TMenuCaps& caps)
{
wxMenuBar* t_bar = FMainFrame->GetMenuBar();
wxMenu* t_menu = t_bar->GetMenu(t_bar->FindMenu("&Xml Data"));
if (FIsModified)
{
caps.insert(mcSave);
}
if (FIsFiltered)
{
caps.insert(mcClearFilter);
}
wxMenuItem* t_item = t_menu->FindItem(ID_Save);
if (t_item)
t_item->Enable(FIsModified);
t_item = t_menu->FindItem(ID_ClearFilter);
if (t_item)
t_item->Enable(FIsFiltered);
}
bool TXMLDataForm::Initialize()
{
wxString t_base;
wxString t_user;
bool t_result = GetDictionariesFromXmlDataFile(FDictionariesDir, FXmlFileName, t_base, t_user);
if (t_result)
{
if (!FXmlInterface->Initialize(t_base, t_user))
{
wxLogMessage("Failure in FXmlInterface->Initialize");
return false;
}
if (!FXmlInterface->GetAllItemDefs(this, ShowItemDef))
{
wxLogMessage("Failure in FXmlInterface->GetAllItemDefs");
return false;
}
if (!SetUpPatients())
{
wxLogMessage("Process cancelled by user");
return false;
}
FShowAllPanels = false; // initialize to show only what is populated
FFormSizer = new wxBoxSizer(wxHORIZONTAL);
SetSizer(FFormSizer);
FListBoxSizer = new wxBoxSizer(wxVERTICAL);
FFormSizer->Add(FListBoxSizer, wxSizerFlags().Expand().Border(wxALL, 10));
FPatientsListBox = new wxListBox(this, wxID_ANY, wxPoint(0, 0), wxDefaultSize, 0, NULL,
wxLB_SINGLE | wxLB_NEEDED_SB | wxLB_OWNERDRAW); // ?? | wxLB_OWNERDRAW
FPatientsListBox->Bind(wxEVT_LISTBOX, &TXMLDataForm::OnSelListBox, this);
FListBoxSizer->Add(FPatientsListBox, wxEXPAND | wxSHAPED);
FDisplaySizer = new wxBoxSizer(wxVERTICAL);
FNotebook = new wxNotebook(this, wxNB_TOP);
int m_hLine = 15;
size_t m_nLines = 50;
// Note: SetDoubleBuffered(true) eliminates that screen-flicker during
// the processing in the OnSelListBox handler
FPatientPage = new wxScrolledWindow(FNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL | wxALWAYS_SHOW_SB);
FPatientPage->SetDoubleBuffered(true);
// the 0 means don't use a horizontal scrollbar; just vertical
FPatientPage->SetScrollRate(0, m_hLine);
FPatientPage->FitInside();
FTumorPage = new wxScrolledWindow(FNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL | wxALWAYS_SHOW_SB);
FTumorPage->SetDoubleBuffered(true);
FTumorPage->SetScrollRate(0, m_hLine);
FTumorPage->FitInside();
FNaaccrDataPage = new wxScrolledWindow(FNotebook, wxID_ANY,
wxDefaultPosition, wxDefaultSize, wxVSCROLL | wxALWAYS_SHOW_SB);
FNaaccrDataPage->SetDoubleBuffered(true);
FNaaccrDataPage->SetScrollRate(0, m_hLine);
FNaaccrDataPage->FitInside();
FNotebook->AddPage(FPatientPage, "Patient", true);
FNotebook->AddPage(FTumorPage, "Tumor");
FNotebook->AddPage(FNaaccrDataPage, "NaaccrData");
FPatientSizer = new wxBoxSizer(wxVERTICAL);
FTumorSizer = new wxBoxSizer(wxVERTICAL);
FNaaccrDataSizer = new wxBoxSizer(wxVERTICAL);
FPatientPage->SetSizer(FPatientSizer);
FTumorPage->SetSizer(FTumorSizer);
FNaaccrDataPage->SetSizer(FNaaccrDataSizer);
FNotebook->SetSelection(0);
wxPanel *t_panel = CreateDataControlPanel(this);
FDisplaySizer->Add(t_panel, wxSizerFlags().Expand().Align(wxALIGN_TOP));
FDisplaySizer->Add(FNotebook, 1, wxEXPAND | wxALL);
FFormSizer->Add(FDisplaySizer, 1, wxEXPAND | wxALL);
wxString t_temp;
TPatient* t_first_patient = NULL;
std::vector<TPatient*>::iterator pit = FPatients.begin();
while (pit != FPatients.end())
{
TPatient* t_patient = (*pit);
if (!t_first_patient)
t_first_patient = t_patient;
t_temp.Printf("Patient #%d", t_patient->PatientOrdinal);
FPatientsListBox->Append(t_temp, (wxClientData*)t_patient);
pit++;
}
FPatientsListBox->SetSelection(0);
CreateDisplayPanels();
UpdateNaaccrDataControls(false);
if (t_first_patient)
{
UpdatePatientControls(t_first_patient, false);
UpdateTumorControls(t_first_patient, 1, false);
}
}
SetSizer(FFormSizer);
return t_result;
} // Initialize
bool TXMLDataForm::GetDictionariesFromXmlDataFile(wxString dictionaries_folder,
wxString xml_file, wxString& base, wxString& user)
{
bool t_result = true;
// This function reads the attributes of the <NaaccrData...> element
// to extract the baseDictionaryUri and (if it exists) the userDictionaryUri.
// It then lops off the "http://xxx.org/" that likely is fictional anyway
// (really... read the XML standard and the NAACCR XML implementation guide)
// to get the dictionary file name. For our purposes, we then prefix the
// file name with the path to the folder on this computer (FDictionariesDir)
// where we have stashed all of our dictionaries, and return that information to
// the caller so that TXmlInterface::Initialize can open and parse the dictionaries.
std::unique_ptr<std::ifstream> t_file(new std::ifstream(static_cast<const char*>(xml_file.c_str()),
std::ios_base::in | std::ios_base::binary));
if (t_file && !t_file->fail())
{
char t_buf[1024];
t_file->seekg(0, std::ios_base::beg);
t_file->read(t_buf, 1023);
if (t_file->good() || t_file->eof())
{
wxString t_header = t_buf;
wxString t_base_uri = "baseDictionaryUri=\"";
wxString t_user_uri = "userDictionaryUri=\"";
wxString t_parse, t_scrap;
// Get the base dictionary
size_t t_slash,
t_pos = t_header.find(t_base_uri);
if (t_pos != std::string::npos)
{
t_parse = t_header.substr(t_pos + t_base_uri.Length(), t_header.Length());
t_pos = t_parse.find("\"");
if (t_pos != std::string::npos)
{
t_scrap = t_parse.substr(0, t_pos);
// find the right-most forward slash and lop off
// everything that precedes it
t_slash = t_scrap.find_last_of("/");
if (t_slash != std::string::npos)
{
base = dictionaries_folder + FMainFrame->GetPathSeparator() +
t_scrap.substr(t_slash + 1, t_scrap.length());
}
}
}
if (base.IsEmpty())
{
return false;
}
// Get the user dictionar(y|ies)
user = ""; // initialize to empty string
t_pos = t_header.find(t_user_uri);
if (t_pos != std::string::npos)
{
t_parse = t_header.substr(t_pos + t_user_uri.length(), t_header.length());
t_pos = t_parse.find("\"");
if (t_pos != std::string::npos)
{
// remove the quotes around the attribute value
t_parse = t_parse.substr(0, t_pos);
while (!t_parse.empty())
{
t_pos = t_parse.find(" ");
if (t_pos != std::string::npos)
{
t_scrap = t_parse.substr(0, t_pos - 1);
t_slash = t_scrap.find_last_of("/");
if (t_slash == std::string::npos)
{
// bad format; just ignore this uri
break;
}
if (!user.IsEmpty())
{
user += wxString(" ");
}
user += dictionaries_folder + FMainFrame->GetPathSeparator() +
t_scrap.substr(t_slash + 1, t_scrap.length());
t_parse = t_parse.substr(t_pos + 1, t_parse.length());
}
else
{
t_scrap = t_parse;
t_slash = t_scrap.find_last_of("/");
if (t_slash == std::string::npos)
{
// bad format; just ignore this uri
break;
}
if (!user.empty())
{
user += wxString(" ");
}
user += dictionaries_folder + FMainFrame->GetPathSeparator() +
t_scrap.substr(t_slash + 1, t_scrap.Length());
t_parse = "";
}
}
}
}
}
}
return t_result;
} // GetDictionariesFromXmlDataFile
bool TXMLDataForm::SetUpPatients()
{
bool t_result = true;
size_t t_patient_ordinal = 0;
int t_tumor_ordinal = 0;
int t_is_eof = 0;
int t_tumor_count;
wxString msg;
msg.Printf("Processing Patient #%d", 1);
TProgressDialog dialog(this, wxID_ANY, "Parsing XML data file", wxDefaultPosition, wxDefaultSize, wxCAPTION);
dialog.SetLabelText(msg);
dialog.SetUpAndShow();
// iterate the FNaaccrDataItemDefs vector to get that data
// then...
FCurrentPatient = NULL;
if (!FXmlInterface->OpenXmlDataFile(FXmlFileName, this, ReadItemByNaaccrId, NULL))
{
wxLogMessage("TXMLDataForm::SetUpPatients - failure to OpenXmlDataFile");
return false;
}
try
{
int pat_ordinal = 0;
bool skip = false; // if user clicks "Skip", we'll just use what we have
bool cont = true; // if user clicks "Cancel", we'll abort
while (FXmlInterface->ReadNextPatient(&t_is_eof))
{
++pat_ordinal;
if (pat_ordinal == 1)
{
// Set the progress bar
msg.Printf("Processing Patient #%d", pat_ordinal);
dialog.Pulse(msg, &skip);
}
else if (pat_ordinal % 100 == 0)
{
// Use this where VCL used Application->ProcessMessages();
wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI | wxEVT_CATEGORY_USER_INPUT);
msg.Printf("Processing Patient #%d", pat_ordinal);
cont = dialog.Pulse(msg, &skip);
}
if (skip)
{
// User wants to look at what we have so far
break;
}
if (!cont) // user clicked Cancel or Skip
{
if (wxMessageBox(wxT("Do you really want to cancel?"),
wxT("Abandon parsing"), // caption
wxYES_NO | wxICON_QUESTION) == wxYES)
{
t_result = false;
break;
}
cont = true;
}
// Create a new TPatient
TPatient* t_patient = new TPatient();
t_patient->PatientOrdinal = ++t_patient_ordinal;
t_patient->IsHidden = false;
t_patient->IsModified = false;
// Trying to improve efficiency here... reserve room for
// all of the Patient-level items in the current dictionary
// collection
t_patient->FPatientItems.reserve(FPatientDataItemDefs.size());
// Make this visible to the AddToPatient function
FCurrentPatient = t_patient;
TItemDef* t_item_def;
std::vector<TItemDef*>::iterator pit = FPatientDataItemDefs.begin();
while (pit != FPatientDataItemDefs.end())
{
t_item_def = (*pit);
if (!FXmlInterface->GetItemDataByNaaccrId(t_item_def->NaaccrId))
{
wxLogMessage("TXMLDataForm::SetUpPatients - Cannot get patient item");
return false;
}
pit++;
}
if (FXmlInterface->GetPatientTumorsCount(&t_tumor_count))
{
for (t_tumor_ordinal = 1; t_tumor_ordinal <= t_tumor_count; t_tumor_ordinal++)
{
if (!FXmlInterface->ReadTumor(t_tumor_ordinal))
{
wxLogMessage("TXMLDataForm::SetUpPatients - Failure to ReadTumor");
return false;
}
// iterate the FTumorDataItemDefs vector
std::vector<TItemDef*>::iterator tit = FTumorDataItemDefs.begin();
while (tit != FTumorDataItemDefs.end())
{
t_item_def = (*tit);
if (!FXmlInterface->GetItemDataByNaaccrId(t_item_def->NaaccrId))
{
wxLogMessage("TXMLDataForm::SetUpPatients - cannot get tumor item");
return false;
}
tit++;
}
}
}
std::vector<TItemDef*>::iterator nit = FNaaccrDataItemDefs.begin();
while (nit != FNaaccrDataItemDefs.end())
{
t_item_def = (*nit);
if (!FXmlInterface->GetItemDataByNaaccrId(t_item_def->NaaccrId))
{
wxLogMessage("TXMLDataForm::SetUpPatients - Cannot get NaaccrData item");
return false;
}
nit++;
}
// Sort the TPatientItems by their ItemDef->FieldNumbers
std::sort(t_patient->FPatientItems.begin(), t_patient->FPatientItems.end(),
[](TDataItem* const& a, TDataItem* const& b)
{ return a->ItemDef->FieldNumber < b->ItemDef->FieldNumber; });
for (size_t t_idx = 0; t_idx < t_patient->FTumorItems.size(); t_idx++)
{
std::vector<TDataItem*> t_vector = t_patient->FTumorItems[t_idx];
std::sort(t_vector.begin(), t_vector.end(),
[](TDataItem* const& a, TDataItem* const& b)
{ return a->ItemDef->FieldNumber < b->ItemDef->FieldNumber; });
}
FPatients.push_back(t_patient);
if (t_patient->PatientOrdinal == FMaxSize)
{
FMaxSize += 5000;
FPatients.reserve(FMaxSize);
}
if (t_is_eof)
break;
}
}
catch (std::runtime_error& e)
{
wxLogMessage(e.what());
}
FXmlInterface->CloseXmlDataFile();
return t_result;
} // SetUpPatients
void TXMLDataForm::ShowItemDef(
void* owner,
const char* NaaccrId,
const int NaaccrNum,
const char* NaaccrName,
const int StartColumn,
const int Length,
const int AllowUnlimitedText,
const char* Contains,
const char* RecordTypes,
const char* ParentXmlElement,
const char* DataType,
const char* DictionaryUri,
const char* Padding,
const char* Trim)
{
TXMLDataForm* myself = (TXMLDataForm*)owner;
TItemDef* t_item_def = new TItemDef();
t_item_def->NaaccrId = NaaccrId;
t_item_def->FieldNumber = NaaccrNum;
t_item_def->FieldName = NaaccrName;
t_item_def->ParentXMLElement = ParentXmlElement;
t_item_def->RecordTypes = RecordTypes;
t_item_def->StartPos = StartColumn;
t_item_def->Length = Length;
t_item_def->AllowUnlimitedText = AllowUnlimitedText;
t_item_def->Contains = Contains;
t_item_def->DataType = DataType;
t_item_def->DictionaryUri = DictionaryUri,
t_item_def->Padding = Padding;
t_item_def->Trim = Trim;
myself->GetItemDefsByNaaccrNum()[NaaccrNum] = t_item_def;
myself->GetItemDefsByNaaccrId()[NaaccrId] = t_item_def;
// For use by SetUpPatients
if (t_item_def->ParentXMLElement.compare("Tumor") == 0)
myself->FTumorDataItemDefs.push_back(t_item_def);
else if (t_item_def->ParentXMLElement.compare("Patient") == 0)
myself->FPatientDataItemDefs.push_back(t_item_def);
else if (t_item_def->ParentXMLElement.compare("NaaccrData") == 0)
myself->FNaaccrDataItemDefs.push_back(t_item_def);
} // ShowItemDef
//---------------------------------------------------------------------------
void TXMLDataForm::ReadItemByNaaccrId(
void* owner,
const int patient_ordinal, // the nth Patient
const int tumor_ordinal, // the 1st, 2nd, etc. Tumor for the nth Patient
const char* NaaccrId,
const int NaaccrNum,
const char* value)
{
TXMLDataForm* myself = (TXMLDataForm*)owner;
if (value)
{
int t_vlen = std::strlen(value);
if (t_vlen > 0)
{
TItemDef* t_def = myself->GetItemDefsByNaaccrId()[NaaccrId];
if (t_def)
{
myself->AddToPatient(t_def, tumor_ordinal, value);
}
} // if (t_vlen > 0)
}
} // ReadItemByNaaccrId callback
//---------------------------------------------------------------------------
void TXMLDataForm::AddToPatient(TItemDef* item_def, int tumor_ordinal, wxString value)
{
TDataItem* t_data_item = new TDataItem(item_def);
t_data_item->OriginalValue = value;
t_data_item->ModifiedValue = "";
if (item_def->ParentXMLElement.compare("Patient") == 0)
{
//FCurrentPatient->FPatientItems[item_def->NaaccrId] = t_data_item;
FCurrentPatient->FPatientItems.push_back(t_data_item);
}
else if (item_def->ParentXMLElement.compare("Tumor") == 0)
{
// There could be 0-to-many Tumors for this FCurrentPatient,
// so we have to keep lists separated.
if (tumor_ordinal > 0)
{
std::vector<TDataItem*> t_vector;
if (tumor_ordinal > (int)FCurrentPatient->FTumorItems.size())
{
FCurrentPatient->FTumorItems.push_back(t_vector);
t_vector.reserve(FTumorDataItemDefs.size());
}
else
{
t_vector = FCurrentPatient->FTumorItems[tumor_ordinal - 1];
}
//t_vector[item_def->NaaccrId] = t_data_item;
t_vector.push_back(t_data_item);
FCurrentPatient->FTumorItems[tumor_ordinal - 1] = t_vector;
}
}
else if (item_def->ParentXMLElement.compare("NaaccrData") == 0)
{
// This will happen only once per data file for NaaccrData items
FNaaccrDataItems.push_back(t_data_item);
}
} // AddToPatient
void TXMLDataForm::OnSetFilter(wxCommandEvent& event)
{
// Call a dialog for setting the filters
// TESTING
TPatient* t_first_patient = NULL;
FIsFiltered = true;
FPatientsListBox->Clear();
std::vector<TPatient*>::iterator itx = FPatients.begin();
while (itx != FPatients.end())
{
TPatient* t_patient = (*itx);
int t_primary_site = 400;
wxString t_value = "C504";
wxString t_temp;
for (int t_jdx = 0; t_jdx < (int)t_patient->FTumorItems.size(); t_jdx++)
{
TDataItem* t_pat_item = t_patient->FindTumorItem(t_jdx, t_primary_site);
if (t_pat_item)
{
if (t_pat_item->ModifiedValue.empty())
{
if (t_pat_item->ModifiedValue.compare(t_value) == 0)
{
t_temp.Printf("Patient #%d", t_patient->PatientOrdinal);
FPatientsListBox->Append(t_temp, (wxClientData*)t_patient);
if (!t_first_patient)
t_first_patient = t_patient;
}
else if (t_pat_item->OriginalValue.compare(t_value) == 0)
{
t_temp.Printf("Patient #%d", t_patient->PatientOrdinal);
FPatientsListBox->Append(t_temp, (wxClientData*)t_patient);
if (!t_first_patient)
t_first_patient = t_patient;
}
// FIX ME: If t_patient->IsModified, set color and italics
if (t_patient->IsModified)
{
int t_kdx = FPatientsListBox->GetCount() -1;
if (t_kdx >= 0)
{
FPatientsListBox->GetItem(t_kdx)->SetTextColour(*wxRED);
FPatientsListBox->GetItem(t_kdx)->SetFont(wxFont().Italic());
}
}
}
}
}
itx++;
}
// Update the values in the data sizers
FPatientsListBox->SetSelection(0);
FPatientsListBox->EnsureVisible(0);
if (t_first_patient)
{
UpdatePatientControls(t_first_patient, FShowAllPanels);
UpdateTumorControls(t_first_patient, 1, FShowAllPanels);
}
event.Skip();
} // OnSetFilter
void TXMLDataForm::OnClearFilter(wxCommandEvent& event)
{
FIsFiltered = false;
FPatientsListBox->Clear();
TPatient* t_first_patient = NULL;
wxString t_temp;
std::vector<TPatient*>::iterator itx = FPatients.begin();
while (itx != FPatients.end())
{
TPatient* t_patient = (*itx);
t_temp.Printf("Patient #%d", t_patient->PatientOrdinal);
FPatientsListBox->Append(t_temp, (wxClientData*)t_patient);
if (!t_first_patient)
t_first_patient = t_patient;
// FIX ME: If t_patient->IsModified, set color and italics
if (t_patient->IsModified)
{
int t_kdx = FPatientsListBox->GetCount() - 1;
if (t_kdx >= 0)
{
FPatientsListBox->GetItem(t_kdx)->SetTextColour(*wxRED);
FPatientsListBox->GetItem(t_kdx)->SetFont(wxFont().Italic());
}
}
itx++;
}
// Update the values in the data sizers
FPatientsListBox->SetSelection(0);
FPatientsListBox->EnsureVisible(0);
if (t_first_patient)
{
UpdatePatientControls(t_first_patient, FShowAllPanels);
UpdateTumorControls(t_first_patient, 1, FShowAllPanels);
}
event.Skip();
} // OnClearFilter
void TXMLDataForm::OnSave(wxCommandEvent& event)
{
// Write data back to file of original name
event.Skip();
}
void TXMLDataForm::OnSaveAs(wxCommandEvent& event)
{
// Run a Save-as dialog and write data to new file name
event.Skip();
}
void TXMLDataForm::OnRunEDITS(wxCommandEvent& event)
{
// Launch Run EDITS process... dialog to obtain user preferences,
// create data buffers out of filtered data in tree view
event.Skip();
}
void TXMLDataForm::OnSelListBox(wxCommandEvent& event)
{
try
{
TPatient* t_patient = (TPatient*)event.GetClientObject();
if (t_patient)
{
UpdatePatientControls(t_patient, FShowAllPanels);
UpdateTumorControls(t_patient, 1, FShowAllPanels);
}
}
catch (std::runtime_error& e)
{
wxLogMessage(e.what());
}
event.Skip();
} // OnSelListBox
void TXMLDataForm::CreateDisplayPanels()
{
std::sort(FPatientDataItemDefs.begin(), FPatientDataItemDefs.end(),
[](TItemDef* const& a, TItemDef* const& b) { return a->NaaccrId < b->NaaccrId; });
std::sort(FTumorDataItemDefs.begin(), FTumorDataItemDefs.end(),
[](TItemDef* const& a, TItemDef* const& b) { return a->NaaccrId < b->NaaccrId; });
std::sort(FNaaccrDataItemDefs.begin(), FNaaccrDataItemDefs.end(),
[](TItemDef* const& a, TItemDef* const& b) { return a->NaaccrId < b->NaaccrId; });
int t_max = FPatientDataItemDefs.size() + FTumorDataItemDefs.size() + FNaaccrDataItemDefs.size(),
t_iteration = 0;
wxBusyInfo dialog("Please wait while edit controls are constructed", this);
std::vector<TItemDef*>::iterator pit = FPatientDataItemDefs.begin();
while (pit != FPatientDataItemDefs.end())
{
TItemDef* t_item = (*pit);
TDisplayDataSizer *t_display = new TDisplayDataSizer(FPatientPage, wxVERTICAL, t_item, this);
FPatientSizer->Add(t_display, wxEXPAND | wxALL);
pit++;
}
std::vector<TItemDef*>::iterator tit = FTumorDataItemDefs.begin();
while (tit != FTumorDataItemDefs.end())
{
TItemDef* t_item = (*tit);
TDisplayDataSizer *t_display = new TDisplayDataSizer(FTumorPage, wxVERTICAL, t_item, this);
FTumorSizer->Add(t_display, wxEXPAND | wxALL);
tit++;
}
std::vector<TItemDef*>::iterator nit = FNaaccrDataItemDefs.begin();
while (nit != FNaaccrDataItemDefs.end())
{
TItemDef* t_item = (*nit);
TDisplayDataSizer *t_display = new TDisplayDataSizer(FNaaccrDataPage, wxVERTICAL, t_item, this);
FNaaccrDataSizer->Add(t_display, wxEXPAND | wxALL);
nit++;
}
} // CreateDisplayPanels
void TXMLDataForm::UpdatePatientControls(TPatient* patient, bool show_all /* == false */)
{
size_t t_howmany = FPatientSizer->GetItemCount();
for (size_t t_idx = 0; t_idx < t_howmany; t_idx++)
{
// BIG thanks to doublemax on wxWidgets discussion forum for explaining that
// retrieving a sizer from within a sizer requires calling wxSizerItem::GetSizer...
// that is, you cannot directly cast from wxSizer::GetItem(t_idx).
wxSizerItem* szitem = FPatientSizer->GetItem(t_idx);
TDisplayDataSizer* t_display = static_cast<TDisplayDataSizer*>(szitem->GetSizer());
if (t_display)
{
TItemDef* t_item_def = t_display->GetItemDef();
if (t_item_def)
{
TDataItem* t_pat_item = patient->FindPatientItem(t_item_def->FieldNumber);
if (t_pat_item)
{
if (t_pat_item->ModifiedValue.empty())
{
t_display->SetValueText(t_pat_item->OriginalValue);
t_display->SetValueTextForegroundColour(true);
}
else
{
t_display->SetValueText(t_pat_item->ModifiedValue);
t_display->SetValueTextForegroundColour(false);
}
t_display->Show(true);
}
else
{
t_display->SetValueText("");
t_display->Show(show_all);
}
}
}
}
FPatientPage->Layout();
} // UpdatePatientControls
void TXMLDataForm::UpdateTumorControls(TPatient* patient, int tumor_ordinal, bool show_all /* == false */)
{
if (tumor_ordinal > 0 &&
tumor_ordinal <= (int)patient->FTumorItems.size())
{
FCurrentTumorOrdinal = tumor_ordinal; // the spin button handler needs to know
FTumorSpinButton->SetMax((int)patient->FTumorItems.size());
FTumorSpinButton->SetMin(1);
if (patient->FTumorItems.size() > 1)
{
wxString t_temp;
t_temp.Printf("Tumor #%d of %d", tumor_ordinal, patient->FTumorItems.size());
FNotebook->SetPageText(1, t_temp);
FSpinLabel->Enable(true);
FTumorSpinButton->Enable(true);
}
else
{
FNotebook->SetPageText(1, "Tumor");
FSpinLabel->Enable(false);
FTumorSpinButton->Enable(false);
}
size_t t_howmany = FTumorSizer->GetItemCount();
for (size_t t_idx = 0; t_idx < t_howmany; t_idx++)
{
wxSizerItem* szitem = FTumorSizer->GetItem(t_idx);
TDisplayDataSizer* t_display = static_cast<TDisplayDataSizer*>(szitem->GetSizer());
if (t_display)
{
TItemDef* t_item_def = t_display->GetItemDef();
if (t_item_def)
{
size_t t_jdx = tumor_ordinal -1;
TDataItem* t_pat_item = patient->FindTumorItem(t_jdx, t_item_def->FieldNumber);
if (t_pat_item)
{
if (t_pat_item->ModifiedValue.empty())
{
t_display->SetValueText(t_pat_item->OriginalValue);
t_display->SetValueTextForegroundColour(true);
}
else
{
t_display->SetValueText(t_pat_item->ModifiedValue);
t_display->SetValueTextForegroundColour(false);
}
t_display->Show(true);
}
else
{
t_display->SetValueText("");
t_display->Show(show_all);
}
}
}
} // for (t_idx...)
}
FTumorPage->Layout();
} // UpdateTumorControls
void TXMLDataForm::UpdateNaaccrDataControls(bool show_all /* == false */)
{
// This gets called only once; the NaaccrData page is always available,
// but does not change as Patient and Tumor data changes.
size_t t_howmany = FNaaccrDataSizer->GetItemCount();
for (size_t t_idx = 0; t_idx < t_howmany; t_idx++)
{
wxSizerItem* szitem = FNaaccrDataSizer->GetItem(t_idx);
TDisplayDataSizer* t_display = static_cast<TDisplayDataSizer*>(szitem->GetSizer());
if (t_display)
{
TItemDef* t_item_def = t_display->GetItemDef();
if (t_item_def)
{
TDataItem* t_data_item = FindNaaccrDataItem(t_item_def->FieldNumber);
if (t_data_item)
{
if (t_data_item->ModifiedValue.empty())
t_display->SetValueText(t_data_item->OriginalValue);
else
t_display->SetValueText(t_data_item->ModifiedValue);
t_display->Show(true);
}
else
{
t_display->SetValueText("");
t_display->Show(show_all);
}
}
}
}
FNaaccrDataPage->Layout();
} // UpdateNaaccrDataControls
TDataItem* TXMLDataForm::FindNaaccrDataItem(int FieldNumber)
{
TDataItem* t_data_item = NULL;
int t_low = 0,
t_high = FNaaccrDataItems.size() - 1,
t_mid;
while (t_low <= t_high)
{
t_mid = (t_low + t_high) / 2;
if (FNaaccrDataItems[t_mid]->ItemDef->FieldNumber == FieldNumber)
return FNaaccrDataItems[t_mid];
else if (FNaaccrDataItems[t_mid]->ItemDef->FieldNumber > FieldNumber)
t_high = t_mid - 1;
else
t_low = t_mid + 1;
}
return t_data_item;
} // FindNaaccrDataItem
wxPanel* TXMLDataForm::CreateDataControlPanel(TXMLDataForm *parent)
{
wxPanel* t_panel = new wxPanel(parent);
wxString t_options[] = { wxT("Show only those items with data values"),
wxT("Show all items, including those with blank values") };
FDataRadioBox = new wxRadioBox(t_panel, wxID_ANY, "How do you want to display data?",
wxDefaultPosition, wxDefaultSize, 2, t_options, 2, wxRA_SPECIFY_ROWS);
FDataRadioBox->Bind(wxEVT_RADIOBOX, &TXMLDataForm::OnDataRadioBox, this);
wxBoxSizer *t_sizer = new wxBoxSizer(wxVERTICAL);
t_sizer->Add(FDataRadioBox, 2, wxEXPAND);
wxPanel *t_spin_panel = new wxPanel(t_panel);
wxBoxSizer *t_spin_sizer = new wxBoxSizer(wxHORIZONTAL);
FSpinLabel = new wxStaticText(t_spin_panel, wxID_ANY, "Peruse the multiple tumors",
wxDefaultPosition, wxDefaultSize, 0L, "SpinLabel");
t_spin_sizer->Add(FSpinLabel);
t_spin_sizer->AddSpacer(8);
FTumorSpinButton =
new wxSpinButton(t_spin_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxSP_HORIZONTAL | wxSP_ARROW_KEYS);
//t_spin_sizer->Add(FTumorSpinButton, wxSizerFlags().Centre());
t_sizer->AddSpacer(8);
t_spin_sizer->Add(FTumorSpinButton, wxSizerFlags().Align(wxALIGN_TOP));
FTumorSpinButton->Bind(wxEVT_SPIN, &TXMLDataForm::OnSpinTumor, this);
t_spin_panel->SetSizerAndFit(t_spin_sizer);
t_sizer->Add(t_spin_panel, 1, wxEXPAND);
t_panel->SetSizer(t_sizer);
return t_panel;
} // CreateDataControlPanel
void TXMLDataForm::OnDataRadioBox(wxCommandEvent& event)
{
int t_event_sel = event.GetSelection();
TPatient* t_patient = (TPatient*)FPatientsListBox->GetClientObject(FPatientsListBox->GetSelection());
if (t_patient)
{
FShowAllPanels = (t_event_sel == 1);
UpdatePatientControls(t_patient, FShowAllPanels);
UpdateTumorControls(t_patient, 1, FShowAllPanels);
FTumorSpinButton->SetValue(1);
UpdateNaaccrDataControls(FShowAllPanels);
}
event.Skip();
} // OnDataRadioBox
void TXMLDataForm::OnSpinTumor(wxCommandEvent& event)
{
int t_value = FTumorSpinButton->GetValue();
TPatient* t_patient = (TPatient*)FPatientsListBox->GetClientObject(FPatientsListBox->GetSelection());
if (t_patient)
{
FCurrentTumorOrdinal = t_value;
UpdateTumorControls(t_patient, FCurrentTumorOrdinal, FShowAllPanels);
}
event.Skip();
} // OnSpinTumor
bool TXMLDataForm::RestoreOriginalValue(TItemDef *item_def, wxString& value)
{
// Called from TDisplayDataSizer pop-up menu item "Restore Original Value"
bool t_is_changed = false;
TPatient* t_patient = (TPatient*)FPatientsListBox->GetClientObject(FPatientsListBox->GetSelection());
if (t_patient)
{
TDataItem* t_data_item = t_patient->FindPatientItem(item_def->FieldNumber);
if (!t_data_item)
{
t_data_item = t_patient->FindTumorItem(FCurrentTumorOrdinal - 1, item_def->FieldNumber);
}
if (!t_data_item)
{
t_data_item = FindNaaccrDataItem(item_def->FieldNumber);
}
if (t_data_item)
{
if (t_data_item->OriginalValue.compare(value) != 0)
{
// the value was modified
t_data_item->ModifiedValue.assign("");
value.assign(t_data_item->OriginalValue);
t_is_changed = true;
// The patient item in the list box does not get updated
// for items on the NaaccrData page, so nothing to undo here.
if (item_def->ParentXMLElement.compare("NaaccrData") != 0)
{
TDataItem* t_found_modified = t_patient->FindFirstModifiedDataItem();
if (!t_found_modified)
{
t_patient->IsModified = false;
// undo the display of the patient item
int t_idx = FPatientsListBox->GetSelection();
FPatientsListBox->GetItem(t_idx)->SetTextColour(*wxBLACK);
FPatientsListBox->GetItem(t_idx)->SetFont(wxFont());
FPatientsListBox->RefreshItem(t_idx);
}
}
}
}
}
return t_is_changed;
} // RestoreOriginalValue
void TXMLDataForm::MoveSizerToTop(TDisplayDataSizer *display_sizer)
{
// We need to know which sizer contains the display_sizer
wxBoxSizer *t_parent_sizer = NULL;
TItemDef *t_item = display_sizer->GetItemDef();
if (t_item)
{
if (t_item->ParentXMLElement.compare("Patient") == 0)
t_parent_sizer = FPatientSizer;
else if (t_item->ParentXMLElement.compare("Tumor") == 0)
t_parent_sizer = FTumorSizer;
if (t_parent_sizer->Detach(display_sizer))
{
//t_parent_sizer->Insert(0, display_sizer, wxEXPAND | wxALL);
t_parent_sizer->Prepend(display_sizer, wxEXPAND | wxALL);
t_parent_sizer->Layout();
// We have to change the z-order, and that takes locating the
// MyTextCtrl on the next TDisplayDataSizer object
if (t_parent_sizer->GetItemCount() > 1)
{
//TDisplayDataSizer *next_sizer = (TDisplayDataSizer*) t_parent_sizer->GetItem(1);
// Violation: MoveBefore/AfterInTabOrder works only on sibling controls
//display_sizer->GetMyTextCtrl()->MoveBeforeInTabOrder(next_sizer->GetMyTextCtrl());
;
}
}
}
} // MoveSizerToTop()
void TXMLDataForm::UpdateOnExitTextCtrl(wxString current_value, TItemDef *item_def, bool& is_changed)
{
TPatient* t_patient = (TPatient*)FPatientsListBox->GetClientObject(FPatientsListBox->GetSelection());
if (t_patient)
{
TDataItem* t_data_item = t_patient->FindPatientItem(item_def->FieldNumber);
if (!t_data_item)
{
t_data_item = t_patient->FindTumorItem(FCurrentTumorOrdinal-1, item_def->FieldNumber);
}
if (!t_data_item)
{
t_data_item = FindNaaccrDataItem(item_def->FieldNumber);
}
if (t_data_item)
{
if (t_data_item->ModifiedValue.empty())
{
if (t_data_item->OriginalValue.compare(current_value) != 0)
{
is_changed = true;
t_data_item->ModifiedValue.assign(current_value);
// Note that this patient is now "modified"
t_patient->IsModified = true;
// so paint it red in the list box
int t_idx = FPatientsListBox->GetSelection();
FPatientsListBox->GetItem(t_idx)->SetTextColour(*wxRED);
FPatientsListBox->GetItem(t_idx)->SetFont(wxFont().Italic());
//FPatientsListBox->Update();
FPatientsListBox->RefreshItem(t_idx);
// And for that matter... this form is modified, too
this->FIsModified = true;
}
}
}
}
} // UpdateOnExitTextCtrl