]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - tools/src/tools/configtool/standalone/wxwin/configtree.cpp
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / tools / src / tools / configtool / standalone / wxwin / configtree.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 // configtree.cpp :
26 //
27 //===========================================================================
28 //#####DESCRIPTIONBEGIN####
29 //
30 // Author(s):   julians
31 // Contact(s):  julians
32 // Date:        2000/08/24
33 // Version:     $Id$
34 // Purpose:
35 // Description: Implementation file for ecConfigTreeCtrl
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 "configtree.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/cshelp.h"
65
66 // Include XPM icons
67 #if !defined(__WXMSW__)
68 #include "bitmaps/closedfolder.xpm"
69 #include "bitmaps/closedfolder_dis.xpm"
70 #include "bitmaps/package_closed.xpm"
71 #include "bitmaps/package_closed_dis.xpm"
72 #include "bitmaps/package_open.xpm"
73 #include "bitmaps/package_open_dis.xpm"
74 #include "bitmaps/checked.xpm"
75 #include "bitmaps/checked_dis.xpm"
76 #include "bitmaps/unchecked.xpm"
77 #include "bitmaps/unchecked_dis.xpm"
78 #include "bitmaps/integer.xpm"
79 #include "bitmaps/integer_dis.xpm"
80 #include "bitmaps/integer2.xpm"
81 #include "bitmaps/integer2_dis.xpm"
82 #include "bitmaps/enumerated.xpm"
83 #include "bitmaps/enumerated_dis.xpm"
84 #include "bitmaps/radioon.xpm"
85 #include "bitmaps/radioon_dis.xpm"
86 #include "bitmaps/radiooff.xpm"
87 #include "bitmaps/radiooff_dis.xpm"
88 #include "bitmaps/text.xpm"
89 #include "bitmaps/text_dis.xpm"
90 #endif
91
92 #include "configtree.h"
93 #include "configpropdlg.h"
94 #include "configtooldoc.h"
95 #include "configtoolview.h"
96
97 /*
98  * ecConfigTreeCtrl
99  */
100
101 IMPLEMENT_CLASS(ecConfigTreeCtrl, wxRemotelyScrolledTreeCtrl)
102
103 BEGIN_EVENT_TABLE(ecConfigTreeCtrl, wxRemotelyScrolledTreeCtrl)
104     EVT_PAINT(ecConfigTreeCtrl::OnPaint)
105     EVT_MOUSE_EVENTS(ecConfigTreeCtrl::OnMouseEvent)
106     EVT_CHAR(ecConfigTreeCtrl::OnKeyDown)
107     EVT_TREE_SEL_CHANGED(-1, ecConfigTreeCtrl::OnSelChanged)
108     EVT_TREE_ITEM_EXPANDED(-1, ecConfigTreeCtrl::OnCollapseExpand)
109     EVT_TREE_ITEM_COLLAPSED(-1, ecConfigTreeCtrl::OnCollapseExpand)
110     EVT_HELP(-1, ecConfigTreeCtrl::OnHelp)
111 END_EVENT_TABLE()
112
113 ecConfigTreeCtrl::ecConfigTreeCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pt,
114                                    const wxSize& sz, long style):
115 wxRemotelyScrolledTreeCtrl(parent, id, pt, sz, style)
116 {
117     LoadIcons();
118     
119     m_propertiesMenu = new wxMenu;
120     
121     m_propertiesMenu->Append(ecID_WHATS_THIS, _("&What's This?"));
122     m_propertiesMenu->AppendSeparator();
123     m_propertiesMenu->Append(ecID_TREE_PROPERTIES, _("P&roperties"));
124     m_propertiesMenu->Append(ecID_TREE_RESTORE_DEFAULTS, _("Restore &Defaults"));
125     m_propertiesMenu->Append(ecID_TREE_VISIT_DOC, _("Visit Documentation"));
126     m_propertiesMenu->Append(ecID_TREE_VIEW_HEADER, _("View Header"));
127     m_propertiesMenu->AppendSeparator();
128     m_propertiesMenu->Append(ecID_TREE_UNLOAD_PACKAGE, _("&Unload Package..."));
129
130     if (!wxGetApp().GetSettings().GetWindowSettings().GetUseDefaults() &&
131          wxGetApp().GetSettings().GetWindowSettings().GetFont(wxT("Configuration")).Ok())
132     {
133         SetFont(wxGetApp().GetSettings().GetWindowSettings().GetFont(wxT("Configuration")));
134     }
135 }
136
137 // Load the icons and initialize the tree
138 void ecConfigTreeCtrl::LoadIcons()
139 {
140     m_imageList = new wxImageList(16, 16, TRUE);
141     m_iconDB.SetImageList(m_imageList);
142     SetImageList(m_imageList);
143     
144     // We associate names and states so we can easily get the appropriate
145     // icon for a given tree item. This gets used in ecConfigItem::UpdateTreeIcon.
146     
147     m_iconDB.AddInfo("Container", wxICON(closedfolder), 0, TRUE);
148     m_iconDB.AddInfo("Container", wxICON(closedfolder_dis), 0, FALSE);
149     
150     m_iconDB.AddInfo("Package", wxICON(package_open), 0, TRUE);
151     m_iconDB.AddInfo("Package", wxICON(package_open_dis), 0, FALSE);
152     
153     m_iconDB.AddInfo("Checkbox", wxICON(checked), 0, TRUE);
154     m_iconDB.AddInfo("Checkbox", wxICON(checked_dis), 0, FALSE);
155     m_iconDB.AddInfo("Checkbox", wxICON(unchecked), 1, TRUE);
156     m_iconDB.AddInfo("Checkbox", wxICON(unchecked_dis), 1, FALSE);
157     
158     m_iconDB.AddInfo("Radiobox", wxICON(radioon), 0, TRUE);
159     m_iconDB.AddInfo("Radiobox", wxICON(radioon_dis), 0, FALSE);
160     m_iconDB.AddInfo("Radiobox", wxICON(radiooff), 1, TRUE);
161     m_iconDB.AddInfo("Radiobox", wxICON(radiooff_dis), 1, FALSE);
162     
163     m_iconDB.AddInfo("Text", wxICON(text), 0, TRUE);
164     m_iconDB.AddInfo("Text", wxICON(text_dis), 0, FALSE);
165     
166     m_iconDB.AddInfo("Enumerated", wxICON(enumerated), 0, TRUE);
167     m_iconDB.AddInfo("Enumerated", wxICON(enumerated_dis), 0, FALSE);
168     
169     m_iconDB.AddInfo("Integer", wxICON(integer), 0, TRUE);
170     m_iconDB.AddInfo("Integer", wxICON(integer_dis), 0, FALSE);
171     
172 #if 0
173     // Add some dummy items
174     ecConfigItem* item = NULL;
175     wxTreeItemId rootId = AddRoot(_(""), -1, -1, new ecTreeItemData(item = new ecConfigItem(NULL, _("Configuration"), ecContainer)));
176     
177     item->SetTreeItem(rootId);
178     item->UpdateTreeItem(* this);
179     
180     wxTreeItemId childId1 = AppendItem(rootId, _(""), -1, -1, new ecTreeItemData(item = new ecConfigItem(item, _("My Package"), ecPackage, ecFlavorData, ecString)));
181     item->SetTreeItem(childId1);
182     item->GetValue() = _("v1_4_1");
183     item->UpdateTreeItem(* this);
184     
185     wxTreeItemId childId2 = AppendItem(childId1, _(""), -1, -1, new ecTreeItemData(item = new ecConfigItem(item, _("Option 1"), ecOption, ecFlavorData, ecString)));
186     item->SetTreeItem(childId2);
187     item->GetValue() = _("The value for this option");
188     item->UpdateTreeItem(* this);
189     
190     childId2 = AppendItem(childId1, _(""), -1, -1, new ecTreeItemData(item = new ecConfigItem(item, _("Option 2"), ecOption, ecFlavorData, ecLong)));
191     item->SetTreeItem(childId2);
192     item->GetValue() = (long) 176343;
193     item->UpdateTreeItem(* this);
194     
195     childId2 = AppendItem(childId2, _(""), -1, -1, new ecTreeItemData(item = new ecConfigItem(item, _("Option 3"), ecOption, ecFlavorBool, ecOptionTypeNone, TRUE, TRUE, ecHintCheck)));
196     item->SetTreeItem(childId2);
197     item->GetValue() = (bool) TRUE;
198     item->UpdateTreeItem(* this);
199     
200     childId2 = AppendItem(childId1, _(""), -1, -1, new ecTreeItemData(item = new ecConfigItem(item, _("Option 4"), ecOption, ecFlavorBool, ecOptionTypeNone, TRUE, FALSE, ecHintCheck)));
201     item->SetTreeItem(childId2);
202     item->UpdateTreeItem(* this);
203     
204     childId2 = AppendItem(childId1, _(""), -1, -1, new ecTreeItemData(item = new ecConfigItem(item, _("Option 5"), ecOption, ecFlavorBool, ecOptionTypeNone, TRUE, TRUE, ecHintRadio)));
205     item->SetTreeItem(childId2);
206     item->UpdateTreeItem(* this);
207     
208     childId2 = AppendItem(childId1, _(""), -1, -1, new ecTreeItemData(item = new ecConfigItem(item, _("Option 6"), ecOption, ecFlavorBool, ecOptionTypeNone, TRUE, FALSE, ecHintRadio)));
209     item->SetTreeItem(childId2);
210     item->GetValue() = (bool) TRUE ;
211     item->UpdateTreeItem(* this);
212     
213     // Another branch
214     childId1 = AppendItem(rootId, _(""), -1, -1, new ecTreeItemData(item = new ecConfigItem(item, _("My Container"), ecContainer)));
215     item->SetTreeItem(childId1);
216     item->UpdateTreeItem(* this);
217     
218     childId2 = AppendItem(childId1, _(""), -1, -1, new ecTreeItemData(item = new ecConfigItem(item, _("Option 1"), ecOption, ecFlavorData, ecString, FALSE)));
219     item->SetTreeItem(childId2);
220     item->GetValue() = _("The value for this option");
221     item->UpdateTreeItem(* this);
222     
223     childId2 = AppendItem(childId1, _(""), -1, -1, new ecTreeItemData(item = new ecConfigItem(item, _("Option 2"), ecOption, ecFlavorData, ecLong, FALSE)));
224     item->SetTreeItem(childId2);
225     item->GetValue() = (long) 176343;
226     item->UpdateTreeItem(* this);
227     
228     childId2 = AppendItem(childId1, _(""), -1, -1, new ecTreeItemData(item = new ecConfigItem(item, _("Option 3"), ecOption, ecFlavorBool, ecOptionTypeNone, FALSE, TRUE, ecHintCheck)));
229     item->SetTreeItem(childId2);
230     item->GetValue() = (bool) TRUE;
231     item->UpdateTreeItem(* this);
232     
233     childId2 = AppendItem(childId1, _(""), -1, -1, new ecTreeItemData(item = new ecConfigItem(item, _("Option 4"), ecOption, ecFlavorBool, ecOptionTypeNone, FALSE, FALSE, ecHintCheck)));
234     item->SetTreeItem(childId2);
235     item->UpdateTreeItem(* this);
236     
237     childId2 = AppendItem(childId1, _(""), -1, -1, new ecTreeItemData(item = new ecConfigItem(item, _("Option 5"), ecOption, ecFlavorBool, ecOptionTypeNone, FALSE, TRUE, ecHintRadio)));
238     item->SetTreeItem(childId2);
239     item->UpdateTreeItem(* this);
240     
241     childId2 = AppendItem(childId1, _(""), -1, -1, new ecTreeItemData(item = new ecConfigItem(item, _("Option 6"), ecOption, ecFlavorBool, ecOptionTypeNone, FALSE, FALSE, ecHintRadio)));
242     item->SetTreeItem(childId2);
243     item->GetValue() = (bool) TRUE ;
244     item->UpdateTreeItem(* this);
245     
246     Expand(rootId);
247 #endif
248 }
249
250 ecConfigTreeCtrl::~ecConfigTreeCtrl()
251 {
252     delete m_propertiesMenu;
253     
254     SetImageList(NULL);
255     delete m_imageList;
256 }
257
258 // Draw the lines on top of the tree
259 void ecConfigTreeCtrl::OnPaint(wxPaintEvent& event)
260 {
261     wxPaintDC dc(this);
262     
263     wxTreeCtrl::OnPaint(event);
264     
265     // Reset the device origin since it may have been set
266     dc.SetDeviceOrigin(0, 0);
267     
268     wxSize sz = GetClientSize();
269     
270     wxPen pen(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT), 1, wxSOLID);
271     dc.SetPen(pen);
272     dc.SetBrush(* wxTRANSPARENT_BRUSH);
273     
274     wxSize clientSize = GetClientSize();
275     wxRect itemRect;
276     int cy=0;
277     wxTreeItemId h, lastH;
278     for(h=GetFirstVisibleItem();h;h=GetNextVisible(h))
279     {
280         if (GetBoundingRect(h, itemRect))
281         {
282             cy = itemRect.GetTop();
283             dc.DrawLine(0, cy, clientSize.x, cy);
284             lastH = h;
285         }
286     }
287     
288     if (lastH && lastH.IsOk() && GetBoundingRect(lastH, itemRect))
289     {
290         cy = itemRect.GetBottom();
291         dc.DrawLine(0, cy, clientSize.x, cy);
292     }
293 }
294
295 void ecConfigTreeCtrl::OnSelChanged(wxTreeEvent& event)
296 {
297     ecConfigToolDoc* doc = wxGetApp().GetConfigToolDoc();
298     if (doc)
299     {
300         ecConfigToolHint hint(NULL, ecSelChanged);
301         doc->UpdateAllViews(NULL, & hint);
302     }
303 }
304
305 void ecConfigTreeCtrl::OnMouseEvent(wxMouseEvent& event)
306 {
307     int flags = 0;
308     wxTreeItemId item = HitTest(wxPoint(event.GetX(), event.GetY()), flags);
309     
310     if (item == 0 || !item.IsOk())
311     {
312         if (event.RightDown())
313             PopupMenu(wxGetApp().GetWhatsThisMenu(), event.GetX(), event.GetY());
314         return;
315     }
316     
317     if (event.LeftDown())
318     {
319         if (flags & wxTREE_HITTEST_ONITEMICON)
320         {
321             ecTreeItemData* data = (ecTreeItemData*) GetItemData(item);
322             data->GetConfigItem()->OnIconLeftDown(* this);
323         }
324     }
325     else if (event.RightDown())
326     {
327         if ((flags & wxTREE_HITTEST_ONITEMBUTTON) ||
328             (flags & wxTREE_HITTEST_ONITEMICON) ||
329             (flags & wxTREE_HITTEST_ONITEMINDENT) ||
330             (flags & wxTREE_HITTEST_ONITEMLABEL))
331         {
332             SelectItem(item);
333             GetPropertiesMenu()->SetClientData((void*) TRUE);
334             PopupMenu(GetPropertiesMenu(), event.GetX(), event.GetY());
335         }
336         else
337         {
338             wxGetApp().GetWhatsThisMenu()->SetClientData((void*) FALSE);
339             PopupMenu(wxGetApp().GetWhatsThisMenu(), event.GetX(), event.GetY());
340         }
341         return;
342     }
343     event.Skip();
344 }
345
346 void ecConfigTreeCtrl::OnKeyDown(wxKeyEvent& event)
347 {
348     wxTreeItemId id = GetSelection();
349     if (event.GetKeyCode() == WXK_F10 && event.ShiftDown())
350     {
351         if (id.IsOk())
352         {
353             wxRect rect;
354             if (GetBoundingRect(id, rect))
355             {
356                 GetPropertiesMenu()->SetClientData((void*) TRUE);
357                 PopupMenu(GetPropertiesMenu(), 100, rect.GetTop() + 4);
358             }
359         }
360     }
361     else if (event.GetKeyCode() == '<')
362     {
363         if (id.IsOk())
364         {
365             ecConfigItem* item = ((ecTreeItemData*) GetItemData(id))->GetConfigItem();
366             item->BumpItem(-1);
367         }
368     }
369     else if (event.GetKeyCode() == '>')
370     {
371         if (id.IsOk())
372         {
373             ecConfigItem* item = ((ecTreeItemData*) GetItemData(id))->GetConfigItem();
374             item->BumpItem(+1);
375         }        
376     }
377     else if (event.GetKeyCode() == WXK_SPACE)
378     {
379         if (id.IsOk())
380         {
381             ecConfigItem* item = ((ecTreeItemData*) GetItemData(id))->GetConfigItem();
382             item->BumpItem(0);
383         }
384     }
385     else if (event.GetKeyCode() == WXK_RETURN && event.AltDown())
386     {
387         if (id.IsOk())
388         {
389             ecConfigItem* item = ((ecTreeItemData*) GetItemData(id))->GetConfigItem();
390             
391             ecConfigPropertiesDialog dialog(wxGetApp().GetTopWindow(), item);
392             dialog.SetTitle(item->GetName());
393             dialog.ShowModal();
394         }
395     }
396     else
397     {
398         event.Skip();
399     }
400 }
401
402 void ecConfigTreeCtrl::OnCollapseExpand(wxTreeEvent& event)
403 {
404     if (GetCompanionWindow())
405         GetCompanionWindow()->Refresh();
406 }
407
408 // show help for this window
409 void ecConfigTreeCtrl::OnHelp(wxHelpEvent& event)
410 {
411     wxPoint pt = ScreenToClient(event.GetPosition());
412     int flags = 0;
413     wxTreeItemId id = HitTest(pt, flags);
414     wxHelpProvider *helpProvider = wxHelpProvider::Get();
415     if ( helpProvider && id > 0)
416     {
417         ecConfigItem* item = ((ecTreeItemData*) GetItemData(id))->GetConfigItem();
418
419         if (item)
420         {
421             wxGetApp().GetHelpController().DisplayTextPopup(item->GetDescription(), event.GetPosition());
422             return;
423         }
424     }
425
426     event.Skip();
427 }
428
429 /*
430 * ecValueWindow
431 */
432
433 IMPLEMENT_CLASS(ecValueWindow, wxTreeCompanionWindow)
434
435 BEGIN_EVENT_TABLE(ecValueWindow, wxTreeCompanionWindow)
436     EVT_PAINT(ecValueWindow::OnPaint)
437     EVT_MOUSE_EVENTS(ecValueWindow::OnMouseEvent)
438     EVT_SCROLLWIN(ecValueWindow::OnScroll)
439     EVT_TREE_ITEM_EXPANDED(-1, ecValueWindow::OnExpand)
440     EVT_TREE_ITEM_COLLAPSED(-1, ecValueWindow::OnExpand)
441 END_EVENT_TABLE()
442
443 ecValueWindow::ecValueWindow(wxWindow* parent, wxWindowID id,
444                              const wxPoint& pos,
445                              const wxSize& sz,
446                              long style):
447 wxTreeCompanionWindow(parent, id, pos, sz, style)
448 {
449     SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_LISTBOX));
450
451     if (!wxGetApp().GetSettings().GetWindowSettings().GetUseDefaults() &&
452          wxGetApp().GetSettings().GetWindowSettings().GetFont(wxT("Configuration")).Ok())
453     {
454         SetFont(wxGetApp().GetSettings().GetWindowSettings().GetFont(wxT("Configuration")));
455     }
456     else
457         SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
458
459     
460     m_editWindow = NULL;
461     m_configItem = NULL;
462 }
463
464 void ecValueWindow::OnPaint(wxPaintEvent& event)
465 {
466     wxPaintDC dc(this);
467     
468     if (!m_treeCtrl)
469         return;
470     
471     wxPen pen(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT), 1, wxSOLID);
472     dc.SetPen(pen);
473     dc.SetBrush(* wxTRANSPARENT_BRUSH);
474     wxFont font(GetFont());
475     dc.SetFont(font);
476     //dc.SetTextForeground(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT));
477     dc.SetBackgroundMode(wxTRANSPARENT);
478     
479     wxSize clientSize = GetClientSize();
480     wxRect itemRect;
481     int cy=0;
482     wxTreeItemId h, lastH;
483     for(h=m_treeCtrl->GetFirstVisibleItem();h;h=m_treeCtrl->GetNextVisible(h))
484     {
485         if (m_treeCtrl->GetBoundingRect(h, itemRect))
486         {
487             cy = itemRect.GetTop();
488             wxRect drawItemRect(0, cy, clientSize.x, itemRect.GetHeight());
489             
490             lastH = h;
491             
492             // Draw the actual item
493             DrawItem(dc, h, drawItemRect);
494             dc.DrawLine(0, cy, clientSize.x, cy);
495         }
496     }
497     if (lastH && lastH.IsOk() && m_treeCtrl->GetBoundingRect(lastH, itemRect))
498     {
499         cy = itemRect.GetBottom();
500         dc.DrawLine(0, cy, clientSize.x, cy);
501     }
502 }
503
504 // Returns the rectangle which will enclose the value for this tree item
505 wxRect ecValueWindow::GetItemRect(ecConfigItem* item)
506 {
507     if (!m_treeCtrl)
508         return wxRect(0, 0, 0, 0);
509     
510     wxSize clientSize = GetClientSize();
511     wxRect itemRect;
512     int cy=0;
513     wxTreeItemId h;
514     for(h=m_treeCtrl->GetFirstVisibleItem();h;h=m_treeCtrl->GetNextVisible(h))
515     {
516         ecTreeItemData* data = (ecTreeItemData*) m_treeCtrl->GetItemData(h);
517         if (data->GetConfigItem() == item)
518         {
519             if (m_treeCtrl->GetBoundingRect(h, itemRect))
520             {
521                 cy = itemRect.GetTop();
522                 wxRect drawItemRect(0, cy, clientSize.x, itemRect.GetHeight());
523                 return drawItemRect;
524             }
525             else
526                 return wxRect(0, 0, 0, 0);
527         }
528     }
529     return wxRect(0, 0, 0, 0);
530 }
531
532 void ecValueWindow::OnMouseEvent(wxMouseEvent& event)
533 {
534     if (event.LeftDown() && (event.GetX() > 2))
535     {
536         // Find if this corresponds to a tree item
537         int flags = 0;
538         wxTreeItemId item = m_treeCtrl->HitTest(wxPoint(4, event.GetY()), flags);
539         if (item.IsOk())
540         {
541             m_treeCtrl->SelectItem(item);
542             ecConfigItem* configItem = ((ecTreeItemData*) m_treeCtrl->GetItemData(item))->GetConfigItem();
543             if (configItem->CanEdit())
544                 BeginEditing(configItem);            
545         }
546     }
547     else if (event.RightDown())
548     {
549         // Find if this corresponds to a tree item
550         int flags = 0;
551         wxTreeItemId item = m_treeCtrl->HitTest(wxPoint(4, event.GetY()), flags);
552         if (item != 0)
553         {
554             ecConfigItem* configItem = ((ecTreeItemData*) m_treeCtrl->GetItemData(item))->GetConfigItem();
555             m_treeCtrl->SelectItem(item);
556             ((ecConfigTreeCtrl*) m_treeCtrl)->GetPropertiesMenu()->SetClientData((void*) TRUE);
557             PopupMenu(((ecConfigTreeCtrl*) m_treeCtrl)->GetPropertiesMenu(), event.GetX(), event.GetY());
558         }
559         else
560         {
561             wxGetApp().GetWhatsThisMenu()->SetClientData((void*) FALSE);
562             PopupMenu(wxGetApp().GetWhatsThisMenu(), event.GetX(), event.GetY());
563         }
564     }
565 }
566
567 void ecValueWindow::DrawItem(wxDC& dc, wxTreeItemId id, const wxRect& rect)
568 {
569     if (m_treeCtrl)
570     {
571         ecConfigItem* item = ((ecTreeItemData*) m_treeCtrl->GetItemData(id))->GetConfigItem();
572         if (!item)
573             return;
574         wxString text = item->GetDisplayValue();
575         
576         if (text.IsEmpty())
577             return;
578         
579         static wxColour normalColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT);
580         static wxColour disabledColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_GRAYTEXT);
581         dc.SetTextForeground( (item->GetActive() && (item->GetConfigType() != ecPackage)) ? normalColour : disabledColour );
582         
583         int textW, textH;
584         dc.GetTextExtent(text, & textW, & textH);
585         
586         int x = 2;
587         int y = rect.GetY() + wxMax(0, (rect.GetHeight() - textH) / 2);
588         
589         dc.DrawText(text, x, y);
590     }
591 }
592
593 bool ecValueWindow::BeginEditing(ecConfigItem* item)
594 {
595     if (m_configItem)
596         EndEditing();
597     
598     m_configItem = item;
599     
600     m_editWindow = item->CreateEditWindow(this);
601     if (m_editWindow)
602     {
603         m_editWindow->Show(FALSE);
604         
605         item->TransferDataToWindow(m_editWindow);
606         
607         // Position the control
608         PositionEditWindow();
609         
610         m_editWindow->Show(TRUE);
611         m_editWindow->SetFocus();
612         
613         return TRUE;
614     }
615     else
616     {
617         m_configItem = NULL;
618         return FALSE;
619     }
620 }
621
622 // Position the control
623 void ecValueWindow::PositionEditWindow()
624 {
625     if (!m_configItem || !m_editWindow)
626         return;
627     
628     // Position the control
629     wxSize clientSize = GetClientSize();
630     wxRect itemRect;
631     m_treeCtrl->GetBoundingRect(m_configItem->GetTreeItem(), itemRect);
632
633     wxSize sz = m_editWindow->GetSize();
634
635     // m_editWindow->SetSize(2, itemRect.y+1, clientSize.x, itemRect.GetHeight() /* -2 */);
636     m_editWindow->SetSize(0, itemRect.y, clientSize.x, sz.y);
637 }
638
639 bool ecValueWindow::EndEditing()
640 {
641     if (m_configItem)
642     {
643         if (m_editWindow && !wxGetApp().GetValuesLocked())
644             m_configItem->TransferDataFromWindow(m_editWindow);
645         m_configItem = NULL;
646     }
647     
648     if (m_editWindow)
649     {
650         delete m_editWindow;
651         m_editWindow = NULL;
652     }
653     
654     return TRUE;
655 }
656
657 void ecValueWindow::OnScroll(wxScrollWinEvent& event)
658 {
659     wxTreeCompanionWindow::OnScroll(event);
660     
661     PositionEditWindow();
662 }
663
664 void ecValueWindow::OnExpand(wxTreeEvent& event)
665 {
666     wxTreeCompanionWindow::OnExpand(event);
667     
668     EndEditing();
669 }
670
671 /*
672 * wxIconStateInfo
673 */
674
675 wxIconStateInfo::wxIconStateInfo(const wxString& name)
676 {
677     m_maxStates = 0;
678     m_name = name;
679     int i;
680     for (i = 0; i < wxMAX_ICON_STATES; i++)
681         m_states[i] = 0;
682 }
683
684 int wxIconStateInfo::GetIconId(int state, bool enabled) const
685 {
686     wxASSERT ( state < (wxMAX_ICON_STATES * 2) );
687     wxASSERT ( state < m_maxStates );
688     
689     return m_states[state * 2 + (enabled ? 0 : 1)];
690 }
691
692 void wxIconStateInfo::SetIconId(int state, bool enabled, int iconId)
693 {
694     wxASSERT ( state < (wxMAX_ICON_STATES * 2) );
695     if (state+1 > m_maxStates)
696         m_maxStates = state+1;
697     
698     m_states[state * 2 + (enabled ? 0 : 1)] = iconId;
699 }
700
701 /*
702 * wxIconStateInfoDb
703 * Contains a list of wxIconStateInfos
704 */
705
706 wxIconStateInfoDB::wxIconStateInfoDB(wxImageList* imageList)
707 {
708     m_imageList = imageList;
709     DeleteContents(TRUE);
710 }
711
712 void wxIconStateInfoDB::AppendInfo(wxIconStateInfo* info)
713 {
714     Append(info);
715 }
716
717 // Easy way of initialising both the image list and the
718 // info db. It will generate image ids itself while appending the icon.
719 bool wxIconStateInfoDB::AddInfo(const wxString& name, const wxIcon& icon, int state, bool enabled)
720 {
721     wxASSERT (m_imageList != NULL);
722     
723     wxIconStateInfo* info = FindInfo(name);
724     if (!info)
725     {
726         info = new wxIconStateInfo(name);
727         Append(info);
728     }
729     info->SetIconId(state, enabled, m_imageList->Add(icon));
730     return TRUE;
731 }
732
733 wxIconStateInfo* wxIconStateInfoDB::FindInfo(const wxString& name) const
734 {
735     wxNode* node = First();
736     while (node)
737     {
738         wxIconStateInfo* info = (wxIconStateInfo*) node->Data();
739         if (info->GetName() == name)
740             return info;
741         node = node->Next();
742     }
743     return NULL;
744 }
745
746 int wxIconStateInfoDB::GetIconId(const wxString& name, int state, bool enabled) const
747 {
748     wxIconStateInfo* info = FindInfo(name);
749     if (!info)
750         return -1;
751     return info->GetIconId(state, enabled);
752 }
753
754 bool wxIconStateInfoDB::SetIconId(const wxString& name, int state, bool enabled, int iconId)
755 {
756     wxIconStateInfo* info = FindInfo(name);
757     if (!info)
758         return FALSE;
759     info->SetIconId(state, enabled, iconId);
760     return TRUE;
761 }
762
763 #if 0
764 wxIcon wxIconStateInfoDB::GetIcon(const wxString& name, int state, bool enabled) const
765 {
766     wxASSERT( m_imageList != NULL );
767     
768     wxIconStateInfo* info = FindInfo(name);
769     if (!info)
770         return wxNullIcon;
771     int id = info->GetIconId(state, enabled);
772     if (id < 0)
773         return wxNullIcon;
774     else
775         return m_imageList->GetImage(id); // Doesn't exist
776 }
777 #endif
778
779 /*
780 * ecSplitterScrolledWindow
781 * This window holds the tree and value windows.
782 * We derive a new class mainly to intercept popup menu commands from both child windows
783 * without resorting to placing their handlers in the main frame.
784 */
785
786 BEGIN_EVENT_TABLE(ecSplitterScrolledWindow, wxSplitterScrolledWindow)
787     EVT_MENU(ecID_WHATS_THIS, ecSplitterScrolledWindow::OnWhatsThis)
788     EVT_MENU(ecID_TREE_PROPERTIES, ecSplitterScrolledWindow::OnProperties)
789     EVT_MENU(ecID_TREE_RESTORE_DEFAULTS, ecSplitterScrolledWindow::OnRestoreDefaults)
790     EVT_MENU(ecID_TREE_VISIT_DOC, ecSplitterScrolledWindow::OnVisitDoc)
791     EVT_MENU(ecID_TREE_VIEW_HEADER, ecSplitterScrolledWindow::OnViewHeader)
792     EVT_MENU(ecID_TREE_UNLOAD_PACKAGE, ecSplitterScrolledWindow::OnUnloadPackage)
793
794     EVT_UPDATE_UI(ecID_TREE_RESTORE_DEFAULTS, ecSplitterScrolledWindow::OnUpdateRestoreDefaults)
795     EVT_UPDATE_UI(ecID_TREE_VISIT_DOC, ecSplitterScrolledWindow::OnUpdateVisitDoc)
796     EVT_UPDATE_UI(ecID_TREE_VIEW_HEADER, ecSplitterScrolledWindow::OnUpdateViewHeader)
797     EVT_UPDATE_UI(ecID_TREE_UNLOAD_PACKAGE, ecSplitterScrolledWindow::OnUpdateUnloadPackage)
798 END_EVENT_TABLE()
799
800 static bool ecIsMenuForItem(wxCommandEvent& event)
801 {
802     wxObject* obj = event.GetEventObject();
803     wxMenu* menu = NULL;
804
805     if (obj->IsKindOf(CLASSINFO(wxMenu)))
806     {
807         // Menu has some client data which tells us if the menu was clicked over an item
808         // or not
809         menu = (wxMenu*) obj;
810         return (bool) (menu->GetClientData() != 0) ;
811     }
812     else
813         return FALSE;
814 }
815
816 void ecSplitterScrolledWindow::OnWhatsThis(wxCommandEvent& event)
817 {
818     ecConfigTreeCtrl* treeCtrl = (ecConfigTreeCtrl*) FindWindow(ecID_TREE_CTRL);
819     wxASSERT (treeCtrl != NULL) ;
820
821     wxTreeItemId id = treeCtrl->GetSelection();
822     if (id != 0 && ecIsMenuForItem(event))
823     {
824         ecConfigItem* item = ((ecTreeItemData*) treeCtrl->GetItemData(id))->GetConfigItem();
825         
826         wxPoint pt = wxGetMousePosition();
827         wxString msg;
828         msg.Printf("Popping at %d x %d", pt.x, pt.y);
829         wxLogDebug(msg);
830
831         wxGetApp().GetHelpController().DisplayTextPopup(item->GetDescription(), wxGetMousePosition());
832     }
833     else
834         event.Skip();
835 }
836
837 void ecSplitterScrolledWindow::OnProperties(wxCommandEvent& event)
838 {
839     wxObject* obj = event.GetEventObject();
840     wxMenu* menu = NULL;
841
842     if (obj->IsKindOf(CLASSINFO(wxMenu)))
843     {
844         // Menu has some client data which tells us if the menu was clicked over an item
845         // or not
846         menu = (wxMenu*) obj;
847     }
848
849     ecConfigTreeCtrl* treeCtrl = (ecConfigTreeCtrl*) FindWindow(ecID_TREE_CTRL);
850     wxASSERT (treeCtrl != NULL) ;
851     
852     wxTreeItemId id = treeCtrl->GetSelection();
853     if (id != 0 && ecIsMenuForItem(event))
854     {
855         ecConfigItem* item = ((ecTreeItemData*) treeCtrl->GetItemData(id))->GetConfigItem();
856         
857         ecConfigPropertiesDialog dialog(wxGetApp().GetTopWindow(), item);
858         dialog.SetTitle(item->GetName());
859         dialog.ShowModal();
860     }
861 }
862
863 void ecSplitterScrolledWindow::OnRestoreDefaults(wxCommandEvent& event)
864 {
865     ecConfigTreeCtrl* treeCtrl = (ecConfigTreeCtrl*) FindWindow(ecID_TREE_CTRL);
866     wxASSERT (treeCtrl != NULL) ;
867     
868     wxTreeItemId id = treeCtrl->GetSelection();
869     if (id != 0 && ecIsMenuForItem(event))
870     {
871         ecConfigItem* item = ((ecTreeItemData*) treeCtrl->GetItemData(id))->GetConfigItem();
872         if (item->HasModifiedChildren())
873         {
874             int ans = wxMessageBox(_("Restore defaults for nested items?"), wxGetApp().GetSettings().GetAppName(), wxYES_NO|wxCANCEL|wxICON_QUESTION);
875             switch (ans)
876             {
877             case wxYES:
878                 RestoreDefault(id, TRUE);
879                 break;
880             case wxNO:
881                 RestoreDefault(id, FALSE);
882                 break;
883             case wxCANCEL:
884                 break;
885             default:
886                 wxASSERT(FALSE);
887                 break;
888             }
889         }
890         else
891         {
892             RestoreDefault(id, FALSE);
893         }
894         // current values may have changed so refresh the other views
895         wxGetApp().GetConfigToolDoc ()->UpdateFailingRuleCount ();
896         
897         if (item->GetOptionType () != ecOptionTypeNone)
898         {
899             ecConfigToolHint hint(item, ecValueChanged);
900             wxGetApp().GetConfigToolDoc ()->UpdateAllViews (NULL, & hint);
901         }
902     }
903 }
904
905 void ecSplitterScrolledWindow::RestoreDefault(wxTreeItemId h, bool bRecurse /* = FALSE */, bool bTopLevel /* = TRUE */)
906 {
907     ecConfigTreeCtrl* treeCtrl = (ecConfigTreeCtrl*) FindWindow(ecID_TREE_CTRL);
908     wxASSERT (treeCtrl != NULL) ;
909
910     ecConfigItem* ti = ((ecTreeItemData*) treeCtrl->GetItemData(h))->GetConfigItem();
911
912     const CdlValuable valuable = ti->GetCdlValuable();
913
914     if (valuable && (CdlValueFlavor_None != valuable->get_flavor ())) // skip the root node and nodes without a value
915         valuable->set_source (CdlValueSource_Default);
916     treeCtrl->SetItemText (h, ti->GetItemNameOrMacro ()); // remove asterisk in control view
917     
918     if (bTopLevel && ti->HasRadio ()) // if user-specified item is a radio button
919     {
920         for (ecConfigItem * pItem = ti->FirstRadio (); pItem; pItem = pItem->NextRadio ())
921         {
922             if (ti != pItem)
923             {
924                 const CdlValuable valuable = pItem->GetCdlValuable();
925                 wxASSERT (valuable);
926                 valuable->set_source (CdlValueSource_Default); // restore default for each sibling radio button
927                 treeCtrl->SetItemText (pItem->GetTreeItem(), pItem->GetItemNameOrMacro ()); // remove asterisk in control view
928             }
929             
930         }
931     }
932     
933     if (bRecurse)
934     {
935         long cookie;
936         for (h = treeCtrl->GetFirstChild(h, cookie); h; h = treeCtrl->GetNextSibling(h))
937         {
938             RestoreDefault (h, TRUE, FALSE);
939         }
940     }
941 }
942
943 void ecSplitterScrolledWindow::OnVisitDoc(wxCommandEvent& event)
944 {
945     ecConfigTreeCtrl* treeCtrl = (ecConfigTreeCtrl*) FindWindow(ecID_TREE_CTRL);
946     wxASSERT (treeCtrl != NULL) ;
947
948     wxTreeItemId id = treeCtrl->GetSelection();
949     if (id != 0 && ecIsMenuForItem(event))
950     {
951         ecConfigItem* item = ((ecTreeItemData*) treeCtrl->GetItemData(id))->GetConfigItem();
952         
953         item->ViewURL();
954     }
955     else
956         event.Skip();
957 }
958
959 void ecSplitterScrolledWindow::OnViewHeader(wxCommandEvent& event)
960 {
961     ecConfigTreeCtrl* treeCtrl = (ecConfigTreeCtrl*) FindWindow(ecID_TREE_CTRL);
962     wxASSERT (treeCtrl != NULL) ;
963
964     wxTreeItemId id = treeCtrl->GetSelection();
965     if (id != 0 && ecIsMenuForItem(event))
966     {
967         ecConfigItem* item = ((ecTreeItemData*) treeCtrl->GetItemData(id))->GetConfigItem();
968         
969         item->ViewHeader();
970     }
971     else
972         event.Skip();
973 }
974
975 void ecSplitterScrolledWindow::OnUnloadPackage(wxCommandEvent& event)
976 {
977     ecConfigTreeCtrl* treeCtrl = (ecConfigTreeCtrl*) FindWindow(ecID_TREE_CTRL);
978     wxASSERT (treeCtrl != NULL) ;
979
980     wxTreeItemId id = treeCtrl->GetSelection();
981     if (id != 0)
982     {
983         ecConfigItem* item = ((ecTreeItemData*) treeCtrl->GetItemData(id))->GetConfigItem();
984         
985         if (wxYES == wxMessageBox(_("Are you sure you wish to unload this package?"), wxGetApp().GetSettings().GetAppName(),
986                 wxYES_NO|wxICON_QUESTION))
987         {
988             item->Unload();
989             wxGetApp().GetConfigToolDoc()->RegenerateData();
990         }
991     }
992 }
993
994 void ecSplitterScrolledWindow::OnUpdateRestoreDefaults(wxUpdateUIEvent& event)
995 {
996     ecConfigTreeCtrl* treeCtrl = (ecConfigTreeCtrl*) FindWindow(ecID_TREE_CTRL);
997     wxASSERT (treeCtrl != NULL) ;
998
999     wxTreeItemId id = treeCtrl->GetSelection();
1000     if (id != 0)
1001     {
1002         ecConfigItem* item = ((ecTreeItemData*) treeCtrl->GetItemData(id))->GetConfigItem();
1003         
1004         event.Enable( IsChanged(id, TRUE ) );
1005     }
1006 }
1007
1008 void ecSplitterScrolledWindow::OnUpdateVisitDoc(wxUpdateUIEvent& event)
1009 {
1010     event.Enable( TRUE );
1011 }
1012
1013 void ecSplitterScrolledWindow::OnUpdateViewHeader(wxUpdateUIEvent& event)
1014 {
1015     ecConfigToolDoc *pDoc=wxGetApp().GetConfigToolDoc();
1016     event.Enable( pDoc && !pDoc->GetBuildTree().IsEmpty() ) ;
1017 }
1018
1019 void ecSplitterScrolledWindow::OnUpdateUnloadPackage(wxUpdateUIEvent& event)
1020 {
1021     ecConfigTreeCtrl* treeCtrl = (ecConfigTreeCtrl*) FindWindow(ecID_TREE_CTRL);
1022     wxASSERT (treeCtrl != NULL) ;
1023
1024     wxTreeItemId id = treeCtrl->GetSelection();
1025     if (id != 0)
1026     {
1027         ecConfigItem* item = ((ecTreeItemData*) treeCtrl->GetItemData(id))->GetConfigItem();
1028         
1029         event.Enable( item->IsPackage() );
1030     }
1031 }
1032
1033 bool ecSplitterScrolledWindow::IsChanged(wxTreeItemId id, bool bRecurse)
1034 {
1035     ecConfigTreeCtrl* treeCtrl = (ecConfigTreeCtrl*) FindWindow(ecID_TREE_CTRL);
1036     wxASSERT (treeCtrl != NULL) ;
1037
1038     ecConfigItem* item = ((ecTreeItemData*) treeCtrl->GetItemData(id))->GetConfigItem();
1039     bool rc = item->Modified ();
1040
1041     if(!rc && bRecurse)
1042     {
1043         long cookie;
1044         for (id=treeCtrl->GetFirstChild(id, cookie);id;id=treeCtrl->GetNextSibling(id))
1045         {
1046             if (IsChanged(id,TRUE))
1047             {
1048                 rc=TRUE;
1049                 break;
1050             }
1051         }
1052     }
1053     return rc;
1054 }