[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [5370] Restore wxListView census manager from revision 530
From: |
Greg Chicares |
Subject: |
[lmi-commits] [5370] Restore wxListView census manager from revision 5304 under a new name |
Date: |
Sat, 21 Jan 2012 11:36:24 +0000 |
Revision: 5370
http://svn.sv.gnu.org/viewvc/?view=rev&root=lmi&revision=5370
Author: chicares
Date: 2012-01-21 11:36:23 +0000 (Sat, 21 Jan 2012)
Log Message:
-----------
Restore wxListView census manager from revision 5304 under a new name
Revision Links:
--------------
http://svn.sv.gnu.org/viewvc/?view=rev&root=lmi&revision=5304
Modified Paths:
--------------
lmi/trunk/ChangeLog
Added Paths:
-----------
lmi/trunk/census_view_old.cpp
lmi/trunk/census_view_old.hpp
Modified: lmi/trunk/ChangeLog
===================================================================
--- lmi/trunk/ChangeLog 2012-01-20 10:34:10 UTC (rev 5369)
+++ lmi/trunk/ChangeLog 2012-01-21 11:36:23 UTC (rev 5370)
@@ -29494,3 +29494,12 @@
ihs_irc7702.hpp
Remove unwanted arguments from Irc7702::Irc7702().
+20120121T1136Z <address@hidden> [615]
+
+ census_view_old.cpp
+ census_view_old.hpp
+Restore wxListView census manager from revision 5304 under a new name,
+updating only copyright, header name, and include guards for now. The
+goal is to release a stable system while wxDVC development continues,
+but without changes like those made 20111026T1342Z and 20111028T1211Z.
+
Added: lmi/trunk/census_view_old.cpp
===================================================================
--- lmi/trunk/census_view_old.cpp (rev 0)
+++ lmi/trunk/census_view_old.cpp 2012-01-21 11:36:23 UTC (rev 5370)
@@ -0,0 +1,1082 @@
+// Census manager.
+//
+// Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
2010, 2011, 2012 Gregory W. Chicares.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// 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, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// http://savannah.nongnu.org/projects/lmi
+// email: <address@hidden>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+// $Id$
+
+#ifdef __BORLANDC__
+# include "pchfile.hpp"
+# pragma hdrstop
+#endif // __BORLANDC__
+
+#include "census_view_old.hpp"
+
+#include "alert.hpp"
+#include "assert_lmi.hpp"
+#include "census_document.hpp"
+#include "configurable_settings.hpp"
+#include "contains.hpp"
+#include "default_view.hpp"
+#include "illustration_view.hpp"
+#include "illustrator.hpp"
+#include "input.hpp"
+#include "ledger.hpp"
+#include "ledger_text_formats.hpp"
+#include "miscellany.hpp" // is_ok_for_cctype()
+#include "mvc_controller.hpp"
+#include "path_utility.hpp"
+#include "safely_dereference_as.hpp"
+#include "wx_new.hpp"
+#include "wx_utility.hpp" // class ClipboardEx
+
+#include <wx/icon.h>
+#include <wx/listctrl.h>
+#include <wx/menu.h>
+#include <wx/msgdlg.h>
+#include <wx/xrc/xmlres.h>
+#include <wx/wupdlock.h>
+
+#include <algorithm>
+#include <cctype>
+#include <cstdio> // std::remove()
+#include <istream> // std::ws
+#include <iterator>
+#include <sstream>
+
+// TODO ?? Can't this macro be dispensed with?
+#define ID_LISTWINDOW 12345
+
+namespace
+{
+ // TODO ?? Add description and unit tests; consider relocating,
+ // and include "miscellany.hpp" only in ultimate location.
+ std::string insert_spaces_between_words(std::string const& s)
+ {
+ std::string r;
+ std::insert_iterator<std::string> j(r, r.begin());
+ std::string::const_iterator i;
+ for(i = s.begin(); i != s.end(); ++i)
+ {
+ if(is_ok_for_cctype(*i) && std::isupper(*i) && !r.empty())
+ {
+ *j++ = ' ';
+ }
+ *j++ = *i;
+ }
+ return r;
+ }
+}
+
+IMPLEMENT_DYNAMIC_CLASS(CensusView, ViewEx)
+
+BEGIN_EVENT_TABLE(CensusView, ViewEx)
+ EVT_CONTEXT_MENU( CensusView::UponRightClick)
+ EVT_MENU(XRCID("edit_cell" ),CensusView::UponEditCell )
+ EVT_MENU(XRCID("edit_class" ),CensusView::UponEditClass)
+ EVT_MENU(XRCID("edit_case" ),CensusView::UponEditCase )
+ EVT_MENU(XRCID("run_cell" ),CensusView::UponRunCell)
+// EVT_MENU(XRCID("run_class" ),CensusView::UponRunClass) //
SOMEDAY !! This may be useful for large cases.
+ EVT_MENU(XRCID("run_case" ),CensusView::UponRunCase)
+ EVT_MENU(XRCID("print_case" ),CensusView::UponPrintCase)
+ EVT_MENU(XRCID("print_case_to_disk" ),CensusView::UponPrintCaseToDisk)
+ EVT_MENU(XRCID("print_spreadsheet"
),CensusView::UponRunCaseToSpreadsheet)
+ EVT_MENU(XRCID("paste_census" ),CensusView::UponPasteCensus)
+ EVT_MENU(XRCID("add_cell" ),CensusView::UponAddCell)
+ EVT_MENU(XRCID("delete_cells" ),CensusView::UponDeleteCells)
+ EVT_MENU(XRCID("column_width_varying"
),CensusView::UponColumnWidthVarying)
+ EVT_MENU(XRCID("column_width_fixed" ),CensusView::UponColumnWidthFixed)
+
+// TODO ?? There has to be a better way than this.
+ EVT_UPDATE_UI(XRCID("edit_cell"
),CensusView::UponUpdateApplicable)
+ EVT_UPDATE_UI(XRCID("edit_class"
),CensusView::UponUpdateApplicable)
+ EVT_UPDATE_UI(XRCID("edit_case"
),CensusView::UponUpdateApplicable)
+ EVT_UPDATE_UI(XRCID("run_cell"
),CensusView::UponUpdateApplicable)
+ EVT_UPDATE_UI(XRCID("run_class"
),CensusView::UponUpdateApplicable)
+ EVT_UPDATE_UI(XRCID("run_case"
),CensusView::UponUpdateApplicable)
+ EVT_UPDATE_UI(XRCID("print_case"
),CensusView::UponUpdateApplicable)
+ EVT_UPDATE_UI(XRCID("print_case_to_disk"
),CensusView::UponUpdateApplicable)
+ EVT_UPDATE_UI(XRCID("print_spreadsheet"
),CensusView::UponUpdateApplicable)
+ EVT_UPDATE_UI(XRCID("paste_census"
),CensusView::UponUpdateApplicable)
+ EVT_UPDATE_UI(XRCID("add_cell"
),CensusView::UponUpdateApplicable)
+ EVT_UPDATE_UI(XRCID("delete_cells"
),CensusView::UponUpdateApplicable)
+ EVT_UPDATE_UI(XRCID("column_width_varying"
),CensusView::UponUpdateApplicable)
+ EVT_UPDATE_UI(XRCID("column_width_fixed"
),CensusView::UponUpdateApplicable)
+// TODO ?? Not label-edit.
+// EVT_LIST_BEGIN_LABEL_EDIT(ID_LISTWINDOW,CensusView::UponBeginLabelEdit)
+// Don't do this either--it's triggered by spacebar.
+// EVT_LIST_ITEM_ACTIVATED(ID_LISTWINDOW ,CensusView::UponBeginLabelEdit)
+END_EVENT_TABLE()
+
+CensusView::CensusView()
+ :ViewEx ()
+ ,all_changes_have_been_validated_(true)
+ ,composite_is_available_ (false)
+ ,was_cancelled_ (false)
+ ,list_window_ (0)
+{
+}
+
+CensusView::~CensusView()
+{
+}
+
+inline std::vector<Input>& CensusView::case_parms()
+{
+ return document().doc_.case_parms_;
+}
+
+inline std::vector<Input> const& CensusView::case_parms() const
+{
+ return document().doc_.case_parms_;
+}
+
+inline std::vector<Input>& CensusView::cell_parms()
+{
+ return document().doc_.cell_parms_;
+}
+
+inline std::vector<Input> const& CensusView::cell_parms() const
+{
+ return document().doc_.cell_parms_;
+}
+
+inline std::vector<Input>& CensusView::class_parms()
+{
+ return document().doc_.class_parms_;
+}
+
+inline std::vector<Input> const& CensusView::class_parms() const
+{
+ return document().doc_.class_parms_;
+}
+
+// TODO ?? Is this abstraction actually useful?
+std::string CensusView::cell_title(int index)
+{
+ std::string full_name(cell_parms()[index]["InsuredName"].str());
+ std::ostringstream title;
+ title << "Parameters for cell " << (1 + index);
+ if(!full_name.empty())
+ {
+ title << " (" << full_name << ")";
+ }
+ return title.str();
+}
+
+// TODO ?? Is this abstraction actually useful?
+std::string CensusView::class_title(int index)
+{
+ std::string class_name = class_name_from_cell_number(index);
+
+ std::ostringstream title;
+ title << "Default parameters for employee class ";
+ if(class_name.empty())
+ {
+ title << "[unnamed]";
+ }
+ else
+ {
+ title << "'" << class_name << "'";
+ }
+ return title.str();
+}
+
+// TODO ?? Is this abstraction actually useful?
+std::string CensusView::class_name_from_cell_number(int cell_number) const
+{
+ return cell_parms()[cell_number]["EmployeeClass"].str();
+}
+
+Input* CensusView::class_parms_from_class_name(std::string const& class_name)
+{
+ std::vector<Input>::iterator i = class_parms().begin();
+ while(i != class_parms().end())
+ {
+ // TODO ?? Add an any_member operator== instead.
+ if(class_name == (*i)["EmployeeClass"].str())
+ {
+ return &*i;
+ }
+ ++i;
+ }
+ return 0;
+}
+
+ // Determine which columns need to be displayed because their rows
+ // would not all be identical--i.e. because at least one cell or one
+ // class default differs from the case default wrt that column.
+bool CensusView::column_value_varies_across_cells
+ (std::string const& header
+ ,std::vector<Input> const& cells
+ ) const
+{
+ std::vector<Input>::const_iterator j;
+ for(j = cells.begin(); j != cells.end(); ++j)
+ {
+ if(!((*j)[header] == case_parms()[0][header]))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+wxWindow* CensusView::CreateChildWindow()
+{
+ list_window_ = new(wx) wxListView
+ (GetFrame()
+ ,ID_LISTWINDOW
+ );
+
+ // Show headers.
+ Update();
+ document().Modify(false);
+
+ status() << std::flush;
+
+ return list_window_;
+}
+
+CensusDocument& CensusView::document() const
+{
+ return safely_dereference_as<CensusDocument>(GetDocument());
+}
+
+ // Display exactly those columns whose rows aren't all identical. For
+ // this purpose, consider as "rows" the individual cells--and also the
+ // case and class defaults, even though they aren't displayed in rows.
+ // Reason: although the case and class defaults are hidden, they're
+ // still information--so if the user made them different from any cell
+ // wrt some column, we respect that conscious decision.
+//
+// Only DisplayAllVaryingData() uses the data member this assigns,
+// so move the logic into that function (if that remains true).
+//
+void CensusView::identify_varying_columns()
+{
+ headers_of_varying_parameters_.clear();
+ std::vector<std::string> const&
all_headers(case_parms()[0].member_names());
+ std::vector<std::string>::const_iterator i;
+ for(i = all_headers.begin(); i != all_headers.end(); ++i)
+ {
+ if
+ ( column_value_varies_across_cells(*i, class_parms())
+ || column_value_varies_across_cells(*i, cell_parms ())
+ )
+ {
+ headers_of_varying_parameters_.push_back(*i);
+ }
+ }
+}
+
+int CensusView::edit_parameters
+ (Input& lmi_input
+ ,std::string const& name
+ )
+{
+ if(is_invalid())
+ {
+ return false;
+ }
+
+ bool dirty = document().IsModified();
+
+ Input edited_lmi_input = lmi_input;
+ DefaultView const default_view;
+ MvcController controller(GetFrame(), edited_lmi_input, default_view);
+ controller.SetTitle(name);
+ int rc = controller.ShowModal();
+ if(wxID_OK == rc)
+ {
+ if(lmi_input != edited_lmi_input)
+ {
+ lmi_input = edited_lmi_input;
+ dirty = true;
+ }
+ document().Modify(dirty);
+ }
+ return rc;
+}
+
+bool CensusView::is_invalid()
+{
+ if(!all_changes_have_been_validated_)
+ {
+ int z = wxMessageBox
+ ("Cannot proceed without first validating changes."
+ ,"Validate changes now?"
+ ,wxYES_NO | wxICON_QUESTION
+ );
+ if(wxYES == z)
+ {
+ // TODO ?? Reserved for grid implementation.
+ }
+ }
+ return false;
+}
+
+// TODO ?? Reserved for a grid implementation.
+int CensusView::selected_column()
+{
+ return 0;
+}
+
+int CensusView::selected_row()
+{
+// TODO ?? Lossy type conversion: GetFirstSelected() returns a long
+// int, here and elsewhere in this file.
+ int row = list_window_->GetFirstSelected();
+ if(row < 0)
+ {
+ row = 0;
+// TODO ?? Reserve for grid implementation.
+// fatal_error() << "No row selected." << LMI_FLUSH;
+ }
+ if(static_cast<int>(cell_parms().size()) <= row)
+ {
+// TODO ?? OK if about to delete?
+// fatal_error() << "Invalid row selected." << LMI_FLUSH;
+ }
+ return row;
+}
+
+// Make a vector of all class names used by any individual, from
+// scratch; and update the vector of class default parameters,
+// adding any new classes, and purging any that are no longer in use
+// by any cell.
+void CensusView::update_class_names()
+{
+ // Extract names and add them even if they might be duplicates.
+ std::vector<std::string> all_class_names;
+
+ for
+ (std::vector<Input>::iterator i = cell_parms().begin()
+ ;i != cell_parms().end()
+ ;++i
+ )
+ {
+ all_class_names.push_back((*i)["EmployeeClass"].str());
+ }
+
+ std::vector<std::string> unique_class_names;
+
+ std::insert_iterator<std::vector<std::string> > iin
+ (unique_class_names
+ ,unique_class_names.begin()
+ );
+ std::sort(all_class_names.begin(), all_class_names.end());
+ std::unique_copy(all_class_names.begin(), all_class_names.end(), iin);
+
+// TODO ?? need parms for each?
+// if find name in class array
+// OK
+// else
+// create: copy from first matching individual
+// TODO ?? and if unmatching element in class array: delete it?
+
+ // Rebuild vector of class parameters so that it contains
+ // an element for each class in use.
+ std::vector<Input> rebuilt_class_parms;
+ std::vector<std::string>::iterator n = unique_class_names.begin();
+ while(n != unique_class_names.end())
+ {
+ Input* parms = class_parms_from_class_name(*n);
+ if(0 != parms)
+ {
+ // If we already have default parameters for the class,
+ // insert them into the rebuilt vector.
+ rebuilt_class_parms.push_back(*parms);
+ }
+ else
+ {
+ // If we do not already have default parameters for the class,
+ // find the first individual that belongs to the class and
+ // insert its parameters into the rebuilt vector.
+ std::vector<Input>::const_iterator j = cell_parms().begin();
+ bool found = false;
+ // TODO ?? There has to be a nicer way to do this with STL.
+ while(j != cell_parms().end())
+ {
+ if(*n == (*j)["EmployeeClass"].str())
+ {
+ rebuilt_class_parms.push_back(*j);
+ found = true;
+ break;
+ }
+ ++j;
+ }
+ // It should not be possible for no cell to be found in the class.
+ if(!found)
+ {
+ fatal_error()
+ << "Cannot find any cell in class "
+ << "'" << *n << "'."
+ << LMI_FLUSH
+ ;
+ }
+ }
+ ++n;
+ }
+
+ // Replace the vector of class parameters with the one we rebuilt.
+ class_parms().clear();
+ std::insert_iterator<std::vector<Input> > iip(class_parms(),
class_parms().begin());
+ std::copy(rebuilt_class_parms.begin(), rebuilt_class_parms.end(), iip);
+}
+
+/// Ascertain differences between old and new parameters and apply
+/// each such difference to other cells:
+/// if 'for_this_class_only' is specified, to all cells in the
+/// employee class of the old parameters;
+/// otherwise, to all cells in the entire census.
+
+void CensusView::apply_changes
+ (Input const& new_parms
+ ,Input const& old_parms
+ ,bool for_this_class_only
+ )
+{
+ // Case or class default parameters were edited and changed.
+ // Compare the default parameters before and after editing;
+ // for every parameter that was changed, assign the new value
+ // to all applicable cells, i.e.
+ // if case defaults changed: all cells and all class defaults;
+ // if class defaults changed: all cells in the class.
+
+ // TODO ?? temp string for new value, eeclass?
+ // TODO ?? combine class and indv vectors for case changes?
+
+ std::vector<std::string> headers_of_changed_parameters;
+ std::vector<std::string> const&
all_headers(case_parms()[0].member_names());
+ std::vector<std::string>::const_iterator i;
+ for
+ (i = all_headers.begin()
+ ;i != all_headers.end ()
+ ;++i
+ )
+ {
+ if(!(old_parms[*i] == new_parms[*i]))
+ {
+ headers_of_changed_parameters.push_back(*i);
+ }
+ }
+ for
+ (i = headers_of_changed_parameters.begin()
+ ;i != headers_of_changed_parameters.end ()
+ ;++i
+ )
+ {
+ if(!for_this_class_only)
+ {
+ std::vector<Input>::iterator j;
+ for
+ (j = class_parms().begin()
+ ;j != class_parms().end ()
+ ;++j
+ )
+ {
+ (*j)[*i] = new_parms[*i].str();
+ }
+ for
+ (j = cell_parms().begin()
+ ;j != cell_parms().end ()
+ ;++j
+ )
+ {
+ (*j)[*i] = new_parms[*i].str();
+ }
+ }
+ else
+ {
+ std::vector<Input>::iterator j;
+ for
+ (j = cell_parms().begin()
+ ;j != cell_parms().end ()
+ ;++j
+ )
+ {
+ if((*j)["EmployeeClass"] == new_parms["EmployeeClass"])
+ {
+ (*j)[*i] = new_parms[*i].str();
+ }
+ }
+ }
+ }
+
+ // Probably this should be factored out into a member function
+ // that's called elsewhere too--e.g., when a cell is read from
+ // file, or when a census is pasted. For this to work fully as
+ // desired, however, the DATABASE !! must be changed. Today,
+ // it caches exactly one product, and its cache-invalidation
+ // discipline isn't sufficiently strict. For now, applying the
+ // present technique elsewhere might well exacerbate crosstalk
+ // in a census that comprises more than one product.
+ std::vector<Input>::iterator j;
+ for(j = class_parms().begin(); j != class_parms().end(); ++j)
+ {
+ j->Reconcile();
+ }
+ for(j = cell_parms() .begin(); j != cell_parms() .end(); ++j)
+ {
+ j->Reconcile();
+ }
+ composite_is_available_ = false;
+}
+
+void CensusView::DisplayAllVaryingData()
+{
+ // Column zero (cell serial number) is always shown.
+ list_window_->InsertColumn(0, "Cell");
+ for(unsigned int column = 0; column <
headers_of_varying_parameters_.size(); ++column)
+ {
+ list_window_->InsertColumn
+ (1 + column
+
,insert_spaces_between_words(headers_of_varying_parameters_[column])
+ );
+ }
+ for(unsigned int row = 0; row < cell_parms().size(); ++row)
+ {
+ list_window_->InsertItem
+ (row
+ ,value_cast<std::string>(row)
+ ,0
+ );
+ // TODO ?? Necessary? Move to subfunction?
+// long index = ?
+// list_window_->SetItemData(index, row);
+
+ list_window_->SetItem(row, 0, value_cast<std::string>(1 + row));
+
+ for(unsigned int column = 0; column <
headers_of_varying_parameters_.size(); ++column)
+ {
+ std::string s =
cell_parms()[row][headers_of_varying_parameters_[column]].str();
+ list_window_->SetItem(row, 1 + column, s);
+ }
+ }
+}
+
+wxIcon CensusView::Icon() const
+{
+ return IconFromXmlResource("census_view_icon");
+}
+
+wxMenuBar* CensusView::MenuBar() const
+{
+ return MenuBarFromXmlResource("census_view_menu");
+}
+
+///* TODO expunge?
+// Double-click handler.
+// Factor out code: exact duplicate of CensusView::UponEditCell().
+void CensusView::UponBeginLabelEdit(wxListEvent& event)
+{
+ int cell_number = selected_row();
+ Input& original_parms = cell_parms()[cell_number];
+ Input temp_parms(original_parms);
+
+ if(wxID_OK != edit_parameters(temp_parms, cell_title(cell_number)))
+ {
+ return;
+ }
+
+ // TODO ?? Wouldn't it be better just to have edit_parameters()
+ // say whether it changed anything?
+ if(temp_parms != original_parms)
+ {
+ original_parms = temp_parms;
+ UpdatePreservingSelection();
+ document().Modify(true);
+ }
+}
+//*/
+
+void CensusView::UponEditCell(wxCommandEvent&)
+{
+ int cell_number = selected_row();
+ Input& original_parms = cell_parms()[cell_number];
+ Input temp_parms(original_parms);
+
+ if(wxID_OK != edit_parameters(temp_parms, cell_title(cell_number)))
+ {
+ return;
+ }
+
+ // TODO ?? Wouldn't it be better just to have edit_parameters()
+ // say whether it changed anything?
+ if(temp_parms != original_parms)
+ {
+ original_parms = temp_parms;
+ UpdatePreservingSelection();
+ document().Modify(true);
+ }
+}
+
+void CensusView::UponEditClass(wxCommandEvent&)
+{
+ int cell_number = selected_row();
+ std::string class_name = class_name_from_cell_number(cell_number);
+ Input& original_parms = *class_parms_from_class_name(class_name);
+ Input temp_parms(original_parms);
+
+ if(wxID_OK != edit_parameters(temp_parms, class_title(cell_number)))
+ {
+ return;
+ }
+
+ if(!(temp_parms == original_parms))
+ {
+ int z = wxMessageBox
+ ("Apply all changes to every cell in this class?"
+ ,"Confirm changes"
+ ,wxYES_NO | wxICON_QUESTION
+ );
+ if(wxYES == z)
+ {
+ apply_changes(temp_parms, original_parms, true);
+ }
+ original_parms = temp_parms;
+ UpdatePreservingSelection();
+ document().Modify(true);
+ }
+}
+
+void CensusView::UponEditCase(wxCommandEvent&)
+{
+ Input& original_parms = case_parms()[0];
+ Input temp_parms(original_parms);
+ if(wxID_OK != edit_parameters(temp_parms, "Default parameters for case"))
+ {
+ return;
+ }
+
+ if(!(temp_parms == original_parms))
+ {
+ int z = wxMessageBox
+ ("Apply all changes to every cell?"
+ ,"Confirm changes"
+ ,wxYES_NO | wxICON_QUESTION
+ );
+ if(wxYES == z)
+ {
+ apply_changes(temp_parms, original_parms, false);
+ }
+ original_parms = temp_parms;
+ UpdatePreservingSelection();
+ document().Modify(true);
+ }
+}
+
+// Make each nonfrozen column wide enough to display its widest entry,
+// ignoring column headers.
+//
+// VZ note from sample program (is this true?):
+// "note that under MSW for SetColumnWidth() to work we need to create the
+// items with images initially even if we specify dummy image id"
+//
+// TODO ?? Offer both ways of autosizing.
+//
+void CensusView::UponColumnWidthVarying(wxCommandEvent&)
+{
+ wxWindowUpdateLocker u(list_window_);
+ for(int j = 0; j < list_window_->GetColumnCount(); ++j)
+ {
+// TODO ?? Pick one, and remove the other?
+// list_window_->SetColumnWidth(j, wxLIST_AUTOSIZE);
+ list_window_->SetColumnWidth(j, wxLIST_AUTOSIZE_USEHEADER);
+ }
+}
+
+// Shrink all nonfrozen columns to default width.
+void CensusView::UponColumnWidthFixed(wxCommandEvent&)
+{
+ wxWindowUpdateLocker u(list_window_);
+ for(int j = 0; j < list_window_->GetColumnCount(); ++j)
+ {
+ // WX !! Sad to hardcode '80', but that's the undocumented wx default.
+ // TODO ?? If it's a default, then why must it be specified?
+ list_window_->SetColumnWidth(j, 80);
+ }
+}
+
+void CensusView::UponRightClick(wxContextMenuEvent&)
+{
+ wxMenu* census_menu = wxXmlResource::Get()->LoadMenu("census_menu_ref");
+ LMI_ASSERT(census_menu);
+ list_window_->PopupMenu(census_menu);
+ delete census_menu;
+}
+
+void CensusView::UponUpdateApplicable(wxUpdateUIEvent& e)
+{
+ e.Enable(true);
+}
+
+// Update the spreadsheet display.
+// If a parameter was formerly the same for all cells but now differs due
+// to editing, then display its column for all cells.
+// If a column was previously displayed but is now the same for all cells
+// due to editing, then display it no longer.
+// Similarly, if an old employee class is no longer used, remove it; and
+// if a new one comes into use, display it.
+void CensusView::Update()
+{
+ wxWindowUpdateLocker u(list_window_);
+
+ list_window_->ClearAll();
+
+ update_class_names();
+ identify_varying_columns();
+ DisplayAllVaryingData();
+
+ // All displayed data is valid when this function ends.
+ all_changes_have_been_validated_ = true;
+}
+
+void CensusView::UpdatePreservingSelection()
+{
+ wxWindowUpdateLocker u(list_window_);
+
+ // Save active cell.
+ int selection = selected_row();
+ int top_row = list_window_->GetTopItem();
+// TODO ?? Reserve for grid implementation.
+// int c = selected_column();
+
+ Update();
+
+ // Restore active cell.
+ // TODO ?? Better would be to restore to previously active col and row
+ // as determined by col hdr and cell #.
+ //
+ // This is kind of nasty. There's no SetTopItem(). Maybe it can be
+ // faked by 'ensuring' that the last row is visible first.
+ selection = std::min(selection, list_window_->GetItemCount());
+ list_window_->Select(selection);
+ list_window_->EnsureVisible(list_window_->GetItemCount());
+ list_window_->EnsureVisible(top_row);
+ list_window_->EnsureVisible(selection);
+}
+
+void CensusView::UponPrintCase(wxCommandEvent&)
+{
+ DoAllCells(mce_emit_pdf_to_printer);
+}
+
+void CensusView::UponPrintCaseToDisk(wxCommandEvent&)
+{
+ DoAllCells(mce_emit_pdf_file);
+}
+
+void CensusView::UponRunCase(wxCommandEvent&)
+{
+ if(is_invalid())
+ {
+ return;
+ }
+
+ ViewComposite();
+}
+
+void CensusView::UponRunCell(wxCommandEvent&)
+{
+ if(is_invalid())
+ {
+ return;
+ }
+
+ int cell_number = selected_row();
+ ViewOneCell(cell_number);
+}
+
+void CensusView::ViewOneCell(int index)
+{
+ std::string const name(cell_parms()[index]["InsuredName"].str());
+ IllustrationView& illview = MakeNewIllustrationDocAndView
+ (document().GetDocumentManager()
+ ,serial_file_path(base_filename(), name, index, "ill").string().c_str()
+ );
+ illview.Run(&cell_parms()[index]);
+}
+
+void CensusView::ViewComposite()
+{
+ // Run all cells if necessary to (re)generate composite numbers.
+ if(!composite_is_available_)
+ {
+ if(!DoAllCells(mce_emit_nothing))
+ {
+ return;
+ }
+ }
+
+ if(!was_cancelled_)
+ {
+ std::string const name("composite");
+ IllustrationView& illview = MakeNewIllustrationDocAndView
+ (document().GetDocumentManager()
+ ,serial_file_path(base_filename(), name, -1,
"ill").string().c_str()
+ );
+
+ // This is necessary for the view to be able to print.
+ illview.SetLedger(composite_ledger_);
+
+ illview.DisplaySelectedValuesAsHtml();
+ }
+}
+
+bool CensusView::DoAllCells(mcenum_emission emission)
+{
+ assert_consistency(case_parms()[0], cell_parms()[0]);
+
+ illustrator z(emission);
+ if(!z(base_filename(), cell_parms()))
+ {
+ return false;
+ }
+
+ composite_ledger_ = z.principal_ledger();
+ return true;
+}
+
+void CensusView::UponAddCell(wxCommandEvent&)
+{
+ if(is_invalid())
+ {
+ return;
+ }
+
+ cell_parms().push_back(case_parms()[0]);
+ UpdatePreservingSelection();
+ document().Modify(true);
+}
+
+void CensusView::UponDeleteCells(wxCommandEvent&)
+{
+ if(is_invalid())
+ {
+ return;
+ }
+
+ unsigned int n_items = list_window_->GetItemCount();
+ unsigned int n_sel_items = list_window_->GetSelectedItemCount();
+
+ if(n_items == n_sel_items)
+ {
+ warning()
+ << "Cannot delete all cells. A census must always"
+ << " contain at least one cell."
+ << LMI_FLUSH
+ ;
+ return;
+ }
+
+ LMI_ASSERT(n_sel_items < n_items);
+
+ std::ostringstream oss;
+ oss
+ << "Irrevocably delete "
+ << n_sel_items
+ << " of "
+ << n_items
+ << " cells?"
+ ;
+ int z = wxMessageBox
+ (oss.str()
+ ,"Confirm deletion"
+ ,wxYES_NO | wxICON_QUESTION
+ );
+ if(wxYES != z)
+ {
+ return;
+ }
+
+ std::vector<unsigned int> erasures;
+ int index = list_window_->GetFirstSelected();
+ while(-1 != index)
+ {
+ erasures.push_back(index);
+ index = list_window_->GetNextSelected(index);
+ }
+
+ std::sort(erasures.begin(), erasures.end());
+
+ LMI_ASSERT(cell_parms().size() == n_items);
+
+ std::vector<Input> expurgated_cell_parms;
+ expurgated_cell_parms.reserve
+ (n_items - n_sel_items
+ );
+
+ for(unsigned int j = 0; j < cell_parms().size(); ++j)
+ {
+ if(!contains(erasures, j))
+ {
+ expurgated_cell_parms.push_back(cell_parms()[j]);
+ }
+ }
+ LMI_ASSERT(expurgated_cell_parms.size() == n_items - n_sel_items);
+
+// cell_parms().swap(expurgated_cell_parms); // TODO ?? Would this be
better?
+ cell_parms() = expurgated_cell_parms;
+
+ Update();
+ document().Modify(true);
+}
+
+// Print tab-delimited output to file loadable in spreadsheet programs.
+void CensusView::UponRunCaseToSpreadsheet(wxCommandEvent&)
+{
+ std::string spreadsheet_filename =
+ base_filename()
+ + configurable_settings::instance().spreadsheet_file_extension()
+ ;
+ std::remove(spreadsheet_filename.c_str());
+ DoAllCells(mce_emit_spreadsheet);
+}
+
+/// Paste a census from the clipboard.
+///
+/// See unit tests in Skeleton::UponTestPasting().
+///
+/// A newly-created census contains one default cell, which doesn't
+/// represent user input, so it is erased before pasting new cells
+/// from the clipboard. The clipboard contents are validated before
+/// this erasure, so the document is not changed if pasting failed.
+///
+/// But if the census contains any user input, it shouldn't be erased.
+/// User input is present if either the document has been modified
+/// (e.g., if the default cell in a new census has been changed) or
+/// the document was loaded from a file (even if it was saved with
+/// only an unmodified default cell, because the contents of any saved
+/// file are assumed to represent user intention). In this case,
+/// pasted data is appended to the cells that were already present.
+
+void CensusView::UponPasteCensus(wxCommandEvent&)
+{
+ std::string const census_data = ClipboardEx::GetText();
+
+ std::vector<std::string> headers;
+ std::vector<Input> cells;
+
+ std::istringstream iss_census(census_data);
+ std::string line;
+
+ // Get header line; parse into field names.
+ if(std::getline(iss_census, line, '\n'))
+ {
+ iss_census >> std::ws;
+
+ std::istringstream iss_line(line);
+ std::string token;
+
+ while(std::getline(iss_line, token, '\t'))
+ {
+ headers.push_back(token);
+ }
+ }
+ else
+ {
+ warning() << "Error pasting census data: no header line." << LMI_FLUSH;
+ return;
+ }
+
+ // Read each subsequent line into an input object representing one cell.
+ int current_line = 0;
+ while(std::getline(iss_census, line, '\n'))
+ {
+ ++current_line;
+
+ iss_census >> std::ws;
+
+ Input current_cell(case_parms()[0]);
+
+ std::istringstream iss_line(line);
+ std::string token;
+ std::vector<std::string> values;
+
+ while(std::getline(iss_line, token, '\t'))
+ {
+ static std::string const space(" ");
+ if(std::string::npos == token.find_first_not_of(space))
+ {
+ warning()
+ << "Line #" << current_line << ": "
+ << " (" << line << ") "
+ << "has a value that contains no non-blank characters. "
+ << "Last valid value, if any: " << values.back()
+ << LMI_FLUSH
+ ;
+// TODO ?? It would be better to use fatal_error() instead of
+// warning() followed by fatal_error() with a short string, but
+// apparently that can segfault with very long strings. Is there
+// a limit on exception size that should be tested here?
+ fatal_error() << "Invalid input." << LMI_FLUSH;
+ }
+ values.push_back(token);
+ }
+
+ if(values.size() != headers.size())
+ {
+ fatal_error()
+ << "Line #" << current_line << ": "
+ << " (" << line << ") "
+ << "should have one value per column. "
+ << "Number of values: " << values.size() << "; "
+ << "number expected: " << headers.size() << "."
+ << LMI_FLUSH
+ ;
+ }
+
+ for(unsigned int j = 0; j < headers.size(); ++j)
+ {
+ current_cell[headers[j]] = values[j];
+ }
+ current_cell.Reconcile();
+ current_cell.RealizeAllSequenceInput();
+ cells.push_back(current_cell);
+
+ status() << "Added cell number " << cells.size() << '.' << std::flush;
+ wxSafeYield();
+ }
+
+ if(0 == current_line)
+ {
+ warning() << "No cells to paste." << LMI_FLUSH;
+ return;
+ }
+
+ if(!document().IsModified() && !document().GetDocumentSaved())
+ {
+ cell_parms().clear();
+ class_parms().clear();
+ class_parms().push_back(case_parms()[0]);
+ }
+
+ std::back_insert_iterator<std::vector<Input> > iip(cell_parms());
+ std::copy(cells.begin(), cells.end(), iip);
+ document().Modify(true);
+ Update();
+ status() << std::flush;
+
+ LMI_ASSERT(!case_parms ().empty());
+ LMI_ASSERT(!cell_parms ().empty());
+ LMI_ASSERT(!class_parms().empty());
+}
+
Property changes on: lmi/trunk/census_view_old.cpp
___________________________________________________________________
Added: svn:keywords
+ Id
Added: lmi/trunk/census_view_old.hpp
===================================================================
--- lmi/trunk/census_view_old.hpp (rev 0)
+++ lmi/trunk/census_view_old.hpp 2012-01-21 11:36:23 UTC (rev 5370)
@@ -0,0 +1,147 @@
+// Census manager.
+//
+// Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Gregory
W. Chicares.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// 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, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// http://savannah.nongnu.org/projects/lmi
+// email: <address@hidden>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+// $Id$
+
+#ifndef census_view_old_hpp
+#define census_view_old_hpp
+
+#include "config.hpp"
+
+#include "view_ex.hpp"
+
+#include "input.hpp"
+#include "ledger.hpp"
+#include "mc_enum_type_enums.hpp" // enum mcenum_emission
+#include "obstruct_slicing.hpp"
+#include "uncopyable_lmi.hpp"
+
+#include <boost/shared_ptr.hpp>
+
+#include <wx/defs.h> // wx shared-library 'attributes'
+
+#include <string>
+#include <vector>
+
+class CensusDocument;
+class WXDLLIMPEXP_FWD_CORE wxListEvent;
+class WXDLLIMPEXP_FWD_CORE wxListView;
+
+class CensusView
+ : public ViewEx
+ , private lmi::uncopyable <CensusView>
+ ,virtual private obstruct_slicing<CensusView>
+{
+ friend class CensusDocument;
+
+ public:
+ CensusView();
+ virtual ~CensusView();
+
+ private:
+ void DisplayAllVaryingData();
+
+ CensusDocument& document() const;
+
+ // ViewEx required implementation.
+ virtual wxWindow* CreateChildWindow();
+ virtual wxIcon Icon() const;
+ virtual wxMenuBar* MenuBar() const;
+
+ void UponAddCell (wxCommandEvent&);
+ void UponBeginLabelEdit (wxListEvent&); // TODO ?? Expunge.
+ void UponDeleteCells (wxCommandEvent&);
+ void UponEditCell (wxCommandEvent&);
+ void UponEditClass (wxCommandEvent&);
+ void UponEditCase (wxCommandEvent&);
+ void UponColumnWidthVarying (wxCommandEvent&);
+ void UponColumnWidthFixed (wxCommandEvent&);
+ void UponPasteCensus (wxCommandEvent&);
+ void UponRightClick (wxContextMenuEvent&);
+ void UponPrintCase (wxCommandEvent&);
+ void UponPrintCaseToDisk (wxCommandEvent&);
+ void UponRunCell (wxCommandEvent&);
+ void UponRunCase (wxCommandEvent&);
+ void UponRunCaseToSpreadsheet (wxCommandEvent&);
+ void UponUpdateApplicable (wxUpdateUIEvent&);
+
+ bool DoAllCells(mcenum_emission);
+
+ void Update();
+ void UpdatePreservingSelection();
+ void ViewOneCell(int);
+ void ViewComposite();
+
+ void apply_changes
+ (Input const& new_parms
+ ,Input const& old_parms
+ ,bool for_this_class_only
+ );
+
+ std::vector<Input>& case_parms();
+ std::vector<Input> const& case_parms() const;
+ std::vector<Input>& cell_parms();
+ std::vector<Input> const& cell_parms() const;
+ std::vector<Input>& class_parms();
+ std::vector<Input> const& class_parms() const;
+
+ std::string cell_title(int);
+ std::string class_title(int);
+ std::string class_name_from_cell_number(int) const;
+ Input* class_parms_from_class_name(std::string const&);
+
+ bool column_value_varies_across_cells
+ (std::string const& header
+ ,std::vector<Input> const& cells
+ ) const;
+
+ int edit_parameters
+ (Input& parameters
+ ,std::string const& name
+ );
+
+ void identify_varying_columns();
+
+ bool is_invalid();
+
+ int selected_column();
+ int selected_row();
+
+ void update_class_names();
+
+ bool all_changes_have_been_validated_;
+
+ bool composite_is_available_;
+
+ boost::shared_ptr<Ledger const> composite_ledger_;
+
+ std::vector<std::string> headers_of_varying_parameters_;
+
+ bool was_cancelled_;
+
+ wxListView* list_window_;
+
+ DECLARE_DYNAMIC_CLASS(CensusView)
+ DECLARE_EVENT_TABLE()
+};
+
+#endif // census_view_old_hpp
+
Property changes on: lmi/trunk/census_view_old.hpp
___________________________________________________________________
Added: svn:keywords
+ Id
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [lmi-commits] [5370] Restore wxListView census manager from revision 5304 under a new name,
Greg Chicares <=