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