]> git.saurik.com Git - wxWidgets.git/blame - utils/configtool/src/propeditor.cpp
Regenerate Makefile.in, configure and the VC++ project files after adding rcdefs.h
[wxWidgets.git] / utils / configtool / src / propeditor.cpp
CommitLineData
d7463f75
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: propeditor.cpp
be5a51fb 3// Purpose: wxWidgets Configuration Tool property editor
d7463f75
JS
4// Author: Julian Smart
5// Modified by:
6// Created: 2003-06-03
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
9// Licence:
10/////////////////////////////////////////////////////////////////////////////
11
d9ab621e
WS
12// For compilers that support precompilation, includes "wx/wx.h".
13#include "wx/wxprec.h"
d7463f75
JS
14
15#ifdef __BORLANDC__
16#pragma hdrstop
17#endif
18
d9ab621e
WS
19#ifndef WX_PRECOMP
20
d7463f75
JS
21#include "wx/grid.h"
22#include "wx/filedlg.h"
d9ab621e
WS
23
24#endif
25
26#include "wx/html/htmlwin.h"
d7463f75
JS
27#include "wx/tokenzr.h"
28#include "wx/valgen.h"
d7463f75
JS
29#include "propeditor.h"
30#include "symbols.h"
31#include "utils.h"
32#include "configtooldoc.h"
33#include "configitemselector.h"
d9ab621e 34
d7463f75
JS
35#include "bitmaps/ellipsis.xpm"
36
37
38/*!
39 * A container window for the property editor.
40 * and attribute editor.
41 */
42
43IMPLEMENT_CLASS(ctPropertyEditor, wxPanel)
44
45BEGIN_EVENT_TABLE(ctPropertyEditor, wxPanel)
46 EVT_BUTTON(ctID_ATTRIBUTE_EDITOR_EDIT_DETAILS, ctPropertyEditor::OnEditDetails)
47 EVT_GRID_SELECT_CELL(ctPropertyEditor::OnSelectCell)
48 EVT_GRID_CELL_CHANGE(ctPropertyEditor::OnChangeCell)
49 EVT_GRID_CELL_LEFT_DCLICK(ctPropertyEditor::OnDClickCell)
50 EVT_UPDATE_UI(ctID_ATTRIBUTE_EDITOR_EDIT_DETAILS, ctPropertyEditor::OnUpdateEditDetails)
51END_EVENT_TABLE()
52
53ctPropertyEditor::ctPropertyEditor(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style):
54 wxPanel(parent, id, pos, size, style)
55{
56 m_splitterWindow = NULL;
57 m_attributeEditorGrid = NULL;
58 m_propertyDescriptionWindow = NULL;
59 m_elementTitleTextCtrl = NULL;
60
61 CreateControls(this);
62}
63
d7463f75
JS
64void ctPropertyEditor::CreateControls(wxWindow* parent)
65{
4fe30bce 66 m_elementTitleTextCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY);
d7463f75
JS
67 wxBitmap detailsIcon(ellipsis_xpm);
68
69 wxBoxSizer *item0 = new wxBoxSizer( wxVERTICAL );
70
71 wxBoxSizer *item1 = new wxBoxSizer( wxHORIZONTAL );
72
73 wxTextCtrl *item2 = m_elementTitleTextCtrl;
74 item1->Add( item2, 1, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 );
75
d9ab621e
WS
76 m_attributeEditorEditDetails = new wxButton( parent, ctID_ATTRIBUTE_EDITOR_EDIT_DETAILS, wxT("Edit..."));
77 item1->Add( m_attributeEditorEditDetails, 0, wxALIGN_CENTRE|wxRIGHT|wxTOP|wxBOTTOM, 5 );
d7463f75
JS
78
79 item0->Add( item1, 0, wxGROW|wxALIGN_CENTER_VERTICAL, 5 );
80
81 // TODO: find sash pos from last time
82 int sashPos = 100;
83
84 m_splitterWindow = new wxSplitterWindow(parent, ctID_PROPERTY_EDITOR_SPLITTER, wxDefaultPosition, wxSize(500, 400), wxSP_3DSASH|wxSP_FULLSASH/*|wxCLIP_CHILDREN*/ |wxBORDER_NONE|wxNO_FULL_REPAINT_ON_RESIZE);
85 m_splitterWindow->SetMinimumPaneSize(10);
86
87 m_propertyDescriptionWindow = new wxHtmlWindow(m_splitterWindow, ctID_ATTRIBUTE_EDITOR_DESCRIPTION, wxDefaultPosition, wxSize(200, 60), wxSUNKEN_BORDER);
88 m_propertyDescriptionWindow->SetBackgroundColour(ctDESCRIPTION_BACKGROUND_COLOUR);
89 m_propertyDescriptionWindow->SetBorders(4);
90 m_attributeEditorGrid = new ctPropertyEditorGrid(m_splitterWindow, ctID_ATTRIBUTE_EDITOR_GRID , wxPoint(0, 0), wxSize(200, 100), wxBORDER_SUNKEN | wxWANTS_CHARS);
91
92 m_splitterWindow->SplitHorizontally(m_propertyDescriptionWindow, m_attributeEditorGrid, sashPos);
93
94 // TODO: show or hide description window
95// if (some-setting)
4fe30bce 96// ShowDescriptionWindow(false);
d7463f75
JS
97
98 item0->Add( m_splitterWindow, 1, wxGROW|wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxBOTTOM, 5 );
99
d7463f75
JS
100 this->SetSizer( item0 );
101
102 /// Add help text
103 m_elementTitleTextCtrl->SetHelpText(_("The title of the property being edited."));
d9ab621e
WS
104 m_attributeEditorEditDetails->SetHelpText(_("Click to use an appropriate editor for the selected property (if any)."));
105 m_attributeEditorGrid->SetHelpText(_("Shows the properties of the selected item."));
106 m_propertyDescriptionWindow->SetHelpText(_("Shows a description of the selected property, or a summary of the whole item."));
d7463f75
JS
107
108 /// Set up the grid to display properties
109 m_attributeEditorGrid->RegisterDataType(ctGRID_VALUE_STRING,
110 new wxGridCellStringRenderer,
111 new ctGridCellTextEditor);
112
113 m_attributeEditorGrid->CreateGrid( 0, 2, wxGrid::wxGridSelectRows );
114 m_attributeEditorGrid->SetRowLabelSize(0);
115 m_attributeEditorGrid->SetColLabelSize(0 /* 18 */);
116
117 wxArrayString columns;
118 columns.Add(_T("Name"));
119 columns.Add(_T("Value"));
120
121 m_attributeEditorGrid->SetColSize(0, 140);
122 m_attributeEditorGrid->SetColSize(1, 80);
123
124 m_attributeEditorGrid->SetColumnsToDisplay(columns);
125 m_attributeEditorGrid->DisplayLabels();
126
127 m_attributeEditorGrid->SetStretchableColumn(1);
128
129 m_attributeEditorGrid->SetDefaultCellBackgroundColour(ctCELL_BACKGROUND_COLOUR);
130
131 UpdateDescription();
132}
133
134/// Show/hide the description control
135void ctPropertyEditor::ShowDescriptionWindow(bool show)
136{
137 if (!show)
138 {
139 if (m_splitterWindow->IsSplit())
140 m_splitterWindow->Unsplit(m_propertyDescriptionWindow);
141 }
142 else
143 {
144 // TODO
145 int pos = 100;
4fe30bce 146 m_propertyDescriptionWindow->Show(true);
d7463f75
JS
147 if (!m_splitterWindow->IsSplit())
148 {
149 m_splitterWindow->SplitHorizontally(m_propertyDescriptionWindow, m_attributeEditorGrid, pos);
150 }
151 }
152}
153
154/// Clear grid editor
155void ctPropertyEditor::ClearEditor()
156{
157 m_attributeEditorGrid->ClearAttributes();
158 m_propertyDescriptionWindow->SetPage(WrapDescription(wxEmptyString));
dabbc6a5 159 m_elementTitleTextCtrl->SetValue(wxEmptyString);
d7463f75
JS
160}
161
162/// Handles detailed editing event.
69da0d99 163void ctPropertyEditor::OnEditDetails(wxCommandEvent& WXUNUSED(event))
d7463f75
JS
164{
165 wxWindow* parentFrame = this;
166 while (parentFrame && !parentFrame->IsKindOf(CLASSINFO(wxFrame)))
167 parentFrame = parentFrame->GetParent();
168
169 EditDetails(parentFrame);
170}
171
172/// Handles detailed editing update event.
173void ctPropertyEditor::OnUpdateEditDetails(wxUpdateUIEvent& event)
174{
175 event.Enable(CanEditDetails());
176}
177
178/// Can we edit the details of the selected property?
179bool ctPropertyEditor::CanEditDetails()
180{
181 if (!m_item)
4fe30bce 182 return false;
d7463f75
JS
183
184 int row;
185 ctProperty* prop = FindSelectedProperty(row);
677ded95 186 if (!prop || prop->GetEditorType().empty())
4fe30bce
WS
187 return false;
188 return true;
d7463f75
JS
189}
190
191/// Shows the item
192void ctPropertyEditor::ShowItem(ctConfigItem* item)
193{
194 if (m_attributeEditorGrid->IsCellEditControlEnabled())
195 m_attributeEditorGrid->SaveEditControlValue();
196
197 ClearEditor();
198 if (item)
199 {
200 m_item = item;
201
202 UpdateTitle();
203
204 m_attributeEditorGrid->AppendRows(m_item->GetProperties().GetCount());
205
d9ab621e 206 wxObjectList::compatibility_iterator node = m_item->GetProperties().GetList().GetFirst();
d7463f75
JS
207 int i = 0;
208 while (node)
209 {
210 ctProperty* prop = (ctProperty*) node->GetData();
211 DisplayProperty(i, prop);
212
213 i ++;
214 node = node->GetNext();
215 }
216 // Make sure scrollbars are up-to-date, etc.
217 wxSizeEvent event(m_attributeEditorGrid->GetSize(), m_attributeEditorGrid->GetId());
218 m_attributeEditorGrid->GetEventHandler()->ProcessEvent(event);
219
220 DisplayDefaultProperty();
221 }
222 else
223 {
224 m_item = NULL;
225 }
226}
227
228/// Determine background colour for this property.
229void ctPropertyEditor::DeterminePropertyColour(ctProperty* prop, wxColour& colour)
230{
231 if (prop->IsCustom())
232 colour = ctCUSTOM_CELL_BACKGROUND_COLOUR;
233 else
234 colour = ctCELL_BACKGROUND_COLOUR;
235}
236
237/// Update the title at the top of the property editor
238void ctPropertyEditor::UpdateTitle()
239{
240 if (m_item)
241 {
242 wxString name(m_item->GetTitle());
243 m_elementTitleTextCtrl->SetValue(name);
244 }
245}
246
247/// Updates the item display, assuming it was already displayed.
248void ctPropertyEditor::UpdateItem()
249{
250 if (m_attributeEditorGrid->IsCellEditControlEnabled())
251 m_attributeEditorGrid->SaveEditControlValue();
252 if (m_item)
253 {
254 UpdateTitle();
255
d9ab621e 256 wxObjectList::compatibility_iterator node = m_item->GetProperties().GetList().GetFirst();
d7463f75
JS
257 int i = 0;
258 while (node)
259 {
260 ctProperty* prop = (ctProperty*) node->GetData();
4fe30bce 261 DisplayProperty(i, prop, true);
d7463f75
JS
262
263 i ++;
264 node = node->GetNext();
265 }
266 // Make sure scrollbars are up-to-date, etc.
267 wxSizeEvent event(m_attributeEditorGrid->GetSize(), this->GetId());
268 m_attributeEditorGrid->GetEventHandler()->ProcessEvent(event);
269 }
270}
271
272/// Display attribute at given row
273bool ctPropertyEditor::DisplayProperty(int row, ctProperty* prop, bool valueOnly)
274{
275 wxColour backgroundColour;
276
277 DeterminePropertyColour(prop, backgroundColour);
278
279 if (!valueOnly)
280 {
281 m_attributeEditorGrid->SetCellBackgroundColour(row, 0, backgroundColour);
282 m_attributeEditorGrid->SetCellBackgroundColour(row, 1, backgroundColour);
283
284 m_attributeEditorGrid->SetCellValue(row, 0, prop->GetName());
285
286 m_attributeEditorGrid->SetReadOnly(row, 0);
287 // Set the alignment
288 m_attributeEditorGrid->SetCellAlignment(row, 1, wxALIGN_LEFT, wxALIGN_CENTER);
289 }
290
291 if (!m_item->CanEditProperty(prop->GetName()))
292 {
293 m_attributeEditorGrid->SetReadOnly(row, 1);
dabbc6a5 294
d7463f75
JS
295 wxColour col(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
296 m_attributeEditorGrid->SetCellTextColour(row, 1, col);
297 }
298 else
299 {
dabbc6a5 300 m_attributeEditorGrid->SetReadOnly(row, 1, false);
d7463f75
JS
301 m_attributeEditorGrid->SetCellTextColour(row, 1, * wxBLACK);
302 }
303
304 // Set the value
305 m_attributeEditorGrid->SetCellValue(row, 1, ctConvertToSingleText(prop->GetValue()));
306
307 if (valueOnly)
4fe30bce 308 return true;
d7463f75
JS
309
310 // Set the value type
311 if (prop->GetEditorType() == _T("choice"))
312 {
7db33cc3 313#if 0
d7463f75
JS
314 wxString* strArr = prop->GetChoices().GetStringArray();
315
316 m_attributeEditorGrid->SetCellEditor(row, 1,
317 new wxGridCellChoiceEditor(prop->GetChoices().GetCount(), strArr));
318
319 delete[] strArr;
7db33cc3
MB
320#endif
321 m_attributeEditorGrid->SetCellEditor(row, 1,
322 new wxGridCellChoiceEditor(prop->GetChoices()));
d7463f75
JS
323 }
324 else if (prop->GetEditorType() == _T("integer") || prop->GetVariant().GetType() == _T("long"))
325 {
326 m_attributeEditorGrid->SetCellEditor(row, 1,
327 new wxGridCellNumberEditor);
328 }
329 else if (prop->GetEditorType() == _T("float") || prop->GetVariant().GetType() == _T("double"))
330 {
331 m_attributeEditorGrid->SetCellEditor(row, 1,
332 new wxGridCellFloatEditor);
333 }
334 else if (prop->GetEditorType() == _T("bool") || prop->GetVariant().GetType() == _T("bool"))
335 {
336 m_attributeEditorGrid->SetCellValue(row, 1, prop->GetVariant().GetBool() ? _T("1") : _T("0"));
337 m_attributeEditorGrid->SetCellEditor(row, 1,
338 new wxGridCellBoolEditor);
339 m_attributeEditorGrid->SetCellRenderer(row, 1, new wxGridCellBoolRenderer);
340 }
341 else
342 {
343 m_attributeEditorGrid->SetCellEditor(row, 1,
344 new ctGridCellTextEditor);
345 }
dabbc6a5 346
4fe30bce 347 return true;
d7463f75
JS
348}
349
350/// Display attribute value
351bool ctPropertyEditor::DisplayProperty(ctProperty* prop)
352{
353 if (!m_item)
4fe30bce 354 return false;
d7463f75
JS
355
356 int index = m_item->GetProperties().GetList().IndexOf(prop);
4fe30bce 357 return DisplayProperty(index, prop, true);
d7463f75
JS
358}
359
360/// Display the default property
361bool ctPropertyEditor::DisplayDefaultProperty()
362{
363 if (!m_item)
4fe30bce 364 return false;
d7463f75
JS
365
366 wxString str = m_item->GetDefaultProperty();
367
368 ctProperty* prop = m_item->GetProperties().FindProperty(str);
369 if (prop)
370 {
371 int index = m_item->GetProperties().GetList().IndexOf(prop);
372 this->m_attributeEditorGrid->SelectRow(index);
373 this->m_attributeEditorGrid->SetGridCursor(index, 1);
374 }
4fe30bce 375 return true;
d7463f75
JS
376}
377
378/// Edit the default property
379bool ctPropertyEditor::EditDefaultProperty(ctConfigItem* item)
380{
381 wxString defaultPropertyName = item->GetDefaultProperty();
677ded95 382 if (!defaultPropertyName.empty())
d7463f75
JS
383 {
384 ctProperty* prop = item->GetProperties().FindProperty(defaultPropertyName);
385 if (prop)
386 {
387 int index = item->GetProperties().GetList().IndexOf(prop);
388 if (index >= 0)
389 {
390 this->m_attributeEditorGrid->SelectRow(index);
391 this->m_attributeEditorGrid->SetGridCursor(index, 1);
392 EditDetails(wxTheApp->GetTopWindow());
4fe30bce 393 return true;
d7463f75
JS
394 }
395 }
396
397 }
4fe30bce 398 return false;
d7463f75
JS
399}
400
401/// Find the selected property
402ctProperty* ctPropertyEditor::FindSelectedProperty(int& row)
403{
404 if (!m_item)
405 return NULL;
406
407 int selRow = m_attributeEditorGrid->GetCursorRow();
408 if (selRow > -1)
409 {
410 row = selRow;
dabbc6a5 411
d7463f75
JS
412 if (selRow < (int) m_item->GetProperties().GetCount())
413 {
414 ctProperty* prop = m_item->GetProperties().GetNth(selRow);
415 return prop;
416 }
417 }
418 return NULL;
419}
420
421/// Find the property
422ctProperty* ctPropertyEditor::FindProperty(int row)
423{
424 if (!m_item)
425 return NULL;
426
427 if (row > -1)
428 {
429 if (row < (int) m_item->GetProperties().GetCount())
430 {
431 ctProperty* prop = m_item->GetProperties().GetNth(row);
432 return prop;
433 }
434 }
435 return NULL;
436}
437
438/// Edit the details of this cell appropriately.
69da0d99 439bool ctPropertyEditor::EditDetails(wxWindow* WXUNUSED(parent))
d7463f75
JS
440{
441 if (CanEditDetails())
442 {
443 int row;
444 ctProperty* prop = FindSelectedProperty(row);
445 if (!prop)
4fe30bce 446 return false;
d7463f75
JS
447
448 wxString type(prop->GetEditorType());
449 wxString value = m_attributeEditorGrid->GetCellValue(row, 1);
450
451 if (type == _T("multiline"))
452 {
453 value = ctConvertToMultilineText(value);
454 wxString msg;
455 msg.Printf(wxT("Edit %s:"), (const wxChar*) prop->GetName());
456 ctMultiLineTextEditor dialog(wxTheApp->GetTopWindow(),
4fe30bce 457 wxID_ANY, wxT("Edit Text Property"), msg, value);
d7463f75
JS
458 if (dialog.ShowModal() == wxID_OK)
459 {
460 value = ctConvertToSingleText(dialog.GetText());
461 m_attributeEditorGrid->SetCellValue(row, 1, value);
462 ApplyCellValueToProperty(row, 1);
4fe30bce 463 return true;
d7463f75
JS
464 }
465 else
4fe30bce 466 return false;
d7463f75
JS
467 }
468 else if (type == _T("filename"))
469 {
470 wxString fullPath = value;
471 wxString defaultDir ;
472 wxString defaultFilename = wxFileNameFromPath(fullPath);
473
474 defaultDir = wxPathOnly(value);
475
476 wxString msg = wxT("Choose a filename");
477 wxFileDialog dialog(wxTheApp->GetTopWindow(),
478 msg, defaultDir, defaultFilename, wxT("*.*"));
479 if (dialog.ShowModal() == wxID_OK)
480 {
481 fullPath = dialog.GetPath();
482 value = fullPath;
483
484 m_attributeEditorGrid->SetCellValue(row, 1, value);
485 ApplyCellValueToProperty(row, 1);
4fe30bce 486 return true;
d7463f75
JS
487 }
488 else
4fe30bce 489 return false;
d7463f75
JS
490 }
491 else if (type == _T("configitems"))
492 {
493 wxArrayString items;
494 ctConfigItem::StringToArray(value, items);
495
496 ctConfigItemsSelector dialog(wxTheApp->GetTopWindow(),
4fe30bce 497 wxID_ANY, wxT("Select Configuration Items"));
d7463f75
JS
498 dialog.SetConfigList(items);
499 if (dialog.ShowModal() == wxID_OK)
500 {
501 wxString newValue;
502 items = dialog.GetConfigList();
503 ctConfigItem::ArrayToString(items, newValue);
504
505 m_attributeEditorGrid->SetCellValue(row, 1, newValue);
506 ApplyCellValueToProperty(row, 1);
4fe30bce 507 return true;
d7463f75
JS
508 }
509 else
4fe30bce 510 return false;
d7463f75
JS
511 }
512 }
513
4fe30bce 514 return false;
d7463f75
JS
515}
516
517/// Intercept selection event.
518void ctPropertyEditor::OnSelectCell(wxGridEvent& event)
519{
520 int row = event.GetRow();
521
522 UpdateDescription(row);
523
524 event.Skip();
525}
526
527/// Update the description
528void ctPropertyEditor::UpdateDescription(int row)
529{
530 if (row == -1)
531 {
532 row = m_attributeEditorGrid->GetCursorRow();
533 }
534 if (row == -1)
535 {
dabbc6a5 536 wxString str = WrapDescription(wxEmptyString);
d7463f75
JS
537 m_propertyDescriptionWindow->SetPage(str);
538 }
539 else
540 {
541 ctProperty* prop = FindProperty(row);
542 if (prop)
543 {
dabbc6a5 544 wxString str = WrapDescription(m_item->GetDescription(prop));
d7463f75
JS
545 m_propertyDescriptionWindow->SetPage(str);
546 }
547 }
548}
549
550/// Wraps a description string in HTML
551wxString ctPropertyEditor::WrapDescription(const wxString& s)
552{
553 /// Convert a colour to a 6-digit hex string
554 wxColour col = ctDESCRIPTION_BACKGROUND_COLOUR;
555 wxString colStr = apColourToHexString(col);
556 colStr = wxT("#") + colStr;
dabbc6a5 557
d7463f75
JS
558 wxString str;
559 str << _T("<HTML><BODY BGCOLOR=\"") << colStr << wxT("\"><FONT SIZE=-1>") ;
560 str << s;
561 str << _T("</FONT></BODY></HTML>");
dabbc6a5
DS
562
563 return str;
d7463f75
JS
564}
565
566/// Intercept cell data change event.
567void ctPropertyEditor::OnChangeCell(wxGridEvent& event)
568{
569 int row = event.GetRow();
570 int col = event.GetCol();
571
572 ApplyCellValueToProperty(row, col);
573}
574
575/// Double-click to show specialised editor.
69da0d99 576void ctPropertyEditor::OnDClickCell(wxGridEvent& WXUNUSED(event))
d7463f75
JS
577{
578 wxWindow* parentFrame = this;
579 while (parentFrame && !parentFrame->IsKindOf(CLASSINFO(wxFrame)))
580 parentFrame = parentFrame->GetParent();
581
582 EditDetails(parentFrame);
583}
584
585/// Apply the cell value to the property, and notify the
586/// item object.
587void ctPropertyEditor::ApplyCellValueToProperty(int row, int col)
588{
4fe30bce 589 static bool s_Applying = false;
d7463f75
JS
590
591 if (s_Applying)
592 return;
593
4fe30bce 594 s_Applying = true;
d7463f75
JS
595 if (col == 1 && m_item)
596 {
597 ctProperty* prop = m_item->GetProperties().GetNth(row);
598
599 wxString value = m_attributeEditorGrid->GetCellValue(row, col);
600 if (prop->GetEditorType() == wxT("multiline"))
601 value = ctConvertToMultilineText(value);
602
603 wxVariant variant = prop->GetVariant();
604
605 if (prop->GetVariant().GetType() == _T("bool"))
606 {
607 if (value == _T("1"))
4fe30bce 608 variant = true;
d7463f75 609 else
4fe30bce 610 variant = false;
d7463f75
JS
611 }
612 else if (prop->GetVariant().GetType() == _T("long"))
613 {
614 long l;
615 value.ToLong(& l);
616 variant = l;
617 }
618 else if (prop->GetVariant().GetType() == _T("double"))
619 {
620 double d;
621 value.ToDouble(& d);
622 variant = d;
623 }
624 else
625 {
626 variant = value;
627 }
628
629 ApplyPropertyValue(m_item, prop, variant);
630
631 if (prop->GetName() == _T("description"))
632 UpdateDescription(row);
633 }
4fe30bce 634 s_Applying = false;
d7463f75
JS
635}
636
637/// Apply the cell value to the property, and notify the
638/// item object.
639void ctPropertyEditor::ApplyPropertyValue(ctConfigItem* item, ctProperty* property, const wxVariant& variant)
640{
4fe30bce 641 static bool s_Applying = false;
d7463f75
JS
642
643 if (s_Applying)
644 return;
645
4fe30bce 646 s_Applying = true;
d7463f75
JS
647
648 // Save the old values
649 ctProperties* oldProperties = new ctProperties(item->GetProperties());
650
651 wxVariant oldValue = property->GetVariant();
652
653 // Apply the new value
654 property->GetVariant() = variant;
dabbc6a5 655 item->ApplyProperty(property, oldValue);
d7463f75 656 item->Modify();
dabbc6a5 657
d7463f75
JS
658 UpdateItem();
659
660 wxString menuLabel(_T("Change ") + property->GetName());
dabbc6a5 661
d7463f75
JS
662 // This won't do anything first time Do is applied,
663 // since we've already done the action for this property.
664 // But when we Undo or Redo, the changed properties will be applied.
665 item->GetDocument()->GetCommandProcessor()->Submit(
666 new ctConfigCommand(menuLabel, ctCMD_APPLY_PROPERTY,
4fe30bce 667 item, oldProperties, true));
d7463f75 668
4fe30bce 669 s_Applying = false;
d7463f75
JS
670}
671
672/*!
673 * Attribute editor grid
674 */
675
676IMPLEMENT_CLASS(ctPropertyEditorGrid, wxGrid)
677
678BEGIN_EVENT_TABLE(ctPropertyEditorGrid, wxGrid)
679 EVT_SIZE(ctPropertyEditorGrid::OnSize)
680END_EVENT_TABLE()
681
682ctPropertyEditorGrid::ctPropertyEditorGrid(wxWindow* parent, wxWindowID id,
683 const wxPoint& pos,
684 const wxSize& sz, long style):
685 wxGrid(parent, id, pos, sz, style)
686
687{
688 m_stretchableColumn = -1;
689}
690
691void ctPropertyEditorGrid::OnSize(wxSizeEvent& event)
692{
693 if (m_stretchableColumn != -1)
694 {
695 // This window's client size = the internal window's
696 // client size if it has no borders
697 wxSize sz = GetClientSize();
698
699 int totalSize = 0;
700 int i;
701 for (i = 0; i < GetNumberCols(); i ++)
702 {
703 if (i != m_stretchableColumn)
704 {
705 totalSize += GetColSize(i);
706 }
707 }
708
709 // Allow for grid lines
710 totalSize += 1;
711
712 int stretchSize = wxMax(5, sz.x - totalSize);
713 SetColSize(m_stretchableColumn, stretchSize);
714 }
715
716 event.Skip();
717}
718
719/// Use m_columnsToDisplay to set the label strings
720void ctPropertyEditorGrid::DisplayLabels()
721{
722 size_t i;
723 for (i = 0; i < m_columnsToDisplay.GetCount(); i++)
724 {
725 SetColLabelValue(i, m_columnsToDisplay[i]);
726 }
727}
728
729/// Clear attributes
730bool ctPropertyEditorGrid::ClearAttributes()
731{
732 if (GetNumberRows() > 0)
733 DeleteRows(0, GetNumberRows());
4fe30bce 734 return true;
d7463f75
JS
735}
736
737/*!
738 * Use a single-line text control.
739 */
740
741void ctGridCellTextEditor::Create(wxWindow* parent, wxWindowID id,
742 wxEvtHandler* evtHandler)
743{
744 m_control = new wxTextCtrl(parent, id, wxEmptyString,
745 wxDefaultPosition, wxDefaultSize
746 );
747
748 wxGridCellEditor::Create(parent, id, evtHandler);
749}
750
751
752/// Translate the value to one which can be edited in a single-line
753/// text control
754wxString ctConvertToSingleText(const wxString& value)
755{
756 wxString value1(value);
757 value1.Replace(wxT("\n"), wxT("\\n"));
758 value1.Replace(wxT("\t"), wxT("\\t"));
759 return value1;
760}
761
762/// Translate back to 'real' characters, i.e. newlines are real
763/// newlines.
764wxString ctConvertToMultilineText(const wxString& value)
765{
766 wxString value1(value);
767 value1.Replace(wxT("\\n"), wxT("\n"));
768 value1.Replace(wxT("\\t"), wxT("\t"));
769 return value1;
770}
771
772//----------------------------------------------------------------------------
773// ctMultiLineTextEditor
774//----------------------------------------------------------------------------
775
776BEGIN_EVENT_TABLE(ctMultiLineTextEditor, wxDialog)
777END_EVENT_TABLE()
778
779ctMultiLineTextEditor::ctMultiLineTextEditor( wxWindow *parent, wxWindowID id, const wxString &title,
780 const wxString& msg,
781 const wxString& value,
782 const wxPoint& pos,
783 const wxSize& size,
784 long style):
785 wxDialog(parent, id, title, pos, size, style)
786{
787 m_text = value;
788 AddControls(this, msg);
789 Centre();
790}
dabbc6a5 791
d7463f75
JS
792bool ctMultiLineTextEditor::AddControls(wxWindow* parent, const wxString& msg)
793{
794 wxBoxSizer *item0 = new wxBoxSizer( wxVERTICAL );
795
796 wxBoxSizer *item1 = new wxBoxSizer( wxVERTICAL );
797
798 wxStaticText *item2 = new wxStaticText( parent, wxID_STATIC, msg, wxDefaultPosition, wxDefaultSize, 0 );
799 item1->Add( item2, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT, 5 );
800
dabbc6a5 801 wxTextCtrl *item3 = new wxTextCtrl( parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(330,180), wxTE_MULTILINE|wxTE_RICH );
d7463f75
JS
802 item1->Add( item3, 1, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 );
803
804 wxBoxSizer *item4 = new wxBoxSizer( wxHORIZONTAL );
805
806 item4->Add( 5, 5, 1, wxALIGN_CENTRE|wxALL, 5 );
807
677ded95 808 wxButton *item5 = new wxButton( parent, wxID_OK);
d7463f75
JS
809 item4->Add( item5, 0, wxALIGN_CENTRE|wxALL, 5 );
810
677ded95 811 wxButton *item6 = new wxButton( parent, wxID_CANCEL);
d7463f75
JS
812 item4->Add( item6, 0, wxALIGN_CENTRE|wxALL, 5 );
813
814 item1->Add( item4, 0, wxGROW|wxALIGN_CENTER_VERTICAL, 5 );
815
816 item0->Add( item1, 1, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 );
817
818 item3->SetValue(m_text);
819 item3->SetValidator(wxGenericValidator(& m_text));
820
821
822 item3->SetFocus();
d9ab621e 823 item5->SetDefault();
d7463f75 824
d7463f75
JS
825 parent->SetSizer(item0);
826 item0->Fit(parent);
827
4fe30bce 828 return true;
d7463f75
JS
829}
830
831/*
832 * Special-purpose splitter window for changing sash look and
833 * also saving sash width
834 */
835
836BEGIN_EVENT_TABLE(ctSplitterWindow, wxSplitterWindow)
4fe30bce 837 EVT_SPLITTER_SASH_POS_CHANGED(wxID_ANY, ctSplitterWindow::OnChangeSash)
d7463f75
JS
838END_EVENT_TABLE()
839
840ctSplitterWindow::ctSplitterWindow(wxWindow* parent, wxWindowID id,
841 const wxPoint& pos, const wxSize& size, long style):
842 wxSplitterWindow(parent, id, pos, size, style)
843{
4fe30bce 844 m_updateSettings = false;
d7463f75
JS
845 m_position = 0;
846}
847
848void ctSplitterWindow::OnChangeSash(wxSplitterEvent& event)
849{
850 if (!m_updateSettings)
851 return;
852
853 m_position = event.GetSashPosition();
854}