home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / contrib / utils / wxrcedit / editor.cpp < prev    next >
C/C++ Source or Header  |  2002-02-03  |  23KB  |  798 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Author:      Vaclav Slavik
  3. // Created:     2000/05/05
  4. // RCS-ID:      $Id: editor.cpp,v 1.18 2002/02/02 23:17:15 VS Exp $
  5. // Copyright:   (c) 2000 Vaclav Slavik
  6. // Licence:     wxWindows licence
  7. /////////////////////////////////////////////////////////////////////////////
  8.  
  9. #ifdef __GNUG__
  10.     #pragma implementation "editor.h"
  11.     #pragma implementation "treedt.h"
  12. #endif
  13.  
  14. // For compilers that support precompilation, includes "wx/wx.h".
  15. #include "wx/wxprec.h"
  16.  
  17. #ifdef __BORLANDC__
  18.     #pragma hdrstop
  19. #endif
  20.  
  21. #include "wx/wx.h"
  22. #include "wx/xrc/xml.h"
  23. #include "wx/xrc/xmlres.h"
  24. #include "wx/splitter.h"
  25. #include "wx/config.h"
  26. #include "wx/dir.h"
  27. #include "wx/listctrl.h"
  28. #include "wx/imaglist.h"
  29.  
  30. #include "treedt.h"
  31. #include "editor.h"
  32. #include "nodehnd.h"
  33. #include "xmlhelpr.h"
  34. #include "preview.h"
  35. #include "propframe.h"
  36.  
  37.  
  38. void wxXmlRcEditDocument::UpgradeNodeValue(wxXmlNode *node)
  39. {
  40.     wxXmlNode *n = node;
  41.     if (n == NULL) return;
  42.     n = n->GetChildren();
  43.  
  44.     while (n)
  45.     {
  46.         if (n->GetType() == wxXML_TEXT_NODE ||
  47.             n->GetType() == wxXML_CDATA_SECTION_NODE)
  48.         {
  49.             wxString str1 = n->GetContent();
  50.             const wxChar *dt;
  51.  
  52.             for (dt = str1.c_str(); *dt; dt++)
  53.             {
  54.                 // Remap amp_char to &, map double amp_char to amp_char (for things
  55.                 // like "&File..." -- this is illegal in XML, so we use "_File..."):
  56.                 if (*dt == '$')
  57.                 {
  58.                     if ( *(++dt) != '$' )
  59.                         str1[size_t(dt-str1.c_str()-1)] = '_';
  60.                 }
  61.             }
  62.             n->SetContent(str1);
  63.         }
  64.         n = n->GetNext();
  65.     }
  66. }
  67.  
  68. void wxXmlRcEditDocument::UpgradeNode(wxXmlNode *node)
  69. {
  70.     if (node)
  71.     {
  72.         UpgradeNodeValue(node);
  73.         UpgradeNode(node->GetNext());
  74.         UpgradeNode(node->GetChildren());
  75.     }
  76. }
  77.  
  78. void wxXmlRcEditDocument::Upgrade()
  79. {
  80.     int v1,v2,v3,v4;
  81.     long version;
  82.     wxXmlNode *node = GetRoot();
  83.     wxString verstr = wxT("0.0.0.0");
  84.     node->GetPropVal(wxT("version"),verstr);
  85.     if (wxSscanf(verstr.c_str(), wxT("%i.%i.%i.%i"),
  86.         &v1, &v2, &v3, &v4) == 4)
  87.         version = v1*256*256*256+v2*256*256+v3*256+v4;
  88.     else
  89.         version = 0;
  90.     if (!version)
  91.     {
  92.         UpgradeNode(node);
  93.     }
  94.     node->DeleteProperty(wxT("version"));
  95.     node->AddProperty(wxT("version"), wxT(WX_XMLRES_CURRENT_VERSION_STRING));
  96. }
  97.  
  98.  
  99. class EditorTreeCtrl : public wxTreeCtrl
  100. {
  101.     public:
  102.         EditorTreeCtrl(wxWindow *parent, int id, EditorFrame *frame)
  103.                  : wxTreeCtrl(parent, id), m_EdFrame(frame) {}
  104.                  
  105.     private:
  106.         EditorFrame *m_EdFrame;
  107.         
  108.         void OnRightClick(wxMouseEvent &event)
  109.         {
  110.             wxTreeItemId item = 
  111.                 m_EdFrame->m_TreeCtrl->HitTest(event.GetPosition());
  112.             if (item.IsOk())
  113.             {
  114.                 m_EdFrame->m_TreeCtrl->SelectItem(item);
  115.                 m_EdFrame->OnRightClickTree(event.GetPosition());
  116.             }
  117.         }
  118.         DECLARE_EVENT_TABLE()
  119. };
  120.  
  121. BEGIN_EVENT_TABLE(EditorTreeCtrl, wxTreeCtrl)
  122.     EVT_RIGHT_DOWN(EditorTreeCtrl::OnRightClick)
  123. END_EVENT_TABLE()
  124.  
  125.  
  126. enum 
  127. {
  128.     ID_PREVIEW = wxID_HIGHEST + 100,
  129.     ID_NEW,
  130.     ID_OPEN,
  131.     ID_CLOSE,
  132.     ID_SAVE,
  133.     ID_SAVEAS,
  134.     ID_DELETE_NODE,
  135.     ID_EXIT,
  136.     ID_TREE,    
  137.     
  138.     ID_CUT,
  139.     ID_PASTE_SYBLING,
  140.     ID_PASTE_CHILD,
  141.     ID_COPY,
  142.  
  143.     ID_NEWDIALOG,
  144.     ID_NEWPANEL,
  145.     ID_NEWMENU,
  146.     ID_NEWMENUBAR,
  147.     ID_NEWTOOLBAR,   
  148.     ID_NEWNODE = wxID_HIGHEST + 10000, // safely out of XRCID range :)
  149.     ID_NEWSYBNODE = ID_NEWNODE + 20000
  150. };
  151.  
  152.  
  153.  
  154.  
  155.  
  156. BEGIN_EVENT_TABLE(EditorFrame, wxFrame)
  157.     EVT_TREE_SEL_CHANGED(ID_TREE, EditorFrame::OnTreeSel)
  158.     EVT_TOOL_RANGE(ID_PREVIEW, ID_EXIT, EditorFrame::OnToolbar)
  159.     EVT_MENU_RANGE(ID_NEWDIALOG, ID_NEWSYBNODE + 1000, EditorFrame::OnNewNode)
  160.     EVT_MENU_RANGE(ID_CUT, ID_COPY, EditorFrame::OnClipboardAction)
  161.     EVT_CLOSE(EditorFrame::OnCloseWindow)
  162. END_EVENT_TABLE()
  163.  
  164.  
  165.  
  166. #if defined(__UNIX__)
  167. #include "bitmaps/preview.xpm"
  168. #include "bitmaps/close.xpm"
  169. #include "bitmaps/save.xpm"
  170. #include "bitmaps/open.xpm"
  171.  
  172. #include "bitmaps/control.xpm"
  173. #include "bitmaps/vsizer.xpm"
  174. #include "bitmaps/hsizer.xpm"
  175. #include "bitmaps/panel.xpm"
  176. #include "bitmaps/gsizer.xpm"
  177. #include "bitmaps/resicon.xpm"
  178. #endif
  179.  
  180.  
  181.  
  182. EditorFrame *EditorFrame::ms_Instance = NULL;
  183.  
  184. EditorFrame::EditorFrame(wxFrame *parent, const wxString& filename)
  185.     : wxFrame(parent, -1, filename + _("- wxWindows resources editor"))
  186. {
  187.     ms_Instance = this;
  188.  
  189.     m_Clipboard = NULL;
  190.     m_Modified = FALSE;
  191.     
  192.     wxConfigBase *cfg = wxConfigBase::Get();
  193.     
  194.     SetSize(wxRect(wxPoint(cfg->Read("editor_x", -1), cfg->Read("editor_y", -1)),
  195.             wxSize(cfg->Read("editor_w", 400), cfg->Read("editor_h", 400))));
  196.  
  197.     m_SelectedNode = NULL;
  198.     m_Resource = NULL;
  199.     m_FileName = wxEmptyString;
  200.  
  201.     wxMenu *menuFile = new wxMenu;
  202.     menuFile->Append(ID_NEW, "&New");
  203.     menuFile->Append(ID_OPEN, "&Open\tCtrl-O");
  204.     menuFile->Append(ID_SAVE, "&Save\tCtrl-S");
  205.     menuFile->Append(ID_SAVEAS, "Save &as...");
  206.     menuFile->AppendSeparator();
  207.     menuFile->Append(ID_EXIT, "E&xit\tAlt-X");
  208.  
  209.     wxMenu *menuEdit = new wxMenu;
  210.     menuEdit->Append(ID_CUT, "Cut\tCtrl-X");
  211.     menuEdit->Append(ID_COPY, "Copy\tCtrl-C");
  212.     menuEdit->Append(ID_PASTE_SYBLING, "Paste as sybling\tCtrl-V");
  213.     menuEdit->Append(ID_PASTE_CHILD, "Paste as child");
  214.     menuEdit->AppendSeparator();
  215.     menuEdit->Append(ID_DELETE_NODE,  "Delete");
  216.  
  217.     menuEdit->Enable(ID_PASTE_SYBLING, FALSE);
  218.     menuEdit->Enable(ID_PASTE_CHILD, FALSE);
  219.     
  220.     wxMenuBar *menuBar = new wxMenuBar();
  221.     menuBar->Append(menuFile, "&File");
  222.     menuBar->Append(menuEdit, "&Edit");
  223.     SetMenuBar(menuBar);
  224.   
  225.     // Create toolbar:
  226.     wxToolBar *toolBar = CreateToolBar(wxNO_BORDER | wxTB_HORIZONTAL | wxTB_FLAT);
  227.     toolBar->SetMargins(2, 2);
  228.     toolBar->SetToolBitmapSize(wxSize(24, 24));
  229.     toolBar -> AddTool(ID_EXIT, wxBITMAP(close), wxNullBitmap,
  230.                        FALSE, -1, -1, (wxObject *) NULL,
  231.                        _("Quit the editor"));
  232.     toolBar -> AddTool(ID_OPEN, wxBITMAP(open), wxNullBitmap,
  233.                        FALSE, -1, -1, (wxObject *) NULL,
  234.                        _("Open XML resource file"));   
  235.     toolBar -> AddTool(ID_SAVE, wxBITMAP(save), wxNullBitmap,
  236.                        FALSE, -1, -1, (wxObject *) NULL,
  237.                        _("Save XML file"));
  238.     toolBar -> AddTool(ID_PREVIEW, wxBITMAP(preview), wxNullBitmap,
  239.                        FALSE, -1, -1, (wxObject *) NULL,
  240.                        _("Preview"));   
  241.     toolBar -> Realize();
  242.  
  243.     wxSizer *sizer = new wxBoxSizer(wxHORIZONTAL);
  244.     
  245.     // Create tree control:
  246.     m_TreeCtrl = new EditorTreeCtrl(this, ID_TREE, this);
  247.     wxImageList *imgList = new wxImageList(16, 16);
  248.     imgList->Add(wxICON(control));
  249.     imgList->Add(wxICON(panel));
  250.     imgList->Add(wxICON(vsizer));
  251.     imgList->Add(wxICON(hsizer));
  252.     imgList->Add(wxICON(gsizer));
  253.     imgList->Add(wxICON(resicon));
  254.     m_TreeCtrl->AssignImageList(imgList);
  255.     sizer->Add(m_TreeCtrl, 1, wxEXPAND);
  256.  
  257.     SetAutoLayout(TRUE);
  258.     SetSizer(sizer);
  259.  
  260.     // Load file:
  261.     if (!filename)
  262.         NewFile();
  263.     else
  264.         LoadFile(filename);
  265. }
  266.  
  267.  
  268.  
  269. EditorFrame::~EditorFrame()
  270. {
  271.     PreviewFrame::Get()->Close();
  272.     PropertiesFrame::Get()->Close();
  273.  
  274.     wxConfigBase *cfg = wxConfigBase::Get();
  275.     
  276.     cfg->Write(_T("editor_x"), (long)GetPosition().x);
  277.     cfg->Write(_T("editor_y"), (long)GetPosition().y);
  278.     cfg->Write(_T("editor_w"), (long)GetSize().x);
  279.     cfg->Write(_T("editor_h"), (long)GetSize().y);
  280.  
  281.     delete m_Clipboard;
  282. }
  283.  
  284.  
  285.  
  286.  
  287. void EditorFrame::LoadFile(const wxString& filename)
  288. {
  289.     if (!AskToSave()) return;
  290.  
  291.     delete m_Resource;
  292.     
  293.      // create new resource in order to handle version differences properly
  294.     PreviewFrame::Get()->ResetResource();
  295.     
  296.     m_FileName = "";
  297.     m_Resource = new wxXmlRcEditDocument;
  298.     m_Modified = FALSE;
  299.     
  300.     if (!m_Resource->Load(filename,  wxLocale::GetSystemEncodingName()))
  301.     {
  302.         delete m_Resource;
  303.         m_Resource = NULL;
  304.         NewFile();
  305.         wxLogError("Error parsing " + filename);
  306.     }
  307.     else
  308.     {
  309.         m_FileName = filename;
  310.  
  311.         // Upgrades old versions
  312.         m_Resource->Upgrade();
  313.         RefreshTree();
  314.     }
  315.     RefreshTitle();
  316. }
  317.  
  318.  
  319.  
  320. void EditorFrame::SaveFile(const wxString& filename)
  321. {
  322.     m_FileName = filename;
  323.     
  324.     // save it:
  325.     if (!m_Resource->Save(filename))
  326.         wxLogError(_("Error saving ") + filename);
  327.     else
  328.         m_Modified = FALSE;
  329.  
  330.     RefreshTitle();
  331. }
  332.  
  333.  
  334.  
  335. void EditorFrame::NewFile()
  336. {  
  337.     if (!AskToSave()) return;
  338.  
  339.     delete m_Resource;
  340.     
  341.     m_FileName = "";
  342.     m_Resource = new wxXmlRcEditDocument;
  343.     m_Resource->SetRoot(new wxXmlNode(wxXML_ELEMENT_NODE, _("resource")));
  344.     
  345.     m_Modified = FALSE;
  346.     RefreshTree();
  347.     RefreshTitle();
  348. }
  349.  
  350.  
  351.  
  352. void EditorFrame::RefreshTitle()
  353. {
  354.     wxString s;
  355.     if (m_Modified) s << _T("* ");
  356.     s << _("wxrcedit");
  357.     if (m_FileName != "")
  358.         s << _T(" - ") << wxFileNameFromPath(m_FileName);
  359.     SetTitle(s);
  360. }
  361.  
  362.  
  363.  
  364. void EditorFrame::RefreshTree()
  365. {
  366.     wxXmlNode *sel = m_SelectedNode;
  367.     
  368.     m_TreeCtrl->DeleteAllItems(); 
  369.     wxTreeItemId root = m_TreeCtrl->AddRoot("Resource: " + wxFileNameFromPath(m_FileName), 5, 5);
  370.  
  371.     wxXmlNode *n = m_Resource->GetRoot()->GetChildren();  
  372.     while (n)
  373.     {
  374.         if (n->GetType() == wxXML_ELEMENT_NODE)
  375.             CreateTreeNode(m_TreeCtrl, root, n);
  376.         n = n->GetNext();
  377.     }
  378.  
  379.     m_TreeCtrl->Expand(root);
  380.     SelectNode(sel);
  381. }
  382.  
  383.  
  384.  
  385.  
  386. static void RecursivelyExpand(wxTreeCtrl *t, wxTreeItemId item)
  387. {
  388.     t->Expand(item);
  389.     long cookie;
  390.     wxTreeItemId id = t->GetFirstChild(item, cookie);
  391.     while (id.IsOk())
  392.     {
  393.         RecursivelyExpand(t, id);
  394.         id = t->GetNextChild(item, cookie);
  395.     }
  396. }
  397.  
  398. bool EditorFrame::SelectNode(wxXmlNode *node, wxTreeItemId *root)
  399. {
  400.     if (root == NULL)
  401.     {
  402.         wxTreeItemId rootitem = m_TreeCtrl->GetRootItem();
  403.         return SelectNode(node, &rootitem);
  404.     }
  405.  
  406.     wxTreeItemId item;
  407.     XmlTreeData *dt;
  408.     wxXmlNode *nd;
  409.     long cookie;
  410.     
  411.     item = m_TreeCtrl->GetFirstChild(*root, cookie);
  412.     while (item.IsOk())
  413.     {
  414.         dt = (XmlTreeData*)(m_TreeCtrl->GetItemData(item));
  415.         nd = (dt) ? dt->Node : NULL;
  416.         if (nd == node) 
  417.         {
  418.             RecursivelyExpand(m_TreeCtrl, *root);
  419.             m_TreeCtrl->SelectItem(item);
  420.             m_TreeCtrl->EnsureVisible(item);
  421.             return TRUE; 
  422.         }
  423.         if (m_TreeCtrl->ItemHasChildren(item) && SelectNode(node, &item)) 
  424.             return TRUE; 
  425.         item = m_TreeCtrl->GetNextChild(*root, cookie);
  426.     }
  427.  
  428.     return FALSE;
  429. }
  430.  
  431.  
  432.  
  433. wxTreeItemId EditorFrame::CreateTreeNode(wxTreeCtrl *treectrl, wxTreeItemId parent, wxXmlNode *node)
  434. {
  435.     if (!node) 
  436.     {
  437.         wxTreeItemId invalid;
  438.         return invalid;
  439.     }
  440.  
  441.     return NodeHandler::Find(node)->CreateTreeNode(treectrl, parent, node);
  442. }
  443.  
  444.  
  445.  
  446. void EditorFrame::NotifyChanged(int change_type)
  447. {
  448.     if (change_type & CHANGED_TREE)
  449.         RefreshTree();
  450.  
  451.     if (change_type & CHANGED_TREE_SELECTED)
  452.     {
  453.         wxTreeItemId sel = m_TreeCtrl->GetSelection();
  454.         m_TreeCtrl->SetItemText(sel, 
  455.              NodeHandler::Find(m_SelectedNode)->GetTreeString(m_SelectedNode));
  456.     }
  457.  
  458.     if (change_type & CHANGED_TREE_SELECTED_ICON)
  459.     {
  460.         wxTreeItemId sel = m_TreeCtrl->GetSelection();
  461.         int icon = NodeHandler::Find(m_SelectedNode)->GetTreeIcon(m_SelectedNode);
  462.         m_TreeCtrl->SetItemImage(sel, icon);
  463.     }
  464.     
  465.     if (!m_Modified)
  466.     {
  467.         m_Modified = TRUE;
  468.         RefreshTitle();
  469.     }
  470.     
  471.     PreviewFrame::Get()->MakeDirty();
  472. }
  473.  
  474.  
  475.  
  476. void EditorFrame::OnTreeSel(wxTreeEvent& event)
  477. {
  478.     XmlTreeData *dt = (XmlTreeData*)(m_TreeCtrl->GetItemData(event.GetItem()));
  479.     wxXmlNode *node = (dt) ? dt->Node : NULL;      
  480.             
  481.     m_SelectedNode = node;
  482.     if (node)
  483.         PropertiesFrame::Get()->ShowProps(node);
  484.  
  485.     if (m_TreeCtrl->GetParent(event.GetItem()) == m_TreeCtrl->GetRootItem())
  486.     {
  487.         wxTreeItemId it = event.GetOldItem();
  488.  
  489.         if (it.IsOk() && m_TreeCtrl->GetRootItem() != it)
  490.         {
  491.             while (m_TreeCtrl->GetParent(it) != m_TreeCtrl->GetRootItem())
  492.                 it = m_TreeCtrl->GetParent(it);
  493.             m_TreeCtrl->Collapse(it);
  494.         }
  495.         RecursivelyExpand(m_TreeCtrl, event.GetItem());
  496.  
  497.         PreviewFrame::Get()->Preview(node,m_Resource->GetRoot()->GetPropVal(
  498.                                       wxT("version"), wxT("0.0.0.0")));
  499.     }
  500. }
  501.  
  502.  
  503.  
  504. void EditorFrame::OnToolbar(wxCommandEvent& event)
  505. {
  506.     switch (event.GetId()) 
  507.     {
  508.         case ID_PREVIEW :
  509.             {
  510.             XmlTreeData* dt = (XmlTreeData*)m_TreeCtrl->GetItemData(m_TreeCtrl->GetSelection());;
  511.             if (dt != NULL && dt->Node != NULL)
  512.                 PreviewFrame::Get()->Preview(dt->Node,m_Resource->GetRoot()->GetPropVal(
  513.                                       wxT("version"), wxT("0.0.0.0")));
  514.             break;
  515.             }
  516.  
  517.         case ID_EXIT :
  518.             Close(TRUE);
  519.             break;
  520.  
  521.         case ID_NEW :
  522.             NewFile();
  523.             break;
  524.  
  525.         case ID_OPEN :
  526.             {
  527.             wxString cwd = wxGetCwd(); // workaround for 2.2
  528.             wxString name = wxFileSelector(_("Open XML resource"), _T(""), _T(""), _T(""), _("XML resources (*.xrc)|*.xrc"), wxOPEN | wxFILE_MUST_EXIST);
  529.             wxSetWorkingDirectory(cwd);
  530.             if (!name.IsEmpty())
  531.                 LoadFile(name);
  532.             break;
  533.             }
  534.  
  535.         case ID_SAVE :
  536.             if (m_FileName != "") { SaveFile(m_FileName); break;}
  537.             // else go to SAVEAS
  538.  
  539.         case ID_SAVEAS :
  540.             {
  541.             wxString cwd = wxGetCwd(); // workaround for 2.2
  542.             wxString name = wxFileSelector(_("Save as"), _T(""), m_FileName, _T(""), _("XML resources (*.xrc)|*.xrc"), wxSAVE | wxOVERWRITE_PROMPT);
  543.             wxSetWorkingDirectory(cwd);
  544.             if (!name.IsEmpty())
  545.                 SaveFile((m_FileName = name));
  546.             break;
  547.             }
  548.  
  549.         case ID_DELETE_NODE :
  550.             {
  551.             DeleteSelectedNode();
  552.             break;
  553.             }
  554.     }
  555. }
  556.  
  557.  
  558.  
  559. void EditorFrame::DeleteSelectedNode()
  560. {
  561.     XmlTreeData *dt = (XmlTreeData*)
  562.             (m_TreeCtrl->GetItemData(m_TreeCtrl->GetParent(m_TreeCtrl->GetSelection())));
  563.     wxXmlNode *n = (dt) ? dt->Node : NULL;
  564.  
  565.     m_SelectedNode->GetParent()->RemoveChild(m_SelectedNode);
  566.     NotifyChanged(CHANGED_TREE);
  567.     SelectNode(n);
  568. }
  569.  
  570.  
  571.  
  572. void EditorFrame::OnNewNode(wxCommandEvent& event)
  573. {
  574.     if (event.GetId() >= ID_NEWSYBNODE)
  575.     {
  576.         XmlTreeData *pardt = 
  577.             (XmlTreeData*)(m_TreeCtrl->GetItemData(
  578.                 m_TreeCtrl->GetParent(m_TreeCtrl->GetSelection())));
  579.  
  580.         if (pardt && pardt->Node && pardt->Node != m_Resource->GetRoot())
  581.         {
  582.             wxXmlNode *nd = pardt->Node;
  583.  
  584.             wxXmlNode *realnode = NodeHandler::Find(nd)->GetRealNode(nd);
  585.             NodeHandler *hnd = NodeHandler::Find(realnode);
  586.             wxString name = hnd->GetChildTypes()[event.GetId()-ID_NEWSYBNODE];
  587.  
  588.             wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, _T("object"));
  589.             node->AddProperty(_T("class"), name);
  590.  
  591.             hnd->InsertNode(realnode, node, m_SelectedNode);
  592.             wxTreeItemId root = m_TreeCtrl->GetSelection();
  593.             SelectNode(node, &root);
  594.         }
  595.  
  596.     }
  597.  
  598.     else if (event.GetId() >= ID_NEWNODE)
  599.     {
  600.         wxXmlNode *realnode = NodeHandler::Find(m_SelectedNode)->GetRealNode(m_SelectedNode);
  601.         NodeHandler *hnd = NodeHandler::Find(realnode);
  602.         wxString name = hnd->GetChildTypes()[event.GetId()-ID_NEWNODE];
  603.  
  604.         wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, _T("object"));
  605.         node->AddProperty(_T("class"), name);
  606.  
  607.         hnd->InsertNode(realnode, node);
  608.         wxTreeItemId root = m_TreeCtrl->GetSelection();
  609.         SelectNode(node, &root);
  610.     }
  611.     
  612.     else
  613.     {
  614.         wxString name;
  615.         switch (event.GetId())
  616.         {
  617.             case ID_NEWDIALOG : name = _T("wxDialog"); break;
  618.             case ID_NEWPANEL : name = _T("wxPanel"); break;
  619.             case ID_NEWMENU : name = _T("wxMenu"); break;
  620.             case ID_NEWMENUBAR : name = _T("wxMenuBar"); break;
  621.             case ID_NEWTOOLBAR : name = _T("wxToolBar"); break;
  622.             default : return; // never occurs
  623.         }
  624.         
  625.         wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, _T("object"));
  626.         node->AddProperty(_T("class"), name);
  627.         m_Resource->GetRoot()->AddChild(node);
  628.         NotifyChanged(CHANGED_TREE);
  629.         SelectNode(node);
  630.     }
  631. }
  632.  
  633.  
  634.  
  635. void EditorFrame::OnRightClickTree(wxPoint pos)
  636. {
  637.     wxMenu *popup = new wxMenu;
  638.     
  639.     if (m_SelectedNode == NULL || m_SelectedNode == m_Resource->GetRoot())
  640.     {
  641.         popup->Append(ID_NEWDIALOG, _("New wxDialog"));
  642.         popup->Append(ID_NEWPANEL, _("New wxPanel"));
  643.         popup->Append(ID_NEWMENU, _("New wxMenu"));
  644.         popup->Append(ID_NEWMENUBAR, _("New wxMenuBar"));
  645.         popup->Append(ID_NEWTOOLBAR, _("New wxToolBar"));
  646.     }
  647.     
  648.     else
  649.     {   
  650.         bool has_children;
  651.         {
  652.             wxArrayString& arr = 
  653.                 NodeHandler::Find(NodeHandler::Find(m_SelectedNode)->GetRealNode(m_SelectedNode))->
  654.                     GetChildTypes();
  655.  
  656.             has_children = !arr.IsEmpty();
  657.             if (!arr.IsEmpty())
  658.             {
  659.                 wxMenu *news = new wxMenu;
  660.                 wxMenu *news2 = news;
  661.                 for (size_t i = 0; i < arr.GetCount(); i++)
  662.                 {
  663.                     news2->Append(i + ID_NEWNODE, arr[i]);
  664. #ifdef __WXGTK__ // doesn't support Break
  665.                     if (i % 20 == 19) 
  666.                     {
  667.                         wxMenu *m = new wxMenu;
  668.                         news2->Append(ID_NEWNODE+arr.GetCount(), _("More..."), m);
  669.                         news2 = m;
  670.                     }
  671. #else
  672.                     if (i % 16 == 15) news2->Break();
  673. #endif
  674.                 }
  675.                 popup->Append(ID_NEWNODE-1, _("New child"), news);
  676.             }
  677.         }
  678.  
  679.  
  680.         XmlTreeData *pardt = 
  681.             (XmlTreeData*)(m_TreeCtrl->GetItemData(
  682.                 m_TreeCtrl->GetParent(m_TreeCtrl->GetSelection())));
  683.         if (pardt && pardt->Node && pardt->Node != m_Resource->GetRoot())
  684.         {
  685.             wxXmlNode *nd = pardt->Node;
  686.             wxArrayString& arr = 
  687.                 NodeHandler::Find(NodeHandler::Find(nd)->GetRealNode(nd))->
  688.                     GetChildTypes();
  689.  
  690.             if (!arr.IsEmpty())
  691.             {
  692.                 wxMenu *news = new wxMenu;
  693.                 wxMenu *news2 = news;
  694.                 for (size_t i = 0; i < arr.GetCount(); i++)
  695.                 {
  696.                     news2->Append(i + ID_NEWSYBNODE, arr[i]);
  697. #ifdef __WXGTK__ // doesn't support Break
  698.                     if (i % 20 == 19) 
  699.                     {
  700.                         wxMenu *m = new wxMenu;
  701.                         news2->Append(ID_NEWSYBNODE+arr.GetCount(), _("More..."), m);
  702.                         news2 = m;
  703.                     }
  704. #else
  705.                     if (i % 16 == 15) news2->Break();
  706. #endif
  707.                 }
  708.                 popup->Append(ID_NEWSYBNODE-1, _("New sybling"), news);
  709.             }
  710.         }
  711.  
  712.  
  713.         popup->AppendSeparator();
  714.         popup->Append(ID_CUT, _("Cut"));
  715.         popup->Append(ID_COPY, _("Copy"));
  716.         popup->Append(ID_PASTE_SYBLING, _("Paste as sybling"));
  717.         popup->Append(ID_PASTE_CHILD, _("Paste as child"));
  718.         popup->AppendSeparator();
  719.         popup->Append(ID_DELETE_NODE, _("Delete"));
  720.         popup->Enable(ID_PASTE_SYBLING, m_Clipboard != NULL);
  721.         popup->Enable(ID_PASTE_CHILD, has_children && m_Clipboard != NULL);
  722.     }
  723.     
  724.     m_TreeCtrl->PopupMenu(popup, pos);
  725.     delete popup;
  726. }
  727.  
  728.  
  729.  
  730. void EditorFrame::OnClipboardAction(wxCommandEvent& event)
  731. {
  732.     switch (event.GetId())
  733.     {
  734.         case ID_COPY:
  735.         case ID_CUT:
  736.             delete m_Clipboard;
  737.             m_Clipboard = new wxXmlNode(*m_SelectedNode);
  738.             GetMenuBar()->Enable(ID_PASTE_SYBLING, TRUE);
  739.             GetMenuBar()->Enable(ID_PASTE_CHILD, TRUE);
  740.             if (event.GetId() == ID_CUT) DeleteSelectedNode();
  741.             break;
  742.             
  743.         case ID_PASTE_SYBLING:
  744.             {
  745.             XmlTreeData *pardt = 
  746.                 (XmlTreeData*)(m_TreeCtrl->GetItemData(
  747.                     m_TreeCtrl->GetParent(m_TreeCtrl->GetSelection())));
  748.  
  749.             if (pardt && pardt->Node && pardt->Node != m_Resource->GetRoot())
  750.             {
  751.                 wxXmlNode *nd = pardt->Node;
  752.  
  753.                 wxXmlNode *realnode = NodeHandler::Find(nd)->GetRealNode(nd);
  754.                 NodeHandler *hnd = NodeHandler::Find(realnode);
  755.                 wxXmlNode *node = new wxXmlNode(*m_Clipboard);
  756.                 hnd->InsertNode(realnode, node, m_SelectedNode);
  757.                 wxTreeItemId root = m_TreeCtrl->GetSelection();
  758.                 SelectNode(node, &root);
  759.             }
  760.             }
  761.             break;
  762.             
  763.         case ID_PASTE_CHILD:
  764.             wxXmlNode *realnode = NodeHandler::Find(m_SelectedNode)->GetRealNode(m_SelectedNode);
  765.             NodeHandler *hnd = NodeHandler::Find(realnode);
  766.             wxXmlNode *node = new wxXmlNode(*m_Clipboard);
  767.             hnd->InsertNode(realnode, node);
  768.             wxTreeItemId root = m_TreeCtrl->GetSelection();
  769.             SelectNode(node, &root);
  770.             break;
  771.     }
  772. }
  773.  
  774.  
  775.  
  776.  
  777. bool EditorFrame::AskToSave()
  778.     // asks the user to save current document (if modified)
  779.     // returns FALSE if user cancelled the action, TRUE of he choosed
  780.     // 'yes' or 'no'
  781. {
  782.     if (!m_Modified) return TRUE;
  783.     
  784.     int res = wxMessageBox(_("File modified. Do you want to save changes?"), _("Save changes"), 
  785.                             wxYES_NO | wxCANCEL | wxCENTRE | wxICON_QUESTION);
  786.     if (res == wxYES)
  787.         SaveFile(m_FileName);
  788.     return (res != wxCANCEL);
  789. }
  790.  
  791.  
  792.  
  793. void EditorFrame::OnCloseWindow(wxCloseEvent&)
  794. {
  795.     if (!AskToSave()) return;
  796.     Destroy();
  797. }
  798.