home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / contrib / utils / wxrcedit / editor.cpp < prev    next >
C/C++ Source or Header  |  2003-01-03  |  23KB  |  802 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Author:      Vaclav Slavik
  3. // Created:     2000/05/05
  4. // RCS-ID:      $Id: editor.cpp,v 1.18.2.3 2002/12/29 07:48:09 RL 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"), 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.     m_Resource->SetFileEncoding("utf-8");
  345. #if !wxUSE_UNICODE
  346.     m_Resource->SetEncoding(wxLocale::GetSystemEncodingName());
  347. #endif
  348.     m_Resource->GetRoot()->AddProperty(_T("version"),
  349.                                        WX_XMLRES_CURRENT_VERSION_STRING);
  350.     
  351.     m_Modified = FALSE;
  352.     RefreshTree();
  353.     RefreshTitle();
  354. }
  355.  
  356.  
  357.  
  358. void EditorFrame::RefreshTitle()
  359. {
  360.     wxString s;
  361.     if (m_Modified) s << _T("* ");
  362.     s << _("wxrcedit");
  363.     if (m_FileName != "")
  364.         s << _T(" - ") << wxFileNameFromPath(m_FileName);
  365.     SetTitle(s);
  366. }
  367.  
  368.  
  369.  
  370. void EditorFrame::RefreshTree()
  371. {
  372.     wxXmlNode *sel = m_SelectedNode;
  373.     
  374.     m_TreeCtrl->DeleteAllItems(); 
  375.     wxTreeItemId root = m_TreeCtrl->AddRoot("Resource: " + wxFileNameFromPath(m_FileName), 5, 5);
  376.  
  377.     wxXmlNode *n = m_Resource->GetRoot()->GetChildren();  
  378.     while (n)
  379.     {
  380.         if (n->GetType() == wxXML_ELEMENT_NODE)
  381.             CreateTreeNode(m_TreeCtrl, root, n);
  382.         n = n->GetNext();
  383.     }
  384.  
  385.     m_TreeCtrl->Expand(root);
  386.     SelectNode(sel);
  387. }
  388.  
  389.  
  390.  
  391.  
  392. static void RecursivelyExpand(wxTreeCtrl *t, wxTreeItemId item)
  393. {
  394.     t->Expand(item);
  395.     long cookie;
  396.     wxTreeItemId id = t->GetFirstChild(item, cookie);
  397.     while (id.IsOk())
  398.     {
  399.         RecursivelyExpand(t, id);
  400.         id = t->GetNextChild(item, cookie);
  401.     }
  402. }
  403.  
  404. bool EditorFrame::SelectNode(wxXmlNode *node, wxTreeItemId *root)
  405. {
  406.     if (root == NULL)
  407.     {
  408.         wxTreeItemId rootitem = m_TreeCtrl->GetRootItem();
  409.         return SelectNode(node, &rootitem);
  410.     }
  411.  
  412.     wxTreeItemId item;
  413.     XmlTreeData *dt;
  414.     wxXmlNode *nd;
  415.     long cookie;
  416.     
  417.     item = m_TreeCtrl->GetFirstChild(*root, cookie);
  418.     while (item.IsOk())
  419.     {
  420.         dt = (XmlTreeData*)(m_TreeCtrl->GetItemData(item));
  421.         nd = (dt) ? dt->Node : NULL;
  422.         if (nd == node) 
  423.         {
  424.             RecursivelyExpand(m_TreeCtrl, *root);
  425.             m_TreeCtrl->SelectItem(item);
  426.             m_TreeCtrl->EnsureVisible(item);
  427.             return TRUE; 
  428.         }
  429.         if (m_TreeCtrl->ItemHasChildren(item) && SelectNode(node, &item)) 
  430.             return TRUE; 
  431.         item = m_TreeCtrl->GetNextChild(*root, cookie);
  432.     }
  433.  
  434.     return FALSE;
  435. }
  436.  
  437.  
  438.  
  439. wxTreeItemId EditorFrame::CreateTreeNode(wxTreeCtrl *treectrl, wxTreeItemId parent, wxXmlNode *node)
  440. {
  441.     if (!node) 
  442.     {
  443.         wxTreeItemId invalid;
  444.         return invalid;
  445.     }
  446.  
  447.     return NodeHandler::Find(node)->CreateTreeNode(treectrl, parent, node);
  448. }
  449.  
  450.  
  451.  
  452. void EditorFrame::NotifyChanged(int change_type)
  453. {
  454.     if (change_type & CHANGED_TREE)
  455.         RefreshTree();
  456.  
  457.     if (change_type & CHANGED_TREE_SELECTED)
  458.     {
  459.         wxTreeItemId sel = m_TreeCtrl->GetSelection();
  460.         m_TreeCtrl->SetItemText(sel, 
  461.              NodeHandler::Find(m_SelectedNode)->GetTreeString(m_SelectedNode));
  462.     }
  463.  
  464.     if (change_type & CHANGED_TREE_SELECTED_ICON)
  465.     {
  466.         wxTreeItemId sel = m_TreeCtrl->GetSelection();
  467.         int icon = NodeHandler::Find(m_SelectedNode)->GetTreeIcon(m_SelectedNode);
  468.         m_TreeCtrl->SetItemImage(sel, icon);
  469.     }
  470.     
  471.     if (!m_Modified)
  472.     {
  473.         m_Modified = TRUE;
  474.         RefreshTitle();
  475.     }
  476.     
  477.     PreviewFrame::Get()->MakeDirty();
  478. }
  479.  
  480.  
  481.  
  482. void EditorFrame::OnTreeSel(wxTreeEvent& event)
  483. {
  484.     XmlTreeData *dt = (XmlTreeData*)(m_TreeCtrl->GetItemData(event.GetItem()));
  485.     wxXmlNode *node = (dt) ? dt->Node : NULL;      
  486.             
  487.     m_SelectedNode = node;
  488.     if (node)
  489.         PropertiesFrame::Get()->ShowProps(node);
  490.  
  491.     if (m_TreeCtrl->GetItemParent(event.GetItem()) == m_TreeCtrl->GetRootItem())
  492.     {
  493.         wxTreeItemId it = event.GetOldItem();
  494.  
  495.         if (it.IsOk() && m_TreeCtrl->GetRootItem() != it)
  496.         {
  497.             while (m_TreeCtrl->GetItemParent(it) != m_TreeCtrl->GetRootItem())
  498.                 it = m_TreeCtrl->GetItemParent(it);
  499.             m_TreeCtrl->Collapse(it);
  500.         }
  501.         RecursivelyExpand(m_TreeCtrl, event.GetItem());
  502.  
  503.         PreviewFrame::Get()->Preview(node,m_Resource);
  504.     }
  505. }
  506.  
  507.  
  508.  
  509. void EditorFrame::OnToolbar(wxCommandEvent& event)
  510. {
  511.     switch (event.GetId()) 
  512.     {
  513.         case ID_PREVIEW :
  514.             {
  515.             XmlTreeData* dt = (XmlTreeData*)m_TreeCtrl->GetItemData(m_TreeCtrl->GetSelection());;
  516.             if (dt != NULL && dt->Node != NULL)
  517.                 PreviewFrame::Get()->Preview(dt->Node, m_Resource);
  518.             break;
  519.             }
  520.  
  521.         case ID_EXIT :
  522.             Close(TRUE);
  523.             break;
  524.  
  525.         case ID_NEW :
  526.             NewFile();
  527.             break;
  528.  
  529.         case ID_OPEN :
  530.             {
  531.             wxString cwd = wxGetCwd(); // workaround for 2.2
  532.             wxString name = wxFileSelector(_("Open XML resource"), _T(""), _T(""), _T(""), _("XML resources (*.xrc)|*.xrc"), wxOPEN | wxFILE_MUST_EXIST);
  533.             wxSetWorkingDirectory(cwd);
  534.             if (!name.IsEmpty())
  535.                 LoadFile(name);
  536.             break;
  537.             }
  538.  
  539.         case ID_SAVE :
  540.             if (m_FileName != "") { SaveFile(m_FileName); break;}
  541.             // else go to SAVEAS
  542.  
  543.         case ID_SAVEAS :
  544.             {
  545.             wxString cwd = wxGetCwd(); // workaround for 2.2
  546.             wxString name = wxFileSelector(_("Save as"), _T(""), m_FileName, _T(""), _("XML resources (*.xrc)|*.xrc"), wxSAVE | wxOVERWRITE_PROMPT);
  547.             wxSetWorkingDirectory(cwd);
  548.             if (!name.IsEmpty())
  549.                 SaveFile((m_FileName = name));
  550.             break;
  551.             }
  552.  
  553.         case ID_DELETE_NODE :
  554.             {
  555.             DeleteSelectedNode();
  556.             break;
  557.             }
  558.     }
  559. }
  560.  
  561.  
  562.  
  563. void EditorFrame::DeleteSelectedNode()
  564. {
  565.     XmlTreeData *dt = (XmlTreeData*)
  566.             (m_TreeCtrl->GetItemData(m_TreeCtrl->GetItemParent(m_TreeCtrl->GetSelection())));
  567.     wxXmlNode *n = (dt) ? dt->Node : NULL;
  568.  
  569.     m_SelectedNode->GetParent()->RemoveChild(m_SelectedNode);
  570.     NotifyChanged(CHANGED_TREE);
  571.     SelectNode(n);
  572. }
  573.  
  574.  
  575.  
  576. void EditorFrame::OnNewNode(wxCommandEvent& event)
  577. {
  578.     if (event.GetId() >= ID_NEWSYBNODE)
  579.     {
  580.         XmlTreeData *pardt = 
  581.             (XmlTreeData*)(m_TreeCtrl->GetItemData(
  582.                 m_TreeCtrl->GetItemParent(m_TreeCtrl->GetSelection())));
  583.  
  584.         if (pardt && pardt->Node && pardt->Node != m_Resource->GetRoot())
  585.         {
  586.             wxXmlNode *nd = pardt->Node;
  587.  
  588.             wxXmlNode *realnode = NodeHandler::Find(nd)->GetRealNode(nd);
  589.             NodeHandler *hnd = NodeHandler::Find(realnode);
  590.             wxString name = hnd->GetChildTypes()[event.GetId()-ID_NEWSYBNODE];
  591.  
  592.             wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, _T("object"));
  593.             node->AddProperty(_T("class"), name);
  594.  
  595.             hnd->InsertNode(realnode, node, m_SelectedNode);
  596.             wxTreeItemId root = m_TreeCtrl->GetSelection();
  597.             SelectNode(node, &root);
  598.         }
  599.  
  600.     }
  601.  
  602.     else if (event.GetId() >= ID_NEWNODE)
  603.     {
  604.         wxXmlNode *realnode = NodeHandler::Find(m_SelectedNode)->GetRealNode(m_SelectedNode);
  605.         NodeHandler *hnd = NodeHandler::Find(realnode);
  606.         wxString name = hnd->GetChildTypes()[event.GetId()-ID_NEWNODE];
  607.  
  608.         wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, _T("object"));
  609.         node->AddProperty(_T("class"), name);
  610.  
  611.         hnd->InsertNode(realnode, node);
  612.         wxTreeItemId root = m_TreeCtrl->GetSelection();
  613.         SelectNode(node, &root);
  614.     }
  615.     
  616.     else
  617.     {
  618.         wxString name;
  619.         switch (event.GetId())
  620.         {
  621.             case ID_NEWDIALOG : name = _T("wxDialog"); break;
  622.             case ID_NEWPANEL : name = _T("wxPanel"); break;
  623.             case ID_NEWMENU : name = _T("wxMenu"); break;
  624.             case ID_NEWMENUBAR : name = _T("wxMenuBar"); break;
  625.             case ID_NEWTOOLBAR : name = _T("wxToolBar"); break;
  626.             default : return; // never occurs
  627.         }
  628.         
  629.         wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, _T("object"));
  630.         node->AddProperty(_T("class"), name);
  631.         m_Resource->GetRoot()->AddChild(node);
  632.         NotifyChanged(CHANGED_TREE);
  633.         SelectNode(node);
  634.     }
  635. }
  636.  
  637.  
  638.  
  639. void EditorFrame::OnRightClickTree(wxPoint pos)
  640. {
  641.     wxMenu *popup = new wxMenu;
  642.     
  643.     if (m_SelectedNode == NULL || m_SelectedNode == m_Resource->GetRoot())
  644.     {
  645.         popup->Append(ID_NEWDIALOG, _("New wxDialog"));
  646.         popup->Append(ID_NEWPANEL, _("New wxPanel"));
  647.         popup->Append(ID_NEWMENU, _("New wxMenu"));
  648.         popup->Append(ID_NEWMENUBAR, _("New wxMenuBar"));
  649.         popup->Append(ID_NEWTOOLBAR, _("New wxToolBar"));
  650.     }
  651.     
  652.     else
  653.     {   
  654.         bool has_children;
  655.         {
  656.             wxArrayString& arr = 
  657.                 NodeHandler::Find(NodeHandler::Find(m_SelectedNode)->GetRealNode(m_SelectedNode))->
  658.                     GetChildTypes();
  659.  
  660.             has_children = !arr.IsEmpty();
  661.             if (!arr.IsEmpty())
  662.             {
  663.                 wxMenu *news = new wxMenu;
  664.                 wxMenu *news2 = news;
  665.                 for (size_t i = 0; i < arr.GetCount(); i++)
  666.                 {
  667.                     news2->Append(i + ID_NEWNODE, arr[i]);
  668. #ifdef __WXGTK__ // doesn't support Break
  669.                     if (i % 20 == 19) 
  670.                     {
  671.                         wxMenu *m = new wxMenu;
  672.                         news2->Append(ID_NEWNODE+arr.GetCount(), _("More..."), m);
  673.                         news2 = m;
  674.                     }
  675. #else
  676.                     if (i % 16 == 15) news2->Break();
  677. #endif
  678.                 }
  679.                 popup->Append(ID_NEWNODE-1, _("New child"), news);
  680.             }
  681.         }
  682.  
  683.  
  684.         XmlTreeData *pardt = 
  685.             (XmlTreeData*)(m_TreeCtrl->GetItemData(
  686.                 m_TreeCtrl->GetItemParent(m_TreeCtrl->GetSelection())));
  687.         if (pardt && pardt->Node && pardt->Node != m_Resource->GetRoot())
  688.         {
  689.             wxXmlNode *nd = pardt->Node;
  690.             wxArrayString& arr = 
  691.                 NodeHandler::Find(NodeHandler::Find(nd)->GetRealNode(nd))->
  692.                     GetChildTypes();
  693.  
  694.             if (!arr.IsEmpty())
  695.             {
  696.                 wxMenu *news = new wxMenu;
  697.                 wxMenu *news2 = news;
  698.                 for (size_t i = 0; i < arr.GetCount(); i++)
  699.                 {
  700.                     news2->Append(i + ID_NEWSYBNODE, arr[i]);
  701. #ifdef __WXGTK__ // doesn't support Break
  702.                     if (i % 20 == 19) 
  703.                     {
  704.                         wxMenu *m = new wxMenu;
  705.                         news2->Append(ID_NEWSYBNODE+arr.GetCount(), _("More..."), m);
  706.                         news2 = m;
  707.                     }
  708. #else
  709.                     if (i % 16 == 15) news2->Break();
  710. #endif
  711.                 }
  712.                 popup->Append(ID_NEWSYBNODE-1, _("New sybling"), news);
  713.             }
  714.         }
  715.  
  716.  
  717.         popup->AppendSeparator();
  718.         popup->Append(ID_CUT, _("Cut"));
  719.         popup->Append(ID_COPY, _("Copy"));
  720.         popup->Append(ID_PASTE_SYBLING, _("Paste as sybling"));
  721.         popup->Append(ID_PASTE_CHILD, _("Paste as child"));
  722.         popup->AppendSeparator();
  723.         popup->Append(ID_DELETE_NODE, _("Delete"));
  724.         popup->Enable(ID_PASTE_SYBLING, m_Clipboard != NULL);
  725.         popup->Enable(ID_PASTE_CHILD, has_children && m_Clipboard != NULL);
  726.     }
  727.     
  728.     m_TreeCtrl->PopupMenu(popup, pos);
  729.     delete popup;
  730. }
  731.  
  732.  
  733.  
  734. void EditorFrame::OnClipboardAction(wxCommandEvent& event)
  735. {
  736.     switch (event.GetId())
  737.     {
  738.         case ID_COPY:
  739.         case ID_CUT:
  740.             delete m_Clipboard;
  741.             m_Clipboard = new wxXmlNode(*m_SelectedNode);
  742.             GetMenuBar()->Enable(ID_PASTE_SYBLING, TRUE);
  743.             GetMenuBar()->Enable(ID_PASTE_CHILD, TRUE);
  744.             if (event.GetId() == ID_CUT) DeleteSelectedNode();
  745.             break;
  746.             
  747.         case ID_PASTE_SYBLING:
  748.             {
  749.             XmlTreeData *pardt = 
  750.                 (XmlTreeData*)(m_TreeCtrl->GetItemData(
  751.                     m_TreeCtrl->GetItemParent(m_TreeCtrl->GetSelection())));
  752.  
  753.             if (pardt && pardt->Node && pardt->Node != m_Resource->GetRoot())
  754.             {
  755.                 wxXmlNode *nd = pardt->Node;
  756.  
  757.                 wxXmlNode *realnode = NodeHandler::Find(nd)->GetRealNode(nd);
  758.                 NodeHandler *hnd = NodeHandler::Find(realnode);
  759.                 wxXmlNode *node = new wxXmlNode(*m_Clipboard);
  760.                 hnd->InsertNode(realnode, node, m_SelectedNode);
  761.                 wxTreeItemId root = m_TreeCtrl->GetSelection();
  762.                 SelectNode(node, &root);
  763.             }
  764.             }
  765.             break;
  766.             
  767.         case ID_PASTE_CHILD:
  768.             wxXmlNode *realnode = NodeHandler::Find(m_SelectedNode)->GetRealNode(m_SelectedNode);
  769.             NodeHandler *hnd = NodeHandler::Find(realnode);
  770.             wxXmlNode *node = new wxXmlNode(*m_Clipboard);
  771.             hnd->InsertNode(realnode, node);
  772.             wxTreeItemId root = m_TreeCtrl->GetSelection();
  773.             SelectNode(node, &root);
  774.             break;
  775.     }
  776. }
  777.  
  778.  
  779.  
  780.  
  781. bool EditorFrame::AskToSave()
  782.     // asks the user to save current document (if modified)
  783.     // returns FALSE if user cancelled the action, TRUE of he choosed
  784.     // 'yes' or 'no'
  785. {
  786.     if (!m_Modified) return TRUE;
  787.     
  788.     int res = wxMessageBox(_("File modified. Do you want to save changes?"), _("Save changes"), 
  789.                             wxYES_NO | wxCANCEL | wxCENTRE | wxICON_QUESTION);
  790.     if (res == wxYES)
  791.         SaveFile(m_FileName);
  792.     return (res != wxCANCEL);
  793. }
  794.  
  795.  
  796.  
  797. void EditorFrame::OnCloseWindow(wxCloseEvent&)
  798. {
  799.     if (!AskToSave()) return;
  800.     Destroy();
  801. }
  802.