]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - tools/src/tools/configtool/standalone/wxwin/configitem.cpp
Cleanup CVS ipmorted branch
[karo-tx-redboot.git] / tools / src / tools / configtool / standalone / wxwin / configitem.cpp
1 //####COPYRIGHTBEGIN####
2 //
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
5 //
6 // This program is part of the eCos host tools.
7 //
8 // This program is free software; you can redistribute it and/or modify it
9 // under the terms of the GNU General Public License as published by the Free
10 // Software Foundation; either version 2 of the License, or (at your option)
11 // any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but WITHOUT
14 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16 // more details.
17 //
18 // You should have received a copy of the GNU General Public License along with
19 // this program; if not, write to the Free Software Foundation, Inc.,
20 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 //
22 // ----------------------------------------------------------------------------
23 //
24 //####COPYRIGHTEND####
25 // configitem.cpp :
26 //
27 //===========================================================================
28 //#####DESCRIPTIONBEGIN####
29 //
30 // Author(s):   julians
31 // Contact(s):  julians
32 // Date:        2000/09/01
33 // Version:     $Id: configitem.cpp,v 1.10 2001/04/30 17:12:32 julians Exp $
34 // Purpose:
35 // Description: Implementation file for the ConfigTool application class
36 // Requires:
37 // Provides:
38 // See also:
39 // Known bugs:
40 // Usage:
41 //
42 //####DESCRIPTIONEND####
43 //
44 //===========================================================================
45
46 // ============================================================================
47 // declarations
48 // ============================================================================
49
50 // ----------------------------------------------------------------------------
51 // headers
52 // ----------------------------------------------------------------------------
53 #ifdef __GNUG__
54     #pragma implementation "configitem.h"
55 #endif
56
57 // Includes other headers for precompiled compilation
58 #include "ecpch.h"
59
60 #ifdef __BORLANDC__
61     #pragma hdrstop
62 #endif
63
64 #include "wx/settings.h"
65 #include "wx/valgen.h"
66
67 #include "configitem.h"
68 #include "configtree.h"
69 #include "configtooldoc.h"
70 #include "configtoolview.h"
71 #include "ecutils.h"
72
73 IMPLEMENT_CLASS(ecConfigItem, wxObject)
74
75 /*
76  * ecConfigItem
77  * Represents a node in the configuration hierarchy.
78  * For every ecConfigItem, there is also an ecTreeItemData
79  * that points to it.
80  */
81
82 ecConfigItem::ecConfigItem(ecConfigItem* parent, const wxString& name, ecConfigType ctype,
83                            ecOptionFlavor flavor, ecOptionType otype,
84                            bool active, bool enabled, ecUIHint hint)
85 {
86     m_CdlItem = NULL;
87     m_name = name;
88     m_configType = ctype;
89     m_optionType = otype;
90     m_optionFlavor = flavor;
91     m_enabled = enabled;
92     m_active = active;
93     m_parent = parent;
94     m_hint = hint;
95     m_treeItem = wxTreeItemId();
96
97     switch (otype)
98     {
99     case ecDouble:
100         {
101             m_value = 0.0;
102             break;
103         }
104     case ecString:
105     case ecEnumerated:
106         {
107             m_value = wxT("");
108             break;
109         }
110     case ecLong:
111         {
112             m_value = (long) 0;
113             break;
114         }
115     case ecBool:
116         {
117             m_value = (bool) FALSE;
118             break;
119         }
120     default:
121         {
122             break;
123         }
124     }
125 }
126
127 ecConfigItem::ecConfigItem(ecConfigItem* parent, CdlUserVisible vitem)
128 {
129     m_name = wxT("UNNAMED");
130     m_configType = ecConfigTypeNone;
131     m_optionType = ecOptionTypeNone;
132     m_optionFlavor = ecFlavorNone;
133     m_enabled = FALSE;
134     m_active = FALSE;
135     m_parent = parent;
136     m_CdlItem = vitem;
137     m_hint = ecHintNone;
138     m_treeItem = wxTreeItemId();
139
140     ecConfigTreeCtrl* treeCtrl = wxGetApp().GetTreeCtrl();
141     m_treeItem = treeCtrl->AppendItem(parent->GetTreeItem(), m_name, -1, -1, new ecTreeItemData(this));
142
143     ConvertFromCdl();
144     UpdateTreeItem(* treeCtrl);
145 }
146
147 ecConfigItem::~ecConfigItem()
148 {
149     // Make sure that the tree item no longer references this object
150     ecConfigTreeCtrl* treeCtrl = wxGetApp().GetTreeCtrl();
151     if (m_treeItem && treeCtrl)
152     {
153         ecTreeItemData* data = (ecTreeItemData*) treeCtrl->GetItemData(m_treeItem);
154         data->SetConfigItem(NULL);
155     }
156
157     ecConfigToolDoc* doc = wxGetApp().GetConfigToolDoc();
158     if (doc)
159     {
160         doc->GetItems().DeleteObject(this);
161     }
162 }
163
164 // Convert from Cdl to internal representation
165 bool ecConfigItem::ConvertFromCdl()
166 {
167     if (!GetCdlItem())
168         return FALSE;
169
170     m_name = GetCdlItem()->get_display ().c_str ();
171     m_macro = GetCdlItem()->get_name().c_str();
172     m_strDescr = ecUtils::StripExtraWhitespace (wxString (GetCdlItem()->get_description ().c_str ()));
173
174
175     // FIXME: re-implement using CdlValuableBody::get_widget_hint()
176     // (comment from original MFC configtool)
177
178     if (IsPackage())
179     {
180         // If a package item, display the package version string
181         m_optionType = ecString; 
182         m_configType = ecPackage;
183         m_optionFlavor = ecFlavorNone;
184     }
185     else
186     {
187         const CdlValuable valuable = dynamic_cast<CdlValuable> (GetCdlItem());
188         switch (valuable->get_flavor ()){
189         case CdlValueFlavor_None:
190             m_optionFlavor = ecFlavorNone;
191             m_optionType=ecOptionTypeNone; //??? Shouldn't it be ecBool for CdlValueFlavor_Bool?
192             m_configType = ecContainer;
193             break;
194         case CdlValueFlavor_Bool:
195             m_optionFlavor = ecFlavorBool;
196             m_optionType=ecOptionTypeNone; //??? Shouldn't it be ecBool for CdlValueFlavor_Bool?
197             m_configType = ecOption;
198             m_hint = (HasRadio() ? ecHintRadio : ecHintCheck);
199             break;
200         case CdlValueFlavor_Data:
201         case CdlValueFlavor_BoolData:
202
203             m_optionFlavor = (valuable->get_flavor() == CdlValueFlavor_Data ? ecFlavorData : ecFlavorBoolData);
204             m_configType = ecOption;
205             m_hint = (HasRadio() ? ecHintRadio : ecHintCheck);
206
207             if (! valuable->has_legal_values ()) {
208                 m_optionType=ecString;
209             } else if (0 == valuable->get_legal_values ()->ranges.size ()) {
210                 m_optionType=ecEnumerated;
211             } else {
212                 CdlListValue list_value;
213                 CdlEvalContext context (NULL, valuable, valuable->get_property (CdlPropertyId_LegalValues));
214                 valuable->get_legal_values ()->eval (context, list_value);
215                 m_optionType=list_value.get_double_ranges ().size () ? ecDouble : ecLong;
216             }
217             break;
218         default:
219             wxASSERT (0); // specified flavor not supported
220             break;
221         }
222     }  
223
224     m_active = IsActive();
225     m_enabled = IsEnabled();
226
227     return TRUE;
228 }
229
230 wxString ecConfigItem::GetItemNameOrMacro() const
231 {
232     return (wxGetApp().GetSettings().m_showMacroNames && !GetMacro().IsEmpty() ? GetMacro() : GetName());
233 }
234
235 // Sets the text and icon for this item
236 bool ecConfigItem::UpdateTreeItem(ecConfigTreeCtrl& treeCtrl)
237 {
238     treeCtrl.SetItemText(m_treeItem, m_name);
239
240     static wxColour normalColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT);
241     static wxColour disabledColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_GRAYTEXT);
242
243     treeCtrl.SetItemTextColour(m_treeItem, GetActive() ? normalColour : disabledColour);
244     
245
246     // Find which icon state we're in so we can get the appropriate icon id
247     int iconState = 0;
248     wxString iconName;
249
250     switch (GetConfigType())
251     {
252         case ecContainer:
253             {
254                 iconName = _("Container");
255                 iconState = 0;
256                 break;
257             }
258         case ecPackage:
259             {
260                 iconName = _("Package");
261                 iconState = 0;
262                 break;
263             }
264         case ecComponent:
265             {
266                 iconName = _("??");
267                 iconState = 0;
268                 break;
269             }
270         case ecOption:
271             {
272                 if (GetOptionFlavor() == ecFlavorData)
273                 {
274                     switch (GetOptionType())
275                     {
276                     case ecDouble:
277                     case ecLong:
278                         {
279                             iconName = _("Integer");
280                             iconState = 0;
281                             break;
282                         }
283                     case ecEnumerated:
284                         {
285                             iconName = _("Enumerated");
286                             iconState = 0;
287                             break;
288                         }
289                     case ecString:
290                         {
291                             iconName = _("Text");
292                             iconState = 0;
293                             break;
294                         }
295                     // ??? Actually I don't think there's such a think as ecBool type, only enabled/disabled
296                     case ecBool:
297                         {
298                             if (GetUIHint() == ecHintCheck)
299                                 iconName = _("Checkbox");
300                             else
301                                 iconName = _("Radiobox");
302                             iconState = (m_value.GetBool() ? 0 : 1);
303                             break;
304                         }
305                     default:
306                         {
307                             break;
308                         }
309                     }
310                 }
311                 if (GetOptionFlavor() == ecFlavorBoolData || GetOptionFlavor() == ecFlavorBool)
312                 {
313                     if (GetUIHint() == ecHintCheck)
314                         iconName = _("Checkbox");
315                     else
316                         iconName = _("Radiobox");
317                     iconState = (m_enabled ? 0 : 1);
318                 }
319                 break;
320             }
321         default:
322             {
323                 break;
324             }
325     }
326
327     if (!iconName.IsEmpty())
328     {
329         int iconId = treeCtrl.GetIconDB().GetIconId(iconName, iconState, GetActive());
330         treeCtrl.SetItemImage(m_treeItem, iconId, wxTreeItemIcon_Normal);
331         treeCtrl.SetItemImage(m_treeItem, iconId, wxTreeItemIcon_Selected);
332     }
333
334     return TRUE;
335 }
336
337 // Handle a left click on the icon: e.g. (un)check the option
338 // In the old MFC tool, this was handled by CControlView::Bump
339 void ecConfigItem::OnIconLeftDown(ecConfigTreeCtrl& treeCtrl)
340 {
341     if (GetConfigType() != ecOption)
342         return;
343
344     switch (GetOptionFlavor())
345     {
346     case ecFlavorBool:
347     case ecFlavorBoolData:
348         {
349             if (GetActive())
350             {
351                 wxGetApp().GetConfigToolDoc()->SetEnabled(*this, !m_enabled);
352             }
353             break;
354         }
355     case ecFlavorData:
356         {
357             if (GetActive())
358             {
359                 switch (GetOptionType())
360                 {
361                 case ecLong:
362                     {
363                         int nInc = 1;
364
365                         long nOldValue = Value();
366                         if(nInc==1 && nOldValue == long(-1))
367                         {
368                             nOldValue=0;
369                         } else if(nInc==-1 && nOldValue==0){
370                             nOldValue = long(-1);
371                         } else {
372                             nOldValue+=nInc;
373                         }
374                         wxGetApp().GetConfigToolDoc()->SetValue(*this, nOldValue);
375                         break;
376                     }
377                 case ecEnumerated:
378                     {
379                         int nInc = 1;
380
381                         wxArrayString arEnum;
382                         EvalEnumStrings (arEnum); // calculate legal values just in time
383                         if (0 == arEnum.GetCount()) // if no legal values...
384                             break;           // ...do nothing
385                         int nIndex = -1;
386                         const wxString strCurrent = StringValue ();
387                         int nEnum;
388                         for (nEnum = 0; (nEnum < arEnum.GetCount()) && (nIndex == -1); nEnum++)
389                             if (0 == arEnum[nEnum].CompareTo (strCurrent))
390                                 nIndex = nEnum; // the index of the current value
391                             
392                             if (nIndex != -1) // if the current value is still legal
393                                 nIndex += (nInc < 0 ? -1 : 1); // increment/decrement the index
394                             else
395                                 nIndex = 0; // otherwise select the first enum
396                             
397                             if (nIndex < 0) // if the new index is negative
398                                 nIndex = arEnum.GetCount()-1; // make it positive
399
400                             wxGetApp().GetConfigToolDoc()->SetValue(*this, arEnum[nIndex % arEnum.GetCount()]);
401                             break;
402                     }
403                 default:
404                     {
405                         break;
406                     }
407                 }
408             }
409             break;   
410         }
411     default:
412         {
413             break;
414         }
415     }
416
417 }
418
419 // Gets the value to display (often an empty string)
420 wxString ecConfigItem::GetDisplayValue() const
421 {
422     wxString str;
423     switch(GetOptionType())
424     {
425     case ecEnumerated:
426     case ecLong:
427     case ecDouble:
428     case ecString:
429         {
430             if (GetCdlValuable())
431                 str = StringValue();
432         }
433         break;
434     default:
435         break;
436     }
437     return str;
438 #if 0
439     switch (GetConfigType())
440     {
441         case ecComponent:
442         case ecContainer:
443             {
444                 return wxEmptyString;
445                 break;
446             }
447         case ecPackage:
448             {
449                 return m_value.GetString();
450                 break;
451             }
452         case ecOption:
453             {
454                 switch (GetOptionType())
455                 {
456                     case ecDouble:
457                         {
458                             wxString val;
459                             val.Printf("%.4lf", (double) m_value.GetDouble());
460                             return val;
461                         }
462                     case ecLong:
463                         {
464                             wxString val;
465                             val.Printf("%.ld", (long) m_value.GetLong());
466                             return val;
467                             break;
468                         }
469                     case ecEnumerated:
470                     case ecString:
471                         {
472                             return m_value.GetString();
473                             break;
474                         }
475                     case ecBool:
476                         {
477                             return wxEmptyString;
478                             break;
479                         }
480                     default:
481                         {
482                             break;
483                         }
484                 }
485                 break;
486             }
487         default:
488             {
489                 break;
490             }
491     }
492
493     return wxEmptyString;
494 #endif
495 }
496
497 // Can we start editing this item?
498 bool ecConfigItem::CanEdit() const
499 {
500     if (!GetActive())
501         return FALSE;
502
503     if (GetConfigType() != ecOption)
504         return FALSE;
505
506     if (GetOptionFlavor() != ecFlavorData && GetOptionFlavor() != ecFlavorBoolData)
507         return FALSE;
508
509     // TODO: other criteria for editability
510     return TRUE;
511 }
512
513
514 // Creates an edit window. It will be positioned by the caller.
515 wxWindow* ecConfigItem::CreateEditWindow(wxWindow* parent)
516 {
517     wxWindow* window = NULL;
518
519     switch(GetOptionType())
520     {
521     case ecEnumerated:
522         {
523             window = new ecEnumEditorCtrl(parent, ecID_ITEM_EDIT_WINDOW, wxDefaultPosition, wxDefaultSize,
524                 /* wxNO_BORDER */ 0);
525             wxArrayString arEnumStrings;
526             EvalEnumStrings(arEnumStrings);
527             int i;
528             for (i = 0; i < arEnumStrings.GetCount(); i++)
529             {
530                 ((ecEnumEditorCtrl*) window)->Append(arEnumStrings[i]);
531             }
532             break;
533         }
534     case ecLong:
535         {
536             window = new ecIntegerEditorCtrl(parent, ecID_ITEM_EDIT_WINDOW, wxDefaultPosition, wxDefaultSize,
537                 /* wxNO_BORDER | */ wxSP_ARROW_KEYS);
538             break;
539         }
540     case ecDouble:
541         {
542             window = new ecDoubleEditorCtrl(parent, ecID_ITEM_EDIT_WINDOW, wxDefaultPosition, wxDefaultSize,
543                 /* wxNO_BORDER|*/ wxTE_PROCESS_ENTER);
544             break;
545         }
546     case ecString:
547         {
548             window = new ecTextEditorCtrl(parent, ecID_ITEM_EDIT_WINDOW, wxDefaultPosition, wxDefaultSize,
549                 /* wxNO_BORDER|*/ wxTE_PROCESS_ENTER);
550             break;
551         }
552     default:
553         break;
554     }
555
556     wxASSERT (window != NULL) ;
557     
558     return window;
559 }
560     
561 // Transfers data between item and window
562 bool ecConfigItem::TransferDataToWindow(wxWindow* window)
563 {
564     if (window->IsKindOf(CLASSINFO(ecTextEditorCtrl)))
565     {
566         ecTextEditorCtrl* win = (ecTextEditorCtrl*) window;
567         win->SetValue(GetDisplayValue());
568     }
569     else if (window->IsKindOf(CLASSINFO(ecDoubleEditorCtrl)))
570     {
571         ecDoubleEditorCtrl* win = (ecDoubleEditorCtrl*) window;
572         win->SetValue(GetDisplayValue());
573     }
574     else if (window->IsKindOf(CLASSINFO(ecEnumEditorCtrl)))
575     {
576         ecEnumEditorCtrl* win = (ecEnumEditorCtrl*) window;
577         win->SetStringSelection(GetDisplayValue());
578     }
579     else if (window->IsKindOf(CLASSINFO(ecIntegerEditorCtrl)))
580     {
581         ecIntegerEditorCtrl* win = (ecIntegerEditorCtrl*) window;
582         long i;
583         ecUtils::StrToItemIntegerType(StringValue(), i);
584
585         wxString val;
586         val.Printf(wxT("%ld"), i);
587
588         win->SetValue(val);
589     }
590     return TRUE;
591 }
592
593 bool ecConfigItem::TransferDataFromWindow(wxWindow* window)
594 {
595     ecConfigToolDoc* doc = wxGetApp().GetConfigToolDoc();
596     wxASSERT (doc != NULL);
597
598     if (!doc)
599         return FALSE;
600
601     if (window->IsKindOf(CLASSINFO(ecTextEditorCtrl)))
602     {
603         ecTextEditorCtrl* win = (ecTextEditorCtrl*) window;
604
605         wxASSERT ( GetOptionType() == ecString );
606
607         // TODO: do checking
608         doc->SetValue(*this, win->GetValue());
609     }
610     else if (window->IsKindOf(CLASSINFO(ecDoubleEditorCtrl)))
611     {
612         ecDoubleEditorCtrl* win = (ecDoubleEditorCtrl*) window;
613
614         wxASSERT ( GetOptionType() == ecString );
615
616         // TODO: do checking
617         doc->SetValue(*this, atof(win->GetValue()));
618     }
619     else if (window->IsKindOf(CLASSINFO(ecEnumEditorCtrl)))
620     {
621         ecEnumEditorCtrl* win = (ecEnumEditorCtrl*) window;
622
623         wxASSERT ( GetOptionType() == ecEnumerated );
624
625         // TODO: do checking
626         doc->SetValue(*this, win->GetStringSelection());
627     }
628     else if (window->IsKindOf(CLASSINFO(ecIntegerEditorCtrl)))
629     {
630         ecIntegerEditorCtrl* win = (ecIntegerEditorCtrl*) window;
631
632         wxASSERT ( GetOptionType() == ecLong );
633
634         // TODO: do checking
635         doc->SetValue(*this, (long) win->GetValue());
636     }
637
638     return TRUE;
639 }
640
641 //// Taken from MFC version
642
643 const ecFileName ecConfigItem::GetFilename() const
644 {
645     wxString sep(wxFILE_SEP_PATH);
646
647     ecFileName strFile;
648     const CdlNode node = dynamic_cast<CdlNode> (m_CdlItem);
649     if (node){
650         // get the package which owns the configuration item
651         const CdlPackage package = GetOwnerPackage();
652         if (package){
653             
654             // return the filename of the config header
655             wxString pkg(wxT("include"));
656             pkg += sep;
657             pkg += wxT("pkgconf");
658             strFile=ecFileName(wxGetApp().GetConfigToolDoc()->GetInstallTree()+sep+pkg) + package->get_config_header ().c_str ();
659         }
660     }
661     return strFile;
662 }
663
664 // Change version (of a package)
665 bool ecConfigItem::ChangeVersion(const wxString &strVersion)
666 {
667     bool rc=FALSE;
668     CdlPackage package=dynamic_cast<CdlPackage>(GetCdlItem());
669     wxASSERT(package != 0);
670     const CdlValuable valuable = GetCdlValuable();
671     wxASSERT (valuable != 0);
672     const wxString strMacroName(GetMacro());
673     if (strVersion != valuable->get_value ().c_str ()) { // if the wrong version is loaded
674         // TRACE (wxT("Changing package %s to version '%s'\n"), strMacroName, strVersion);
675         try {
676             wxGetApp().GetConfigToolDoc()->GetCdlConfig()->change_package_version (package, ecUtils::UnicodeToStdStr (strVersion), ecConfigToolDoc::CdlParseErrorHandler, ecConfigToolDoc::CdlParseWarningHandler);
677             rc=TRUE;
678         }
679         catch (CdlStringException exception) {
680             wxString msg;
681             msg.Printf(wxT("Error changing package %s to version '%s':\n\n%s"), (const wxChar*) strMacroName, (const wxChar*) strVersion, (const wxChar*) wxString (exception.get_message ().c_str ())) ;
682             wxMessageBox(msg);
683         }
684         catch (...) {
685             wxString msg;
686             msg.Printf(wxT("Error changing package %s to version '%s'"), (const wxChar*) strMacroName, (const wxChar*) strVersion) ;
687             wxMessageBox(msg);
688         }
689     }
690     return rc;
691 }
692
693 // Unload (a package)
694 bool ecConfigItem::Unload()
695 {
696     bool rc=FALSE;
697     CdlPackage package=dynamic_cast<CdlPackage>(GetCdlItem());
698     wxASSERT(package);
699     ecConfigToolDoc* pDoc=wxGetApp().GetConfigToolDoc();
700
701     // Remove its objects from the view to prevent any painting problems
702     ecTreeItemData* data = (ecTreeItemData*) wxGetApp().GetTreeCtrl()->GetItemData(GetTreeItem());
703     wxASSERT(data);
704
705     // I _think_ we should do this to stop 'this' from being deleted when we delete the item.
706     // But, in that case, where do we delete this item?
707     // Perhaps should store them in an array in the document, as per the MFC tool.
708     data->SetConfigItem(NULL);
709
710     wxGetApp().GetTreeCtrl()->Delete(GetTreeItem());
711
712     wxNode* node = pDoc->GetItems().First();
713     while (node)
714     {
715         ecConfigItem* item = wxDynamicCast(node->Data(), ecConfigItem);
716         if (package == item->GetOwnerPackage())
717         {
718             item->SetTreeItem(wxTreeItemId()); // Make sure we can't attempt to paint it
719             item->SetCdlItem(NULL); // Make sure we can't access stale data
720         }
721         node = node->Next();
722     }
723
724     const wxString strMacroName(GetMacro());
725     //TRACE (wxT("Unloading package %s\n"), strMacroName);
726     try {
727         pDoc->GetCdlConfig()->unload_package (package);
728         rc=TRUE;
729     }
730     catch (CdlStringException exception) {
731         wxString msg;
732         wxString exceptionMsg(exception.get_message ().c_str ());
733         msg.Printf(wxT("Error unloading package %s:\n\n%s"), (const wxChar*) strMacroName, (const wxChar*) exceptionMsg );
734         wxMessageBox(msg);
735     }
736     catch (...) {
737         wxString msg;
738         msg.Printf(wxT("Error unloading package %s"), (const wxChar*) strMacroName);
739         wxMessageBox(msg);
740     }
741     m_treeItem=wxTreeItemId();   // Make sure we can't attempt to paint it
742     m_CdlItem=NULL; // Make sure we can't access stale data
743     return rc;
744 }
745
746 wxString ecConfigItem::GetURL() const
747 {
748     for(const ecConfigItem *pItem=this;pItem;pItem=pItem->GetParent()){
749         if(pItem->GetCdlItem()){
750             wxString strURL;
751             strURL=pItem->GetCdlItem()->get_doc_url().c_str();
752             if(strURL.Len()){
753                 return strURL;
754             }
755             strURL=pItem->GetCdlItem()->get_doc().c_str();
756             if(strURL.Len()){
757                 return strURL;
758             }
759         }
760     }
761     return wxT("ref/ecos-ref.html"); // the default URL
762 }
763
764 bool ecConfigItem::SetValue(const wxString& value, CdlTransaction transaction/*=NULL*/)
765 {
766     wxASSERT ((m_optionType == ecString) || (m_optionType == ecEnumerated));
767     const CdlValuable valuable = GetCdlValuable();
768     wxASSERT (valuable);
769     const std::string str = value.c_str();
770     if(transaction){
771         if (CdlValueFlavor_BoolData == valuable->get_flavor ()){
772             // set the user bool to the current bool when changing a booldata
773             // value to avoid a possible change in the current bool
774             valuable->set_enabled_and_value (transaction, valuable->is_enabled (), str, CdlValueSource_User);
775         } else {// CdlValueFlavor_Data
776             valuable->set_value (transaction, str, CdlValueSource_User);
777         }
778     } else {
779         if (CdlValueFlavor_BoolData == valuable->get_flavor ()){
780             // set the user bool to the current bool when changing a booldata
781             // value to avoid a possible change in the current bool
782             valuable->set_enabled_and_value (valuable->is_enabled (), str, CdlValueSource_User);
783         } else {// CdlValueFlavor_Data
784             valuable->set_value (str, CdlValueSource_User);
785         }
786     }
787
788     // TODO: eliminate m_value, since the value is always taken from the Cdl object.
789     m_value = value;
790     
791     return TRUE;
792 }
793
794 bool ecConfigItem::SetValue (double dValue, CdlTransaction transaction/*=NULL*/)
795 {
796     wxASSERT (m_optionType == ecDouble);
797
798     const CdlValuable valuable = GetCdlValuable();
799     wxASSERT (valuable);
800     
801     if(transaction) {
802         if (CdlValueFlavor_BoolData == valuable->get_flavor ()) {
803             // set the user bool to the current bool when changing a booldata
804             // value to avoid a possible change in the current bool
805             valuable->set_enabled_and_value (transaction, valuable->is_enabled (), dValue, CdlValueSource_User);
806         } else {// CdlValueFlavor_Data
807             valuable->set_double_value (transaction, dValue, CdlValueSource_User);
808         }
809     } else {
810         if (CdlValueFlavor_BoolData == valuable->get_flavor ()) {
811             // set the user bool to the current bool when changing a booldata
812             // value to avoid a possible change in the current bool
813             valuable->set_enabled_and_value (valuable->is_enabled (), dValue, CdlValueSource_User);
814         } else {// CdlValueFlavor_Data
815             valuable->set_double_value (dValue, CdlValueSource_User);
816         }
817     }
818
819     // TODO: BoolData?
820     m_value = dValue;
821     
822     return TRUE;
823 }
824
825 bool ecConfigItem::SetValue (long nValue, CdlTransaction transaction/*=NULL*/)
826 {
827     wxASSERT (m_optionType == ecLong);
828     const CdlValuable valuable = GetCdlValuable();
829     wxASSERT (valuable);
830     
831     if(transaction) {
832         if (CdlValueFlavor_BoolData == valuable->get_flavor ()) {
833             // set the user bool to the current bool when changing a booldata
834             // value to avoid a possible change in the current bool
835             valuable->set_enabled_and_value (transaction, valuable->is_enabled (), (cdl_int) nValue, CdlValueSource_User);
836         } else { // CdlValueFlavor_Data
837             valuable->set_integer_value (transaction, nValue, CdlValueSource_User);
838         }
839     } else {
840         if (CdlValueFlavor_BoolData == valuable->get_flavor ()) {
841             // set the user bool to the current bool when changing a booldata
842             // value to avoid a possible change in the current bool
843             valuable->set_enabled_and_value (valuable->is_enabled (), (cdl_int) nValue, CdlValueSource_User);
844         } else { // CdlValueFlavor_Data
845             valuable->set_integer_value (nValue, CdlValueSource_User);
846         }
847     }
848
849     // TODO: BoolData?
850     m_value = nValue;
851     
852     return TRUE;
853 }
854
855 bool ecConfigItem::HasRadio() const
856 {
857     const CdlValuable valuable = GetCdlValuable();
858     if (! valuable)
859         return FALSE;
860     
861     CdlWidgetHint hint;
862     valuable->get_widget_hint (hint);
863     return (CdlBoolWidget_Radio == hint.bool_widget);
864 }
865
866 ecConfigItem *ecConfigItem::FirstRadio() const
867 {
868     wxASSERT(HasRadio ());
869     
870     for(ecConfigItem *h=GetParent()->FirstChild();h;h=h->NextSibling()){
871         if(h->HasRadio ()){
872             return h;
873         }
874     }
875     // No radio buttons found
876     wxASSERT(FALSE);
877     return FALSE;
878 }
879
880 ecConfigItem *ecConfigItem::FirstChild() const
881
882     ecConfigTreeCtrl* treeCtrl = wxGetApp().GetTreeCtrl();
883
884     long cookie;
885     wxTreeItemId hChild=treeCtrl->GetFirstChild(GetTreeItem(), cookie);
886     if (hChild)
887     {
888         ecTreeItemData* data = (ecTreeItemData*) wxGetApp().GetTreeCtrl()->GetItemData(hChild);
889         wxASSERT(data);
890
891         return data->GetConfigItem();
892     }
893     else
894         return NULL;
895 }
896
897 ecConfigItem *ecConfigItem::NextSibling() const
898
899     ecConfigTreeCtrl* treeCtrl = wxGetApp().GetTreeCtrl();
900
901     wxTreeItemId hChild=treeCtrl->GetNextSibling(GetTreeItem());
902     if (hChild)
903     {
904         ecTreeItemData* data = (ecTreeItemData*) wxGetApp().GetTreeCtrl()->GetItemData(hChild);
905         wxASSERT(data);
906
907         return data->GetConfigItem();
908     }
909     else
910         return NULL;
911 }
912
913 bool ecConfigItem::IsEnabled() const
914 {
915     const CdlValuable valuable = GetCdlValuable();
916     return NULL==valuable ||valuable->is_enabled();
917 }
918
919 bool ecConfigItem::IsActive() const
920 {
921 //    return GetCdlItem()->is_active();
922     const CdlValuable valuable = GetCdlValuable();
923     if (valuable && ((GetOptionType() != ecOptionTypeNone) || HasBool()))
924     {
925         return (valuable->is_modifiable () && valuable->is_active ());
926     }
927     else
928         return GetCdlItem()->is_active();
929 }
930
931 bool ecConfigItem::HasModifiedChildren() const
932 {
933     for(ecConfigItem *pItem=FirstChild();pItem;pItem=pItem->NextSibling()){
934         if(pItem->Modified()||pItem->HasModifiedChildren()){
935             return TRUE;
936         }
937     }
938     return FALSE;
939 }
940
941 bool ecConfigItem::Modified () const
942 {
943     const CdlValuable valuable = GetCdlValuable();
944     return 
945         valuable        // accommodate the root config item which has no CDL item
946         && !IsPackage() // packages are never modified
947         && valuable->get_source () != CdlValueSource_Default;
948 }
949
950 void ecConfigItem::DumpItem()
951 {
952     //TRACE(wxT("Item %08x\n\tDisplay Name='%s'\n\tMacro Name='%s'\n\tType=%s"), this,  Name(),           Macro(),    TreeItemTypeImage[m_Type]);
953     //TRACE(wxT("\n\tValue=%s\n\tURL=%s\n\tParent=%08x"),StringValue(), GetURL(), Parent());
954     
955     //TRACE(wxT("\n"));
956 }
957
958 ecConfigItem * ecConfigItem::NextRadio() const
959 {
960     wxASSERT(this->HasRadio ());
961     for(ecConfigItem *pItem=NextSibling();pItem;pItem=pItem->NextSibling()){
962         if(pItem->HasRadio()){
963             return pItem;
964         }
965     }
966     return NULL;
967 }
968
969 bool ecConfigItem::IsDescendantOf(ecConfigItem * pAncestor)
970 {
971     for(ecConfigItem *pItem=GetParent();pItem;pItem=pItem->GetParent()){
972         if(pItem==pAncestor){
973             return TRUE;
974         }
975     }
976     return FALSE;
977 }
978
979 bool ecConfigItem::ViewHeader()
980 {
981     bool rc=FALSE;
982     const ecFileName strFile(GetFilename());
983     if(!strFile.IsEmpty())
984     {
985         ecConfigToolDoc *pDoc=wxGetApp().GetConfigToolDoc();
986         if(pDoc->GetBuildTree().IsEmpty()){
987             wxString msg;
988             msg.Printf(wxT("Cannot display header file until configuration is saved"));
989             wxMessageBox(msg);
990         } else
991         {
992             rc=wxGetApp().Launch(strFile, wxGetApp().GetSettings().m_strViewer);
993         }
994     }
995     return rc;
996 }
997
998 bool ecConfigItem::ViewURL()
999 {
1000     return wxGetApp().GetConfigToolDoc()->ShowURL(GetURL());
1001 }
1002
1003 bool ecConfigItem::HasBool() const
1004 {
1005     if (!m_CdlItem) {
1006         return FALSE;
1007     } else if (IsPackage()) {
1008         return FALSE;
1009     } else {
1010         const CdlValuable valuable = GetCdlValuable();
1011         CdlValueFlavor flavor = valuable->get_flavor ();
1012         return (flavor == CdlValueFlavor_Bool) || (flavor == CdlValueFlavor_BoolData);
1013     }
1014 }
1015
1016 bool ecConfigItem::SetEnabled(bool bEnabled, CdlTransaction current_transaction/*=NULL*/)
1017 {
1018     const CdlValuable valuable = GetCdlValuable();
1019     wxASSERT (valuable);
1020     
1021     // use a transaction object to ensure that all config items are changed together
1022     CdlTransaction transaction = current_transaction ? current_transaction : CdlTransactionBody::make (wxGetApp().GetConfigToolDoc ()->GetCdlConfig ());
1023     
1024     if (HasRadio () && bEnabled) { // if a new radio button has been selected
1025         for (ecConfigItem *pItem = FirstRadio(); pItem; pItem = pItem->NextRadio ()) { // for each radio button in the group
1026             if (pItem != this) { // if not the newly selected radio button
1027                 pItem->SetEnabled (FALSE, transaction); // disable the radio button
1028             }
1029         }
1030     }
1031     
1032     if (CdlValueFlavor_BoolData == valuable->get_flavor ()) {
1033         // set the user value to the current data value when enabling/disabling
1034         // a booldata item to avoid a possible change in the current data value
1035         CdlSimpleValue simple_value = valuable->get_simple_value ();
1036         valuable->set_enabled_and_value (transaction, bEnabled, simple_value, CdlValueSource_User);
1037     } else { // CdlValueFlavor_Bool
1038         valuable->set_enabled (transaction, bEnabled, CdlValueSource_User);
1039     }
1040     
1041     if (! current_transaction) { // if not a recursive call to disable a radio button
1042         transaction->body (); // commit the transaction
1043         delete transaction;
1044         transaction = NULL;
1045     }
1046     
1047     return TRUE;
1048 }
1049
1050 long ecConfigItem::DefaultValue () const
1051 {
1052     return (long) atoi (StringValue (CdlValueSource_Default)) ;
1053 }
1054
1055 long ecConfigItem::Value () const
1056 {
1057     wxASSERT (!IsPackage()); // not a package item
1058     const CdlValuable valuable = GetCdlValuable();
1059     wxASSERT (valuable);
1060     long nValue (0);
1061     
1062     switch (valuable->get_flavor ())
1063     {
1064         //      case CdlValueFlavor_Bool:
1065         //              nValue = valuable->is_enabled (CdlValueSource_Current) ? 1 : 0;
1066         //              break;
1067         
1068     case CdlValueFlavor_BoolData:
1069     case CdlValueFlavor_Data:
1070         nValue = (long) valuable->get_integer_value (CdlValueSource_Current);
1071         break;
1072         
1073     default:
1074         wxASSERT (0); // specified flavor not supported
1075     }
1076     
1077     return nValue;
1078 }
1079
1080 const double ecConfigItem::DoubleValue (CdlValueSource source /* = CdlValueSource_Current */ ) const
1081 {
1082     wxASSERT (!IsPackage()); // not a package item
1083     const CdlValuable valuable = GetCdlValuable();
1084     wxASSERT (valuable);
1085     wxASSERT (valuable->has_double_value (source));
1086     return valuable->get_double_value (source);
1087 }
1088
1089 const wxString ecConfigItem::StringValue (CdlValueSource source /* = CdlValueSource_Current */ ) const
1090 {
1091     //  wxASSERT (!IsPackage()); // not a package item
1092     const CdlValuable valuable = GetCdlValuable();
1093     wxASSERT (valuable);
1094     wxString strValue (wxT(""));
1095     
1096     switch (valuable->get_flavor ())
1097     {
1098     case CdlValueFlavor_Data:
1099     case CdlValueFlavor_BoolData:
1100     case CdlValueFlavor_None: // a package
1101         if (m_optionType == ecLong)
1102             strValue = ecUtils::IntToStr (Value (), wxGetApp().GetSettings().m_bHex);
1103         else if (m_optionType == ecDouble)
1104             strValue = ecUtils::DoubleToStr (DoubleValue ());
1105         else
1106             strValue = valuable->get_value (source).c_str ();
1107         break;
1108         
1109     default:
1110         wxASSERT (0); // specified flavor not supported
1111     }
1112     
1113     return strValue;
1114 }
1115
1116 const wxString ecConfigItem::StringValue(ecWhereType where) const
1117 {
1118     wxString str;
1119     switch(where){
1120     case ecInName:
1121         str=GetName();
1122         break;
1123     case ecInMacro:
1124         str=GetMacro();
1125         break;
1126     case ecInDesc:
1127         str=GetDescription();
1128         break;
1129     case ecInCurrentValue:
1130         if (ecOptionTypeNone==GetOptionType())
1131             str = wxEmptyString;
1132         else
1133             str = StringValue(CdlValueSource_Current);
1134         break;
1135     case ecInDefaultValue:
1136         if (ecOptionTypeNone==GetOptionType())
1137             str = wxEmptyString;
1138         else
1139             str = StringValue(CdlValueSource_Default);
1140         break;
1141     default:
1142         wxASSERT(FALSE);
1143         break;
1144     }
1145     return str;
1146 }    
1147
1148 int ecConfigItem::EvalEnumStrings (wxArrayString &arEnumStrings) const
1149 {
1150     const CdlValuable valuable = GetCdlValuable();
1151     wxASSERT (valuable);
1152     /*
1153     if (m_Type == Boolean)
1154     {
1155     arEnumStrings.SetSize (2);
1156     arEnumStrings.SetAt (0, wxT("True"));
1157     arEnumStrings.SetAt (1, wxT("False"));
1158     }
1159     else
1160     */
1161     {
1162         wxASSERT (m_optionType == ecEnumerated);
1163         CdlListValue list_value;
1164         CdlEvalContext context (NULL, m_CdlItem, m_CdlItem->get_property (CdlPropertyId_LegalValues));
1165         valuable->get_legal_values ()->eval (context, list_value);
1166         const std::vector<CdlSimpleValue> & table = list_value.get_table ();
1167         
1168         // add legal values to the list
1169         for (unsigned int nValue = 0; nValue < table.size (); nValue++)
1170         {
1171             arEnumStrings.Add (table [nValue].get_value ().c_str ());
1172         }
1173     }
1174     return arEnumStrings.GetCount();
1175 }
1176
1177 static const wxChar* gs_whereTypes[] = 
1178 {
1179         _("Macro names"), 
1180         _("Item names"), 
1181         _("Short descriptions"), 
1182         _("Current Values"), 
1183         _("Default Values")
1184 };
1185
1186 // Convert a string representation of 'where' (e.g. "Macro names") to
1187 // ecWhereType
1188 ecWhereType ecConfigItem::WhereStringToType(const wxString& whereString)
1189 {
1190     int sz = 5;
1191     int i;
1192     for (i = 0; i < sz; i++)
1193         if (whereString == gs_whereTypes[i])
1194             return (ecWhereType) i;
1195
1196     wxASSERT( FALSE );
1197
1198     return (ecWhereType) 0;
1199 }
1200
1201 // Convert a type representation of 'where' to a string
1202 wxString ecConfigItem::WhereTypeToString(ecWhereType whereType)
1203 {
1204     return gs_whereTypes[(size_t) whereType] ;
1205 }
1206
1207 // Bump by specified amount, or toggle if a boolean value
1208 bool ecConfigItem::BumpItem(int nInc)
1209 {
1210     bool rc = FALSE;
1211     
1212     // Take an action for clicking on the icon
1213     ecConfigToolDoc* pDoc = wxGetApp().GetConfigToolDoc();
1214     
1215     // do not modify the option value if it is inactive or not modifiable
1216     const CdlValuable valuable = GetCdlValuable();
1217     if (!valuable || (valuable->is_modifiable () && valuable->is_active ()))
1218     {
1219         if (0 == nInc) // if a toggle request
1220         {
1221             if (HasBool () && ! (HasRadio () && IsEnabled ())) { // only enable (not disable) a radio button
1222                 rc = pDoc->SetEnabled (*this, ! this->IsEnabled ()); // toggle enabled/disabled state
1223             }
1224         } else if (IsEnabled ()) { // the item is enabled...
1225             switch(GetOptionType())
1226             {
1227             case ecOptionTypeNone:
1228             case ecString:
1229             case ecDouble:
1230                 break;
1231             case ecEnumerated:
1232                 {
1233                     wxArrayString arEnum;
1234                     EvalEnumStrings (arEnum); // calculate legal values just in time
1235                     if (0==arEnum.Count()) // if no legal values...
1236                         break;           // ...do nothing
1237                     int nIndex = -1;
1238                     const wxString strCurrent = StringValue ();
1239                     int nEnum;
1240                     for (nEnum = 0; (nEnum < arEnum.Count()) && (nIndex == -1); nEnum++)
1241                         if (strCurrent == arEnum[nEnum])
1242                             nIndex = nEnum; // the index of the current value
1243                         
1244                         if (nIndex != -1) // if the current value is still legal
1245                             nIndex += (nInc < 0 ? -1 : 1); // increment/decrement the index
1246                         else
1247                             nIndex = 0; // otherwise select the first enum
1248                         
1249                         if (nIndex < 0) // if the new index is negative
1250                             nIndex = arEnum.Count()-1; // make it positive
1251                         
1252                         rc=pDoc->SetValue (*this, arEnum[nIndex % arEnum.Count()]);
1253                 }
1254                 break;
1255             case ecLong:
1256                 {
1257                     // TODO: if we're editing, we should get the value in the edit item
1258                     // and not the ecConfigItem.
1259                     long nOldValue = Value();
1260                     if(nInc==1 && nOldValue==-1){
1261                         nOldValue=0;
1262                     } else if(nInc==-1 && nOldValue==0){
1263                         nOldValue=-1;
1264                     } else {
1265                         nOldValue+=nInc;
1266                     }
1267                     rc=pDoc->SetValue(*this, nOldValue);
1268                     break;
1269                 }
1270                 
1271                 break;
1272                 /*
1273                 case CConfigItem::Boolean:
1274                 
1275                   {
1276                   ItemIntegerType nOldValue=Value(h);
1277                   pDoc->SetValue(ti,nOldValue^1);
1278                   }
1279                   break;
1280                   case CConfigItem::Radio:
1281                   
1282                     if(0==Value(h)){
1283                     pDoc->SetValue(ti, (ItemIntegerType) 1);
1284                     }
1285                     break;
1286                 */
1287             default:
1288                 break;
1289             }
1290         }
1291     }
1292     return rc;
1293 }
1294
1295 #if 0
1296
1297 /* Presumably we don't need this since we use the m_parent member instead
1298 ecConfigItem *ecConfigItem::Parent() const 
1299
1300     CTreeCtrl &tree=CConfigTool::GetControlView()->GetTreeCtrl();
1301     HTREEITEM hParent=tree.GetParentItem(HItem());
1302     return (NULL==hParent||TVI_ROOT==hParent)?NULL:(ecConfigItem *)tree.GetItemData(hParent);
1303 }
1304 */
1305
1306 #endif
1307
1308 /*
1309  * ecTextEditorCtrl
1310  * A specialised wxTextCtrl, for editing config values
1311  */
1312
1313 BEGIN_EVENT_TABLE(ecTextEditorCtrl, wxTextCtrl)
1314     EVT_TEXT_ENTER(-1, ecTextEditorCtrl::OnEnter)
1315     EVT_KILL_FOCUS(ecTextEditorCtrl::OnKillFocus)
1316     EVT_LEFT_DCLICK(ecTextEditorCtrl::OnLeftDClick)
1317 END_EVENT_TABLE()
1318
1319 IMPLEMENT_CLASS(ecTextEditorCtrl, wxTextCtrl)
1320
1321 ecTextEditorCtrl::ecTextEditorCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
1322                                    long style):
1323     wxTextCtrl(parent, id, wxEmptyString, pos, size, style)
1324 {
1325 }
1326
1327 void ecTextEditorCtrl::OnEnter(wxCommandEvent& event)
1328 {
1329     ecValueWindow* parent = (ecValueWindow*) GetParent();
1330     parent->EndEditing();
1331 }
1332
1333 void ecTextEditorCtrl::OnKillFocus(wxFocusEvent& event)
1334 {
1335     ecValueWindow* parent = (ecValueWindow*) GetParent();
1336     parent->EndEditing();
1337 }
1338
1339 // Edit the string in a separate dialog, for convenience
1340 void ecTextEditorCtrl::OnLeftDClick(wxMouseEvent& event)
1341 {
1342     ecValueWindow* parent = (ecValueWindow*) GetParent();
1343     ecConfigItem* item = parent->GetCurrentConfigItem();
1344     ecConfigToolDoc* doc = wxGetApp().GetConfigToolDoc();
1345     
1346     wxString initialValue(GetValue());
1347     
1348     ecEditStringDialog dialog(initialValue, wxGetApp().GetTopWindow(), ecID_EDIT_STRING_DIALOG);
1349     if (dialog.ShowModal() == wxID_OK)
1350     {
1351         wxString val = dialog.GetValue() ;
1352         // This control will have been deleted at this point, due to losing the focus.
1353         // So update the item, not the control.
1354         // wxTextCtrl::SetValue(val);
1355         doc->SetValue(*item, val);
1356     }   
1357 }
1358
1359 /*
1360  * ecDoubleEditorCtrl
1361  * A specialised wxTextCtrl, for editing double config values
1362  */
1363
1364 BEGIN_EVENT_TABLE(ecDoubleEditorCtrl, wxTextCtrl)
1365     EVT_TEXT_ENTER(-1, ecDoubleEditorCtrl::OnEnter)
1366     EVT_KILL_FOCUS(ecDoubleEditorCtrl::OnKillFocus)
1367 END_EVENT_TABLE()
1368
1369 IMPLEMENT_CLASS(ecDoubleEditorCtrl, wxTextCtrl)
1370
1371 ecDoubleEditorCtrl::ecDoubleEditorCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
1372                                    long style):
1373     wxTextCtrl(parent, id, wxEmptyString, pos, size, style)
1374 {
1375 }
1376
1377 void ecDoubleEditorCtrl::OnEnter(wxCommandEvent& event)
1378 {
1379     ecValueWindow* parent = (ecValueWindow*) GetParent();
1380     parent->EndEditing();
1381 }
1382
1383 void ecDoubleEditorCtrl::OnKillFocus(wxFocusEvent& event)
1384 {
1385     ecValueWindow* parent = (ecValueWindow*) GetParent();
1386     parent->EndEditing();
1387 }
1388
1389 /*
1390  * ecIntegerEditorCtrl
1391  * A specialised wxTextCtrl, for editing double config values
1392  */
1393
1394 BEGIN_EVENT_TABLE(ecIntegerEditorCtrl, wxSpinCtrl)
1395     EVT_TEXT_ENTER(-1, ecIntegerEditorCtrl::OnEnter)
1396     EVT_KILL_FOCUS(ecIntegerEditorCtrl::OnKillFocus)
1397 END_EVENT_TABLE()
1398
1399 IMPLEMENT_CLASS(ecIntegerEditorCtrl, wxSpinCtrl)
1400
1401 ecIntegerEditorCtrl::ecIntegerEditorCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
1402                                    long style):
1403     wxSpinCtrl(parent, id, wxEmptyString, pos, size, style, -32000, 32000, 0)
1404 {
1405 }
1406
1407 void ecIntegerEditorCtrl::OnEnter(wxCommandEvent& event)
1408 {
1409     ecValueWindow* parent = (ecValueWindow*) GetParent();
1410     parent->EndEditing();
1411 }
1412
1413 void ecIntegerEditorCtrl::OnKillFocus(wxFocusEvent& event)
1414 {
1415     ecValueWindow* parent = (ecValueWindow*) GetParent();
1416     parent->EndEditing();
1417 }
1418
1419 /*
1420  * ecEnumEditorCtrl
1421  * A specialised wxChoice, for editing enumerated config values
1422  */
1423
1424 BEGIN_EVENT_TABLE(ecEnumEditorCtrl, wxChoice)
1425     EVT_CHAR(ecEnumEditorCtrl::OnChar)
1426     EVT_KILL_FOCUS(ecEnumEditorCtrl::OnKillFocus)
1427 END_EVENT_TABLE()
1428
1429 IMPLEMENT_CLASS(ecEnumEditorCtrl, wxChoice)
1430
1431 ecEnumEditorCtrl::ecEnumEditorCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
1432                                    long style):
1433     wxChoice(parent, id, pos, size, 0, 0, style)
1434 {
1435 }
1436
1437 void ecEnumEditorCtrl::OnChar(wxKeyEvent& event)
1438 {
1439     if (event.GetKeyCode() == WXK_RETURN)
1440     {
1441         ecValueWindow* parent = (ecValueWindow*) GetParent();
1442         parent->EndEditing();
1443     }
1444     else
1445         event.Skip();
1446 }
1447
1448 void ecEnumEditorCtrl::OnKillFocus(wxFocusEvent& event)
1449 {
1450     ecValueWindow* parent = (ecValueWindow*) GetParent();
1451     parent->EndEditing();
1452 }
1453
1454 /*
1455  * ecEditStringDialog
1456  * Pops up to make it easier to edit large string values
1457  */
1458
1459 BEGIN_EVENT_TABLE(ecEditStringDialog, ecDialog)
1460     EVT_BUTTON(wxID_OK, ecEditStringDialog::OnOK)
1461 END_EVENT_TABLE()
1462
1463 ecEditStringDialog::ecEditStringDialog(const wxString& initialValue, wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
1464         long style)
1465 {
1466     m_value = initialValue;
1467     //SetExtraStyle(wxDIALOG_EX_CONTEXTHELP);
1468
1469     ecDialog::Create(parent, id, _("String Edit"),
1470         wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER);
1471
1472     CreateControls(this);
1473     
1474     TransferDataToWindow();
1475
1476     Centre(wxBOTH);
1477 }
1478
1479 ecEditStringDialog::~ecEditStringDialog()
1480 {
1481 }
1482
1483 //// Event handlers
1484
1485 void ecEditStringDialog::OnOK(wxCommandEvent& event)
1486 {
1487     wxDialog::OnOK(event);
1488 }
1489
1490 //// Operations
1491 void ecEditStringDialog::CreateControls(wxWindow* parent)
1492 {
1493     wxSizer *item0 = new wxBoxSizer( wxVERTICAL );
1494
1495     wxSizer *item1 = new wxBoxSizer( wxHORIZONTAL );
1496
1497     item1->Add( 20, 20, 10, wxALIGN_CENTRE|wxALL, 5 );
1498
1499     wxButton *item2 = new wxButton( parent, wxID_OK, _("&OK"), wxDefaultPosition, wxDefaultSize, 0 );
1500     item2->SetDefault();
1501     item1->Add( item2, 0, wxALIGN_CENTRE|wxALL, 5 );
1502
1503     wxButton *item3 = new wxButton( parent, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxDefaultSize, 0 );
1504     item1->Add( item3, 0, wxALIGN_CENTRE|wxALL, 5 );
1505
1506     item0->Add( item1, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxTOP, 5 );
1507
1508     wxTextCtrl *item4 = new wxTextCtrl( parent, ecID_STRING_EDIT_TEXTCTRL, _(""), wxDefaultPosition, wxSize(420,250), wxTE_MULTILINE );
1509     item0->Add( item4, 1, wxGROW|wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxBOTTOM, 5 );
1510
1511     parent->SetAutoLayout( TRUE );
1512     parent->SetSizer( item0 );
1513     parent->Layout();
1514     item0->Fit( parent );
1515     item0->SetSizeHints( parent );
1516
1517     FindWindow(ecID_STRING_EDIT_TEXTCTRL)->SetValidator(wxGenericValidator(& m_value));
1518     FindWindow(ecID_STRING_EDIT_TEXTCTRL)->SetFocus();
1519 }