NCBI C++ ToolKit
dock_container.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: dock_container.cpp 47464 2023-04-20 00:19:10Z evgeniev $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Andrey Yazhuk
27  *
28  * File Description:
29  *
30  */
31 
32 
33 #include <ncbi_pch.hpp>
34 
38 
43 
46 
49 
50 IMPLEMENT_DYNAMIC_CLASS(CBeginDragOutsideEvent, wxEvent)
51 DEFINE_EVENT_TYPE(USER_EVT_BEGIN_DRAG_OUTSIDE)
52 
53 ////////////////////////////////////////////////////////////////////////////////
54 /// CDockContainer
55 
56 BEGIN_EVENT_TABLE(CDockContainer, CDockContainer::TParent)
57  EVT_MOTION(CDockContainer::OnMouseMove)
58  EVT_LEFT_DOWN(CDockContainer::OnLeftDown)
59  EVT_LEFT_UP(CDockContainer::OnLeftUp)
60  EVT_MOUSE_CAPTURE_LOST(CDockContainer::OnMouseCaptureLost)
63 
64 
65 CDockContainer::CDockContainer(CDockManager& manager, wxWindow* parent, bool create_tab)
66 : TParent(parent, wxID_ANY, wxDefaultPosition, wxSize(0,0),
67  wxCLIP_CHILDREN, _("dock_container")),
68  m_DockManager(manager),
69  m_WindowManager(manager.GetWindowManager()),
70  m_DockFrame(NULL),
71  m_RootWindow(NULL),
72  m_MarkersWindow(NULL),
73  m_DragTarget(NULL),
74  m_HintWindow(NULL),
75  m_TabDockable(NULL)
76 {
77  SetBackgroundStyle(wxBG_STYLE_CUSTOM);
78 
79  m_DockFrame = dynamic_cast<CFloatingFrame*>(parent);
80 
81  x_CreateControls();
82 
83  x_InitDefaultTree(create_tab);
84 }
85 
86 void CDockContainer::x_InitDefaultTree(bool create_tab)
87 {
88  // create Full tree with a Notebook (for main container) or empty (for
89  // floating frames)
91  if (create_tab) {
92  TNode* node = new TNode(CDockLayoutTree::eTab);
93  tree.Reset(new CDockLayoutTree(node, node));
94  } else {
95  tree.Reset(new CDockLayoutTree());
96  }
97 
98  // initialize the container based on the full tree
99  SetFullTree(*tree);
100 }
101 
103 {
104 }
105 
106 
108 {
109  return m_DockManager;
110 }
111 
112 
114 {
115  return m_DockFrame;
116 }
117 
118 
120 {
121  if (m_VisibleTree && m_VisibleTree->GetRoot()) {
122  return m_VisibleTree->GetRoot()->GetWindow();
123  }
124  return NULL;
125 }
126 
127 
129 {
130  return wxWindow::Layout();
131 }
132 
133 
135 {
136  wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
137  SetSizer(sizer);
138 }
139 
140 
141 // sets the new window as the Root window of the container
142 void CDockContainer::x_SetRootWindow(wxWindow* window)
143 {
144  if (window != m_RootWindow) {
145  if (m_RootWindow) {
146  // disconnect the old window
147  GetSizer()->Detach(m_RootWindow);
148  }
149 
150  m_RootWindow = window;
151 
152  CDockPanel* panel = dynamic_cast<CDockPanel*>(m_RootWindow);
153  if(panel) {
154  panel->ShowBorder(false);
155  }
156 
157  if (m_RootWindow) {
158  m_RootWindow->Reparent(this);
159  GetSizer()->Add(m_RootWindow, 1, wxEXPAND);
160  m_RootWindow->Show();
161 
162  GetSizer()->Layout();
163  }
164  }
165 }
166 
167 
168 // applies a layout tree to the container
170 {
172 
173  m_FullTree.Reset(&full_tree);
174 
175  CRef<TNode> centralPane = m_FullTree->GetCentralPane();
176 
177  if (centralPane) {
179  m_VisibleTree.Reset(new CDockLayoutTree(node, node));
180  node->Link(*centralPane);
181  }
182  else {
184  }
185 
186  // traverse visible tree and create components as needed
188  if (root && root->IsVisible()) {
189  x_InstantiateNode(*root->GetClone(), true);
190 
191  wxWindow* win = root->GetWindow();
192  if (win) {
193  x_SetRootWindow(win);
194  }
195 
196  BlockSplittersLayout(false);
197  }
198 }
199 
200 
201 // Instantiates clients by fingerprints using the given factory.
203 {
204 public:
206  : m_DockContainer(cont),
207  m_Factory(factory)
208  {}
209 
211  {
212  if (m_Factory && ! node.IsContainer() && node.IsVisible()) {
213  IWMClient* client = NULL;
214  IWMClient::CFingerprint fingerprint = node.GetFingerprint();
215 
216  client = m_Factory->CreateClient(fingerprint, &m_DockContainer);
217 
218  if (client) {
219  // client has been created - wrap it in a Dock Panel
220 
221  wxString pname = _("panel_");
222  pname << ToWxString(fingerprint.GetId());
223 
225  CDockPanel* panel = new CDockPanel(&m_DockContainer, &manager,
226  client, pname);
227 
228  node.SetWindow(panel);
229  } else {
230  // client cannot be created - hide the node
231  node.SetHidden(true);
232  }
233  }
234  }
235 protected:
238 };
239 
240 
242 {
243 public:
245  {
246  bool found = ! node.IsContainer() && node.IsHidden();
247  if(found) {
248  m_FoundNode.Reset(&node);
249  }
250  return found;
251  }
252 
254 };
255 
256 
257 /// This clean-up normalizes the tree, so that it can be instantiated as a layout.
258 /// The function applies x_Full_CleanLayoutTreeBranch() recusrsively.
260 {
261  CRef<TNode> full_root = full_tree.GetRoot();
262  if (full_root) {
263  x_Full_CleanLayoutTreeBranch(full_tree.GetCentralPane(), *full_root);
264 
265  bool kill_root = false;
266  if(full_root->IsClient()) {
267  kill_root = full_root->IsHidden();
268  } else {
269  kill_root = ! full_root->HasChildren() &&
270  (full_root != full_tree.GetCentralPane());
271  }
272  if(kill_root) {
273  full_tree.m_Root.Reset();
274  }
275  }
276 }
277 
278 
279 /// Cleans the given tree starting from the given node.
280 /// This function removes all hidden client nodes, then it removes empty
281 /// containers. Containers that have exactly one child node are replaced with
282 /// this child node.
284 {
285  if(full_node.IsContainer()) {
286  CDockLayoutTree::TNodeVector& children = full_node.GetChildren();
287  for( size_t i = 0; i < children.size(); ) {
288  CRef<TNode> child = children[i];
289  bool kill = false;
290 
291  if(child->IsContainer()) {
292  // process containers recursively
293  x_Full_CleanLayoutTreeBranch(centralPane, *child);
294 
295  // now see if this child container needs to be reduced
296  bool central_pane = (centralPane == child);
297  if( ! central_pane) {
298  if(child->HasOnlyOneChild()) {
299  // replace "child" with its only child (node's grand child)
300  CRef<TNode> grand_child = child->GetTheOnlyChild();
301  child->RemoveChild(*grand_child);
302  full_node.ReplaceChild(*child, *grand_child);
303 
304  _ASSERT(grand_child->GetParent() == &full_node);
305  } else {
306  // if child has no children - kill it
307  kill = child->GetChildren().empty();
308  }
309  }
310  // Sometimes splitters get Hidden flag set to TRUE
311  // If splitter contains some views
312  // it may result in NULL pointer access an application exit
313  // JIRA: GB-1280
314  if (child->IsSplitter())
315  child->SetHidden(false);
316  }
317 
318  if(kill) {
319  full_node.RemoveChild(i);
320  } else {
321  i++; // advance
322  }
323  }
324  }
325 }
326 
327 
328 // destroys the visible tree and disconnects the full tree from the container
330 {
332 
333  m_FullTree.Reset();
335 
336  return tree;
337 }
338 
339 
341 {
342  if (m_FullTree) {
343  for (auto i : m_WindowToNode) {
344  if (dynamic_cast<CDockPanel*>(i.first))
345  return false;
346  }
347  }
348  return true;
349 }
350 
351 // get all IWMCient-s in the container
352 void CDockContainer::GetAllClients(vector<IWMClient*>& clients)
353 {
354  if (m_FullTree) {
355  for (auto i : m_WindowToNode) {
356  CDockPanel* panel = dynamic_cast<CDockPanel*>(i.first);
357  if (panel) {
358  IWMClient* client = panel->GetClient();
359  _ASSERT(client);
360  clients.push_back(client);
361  }
362  }
363  }
364 }
365 
366 
367 // returns true if the given window is the root window of this Dock Container
368 bool CDockContainer::IsRootWindow(wxWindow* window)
369 {
371  if (root) {
372  return root->GetWindow() == window;
373  }
374  return false;
375 }
376 
377 
378 // helper function; converts Dock Effect into dock position
380 {
381  switch(effect) {
382  case eSplitLeft:
383  case eSplitTargetLeft:
384  return wxLEFT;
385 
386  case eSplitRight:
387  case eSplitTargetRight:
388  return wxRIGHT;
389 
390  case eSplitTop:
391  case eSplitTargetTop:
392  return wxTOP;
393 
394  case eSplitBottom:
395  case eSplitTargetBottom:
396  return wxBOTTOM;
397 
398  default:
399  return wxALL;
400  }
401 }
402 
403 
405 {
406  switch(effect) {
407  case eSplitLeft:
408  case eSplitRight:
409  case eSplitTop:
410  case eSplitBottom:
411  return true;
412  default:
413  return false;
414  }
415 }
416 
417 
418 // diagnostics helper - dumps and validates Visible and Full trees
419 // we call this function before and after complex operations
421 {
422 #ifdef WM_LOGGING
423  LOG_POST(Info << "LogPostTrees: " << text);
424 
425  LOG_POST(Info << "Visible tree");
427 
428  if (m_VisibleTree->m_Root)
430 
431  LOG_POST(Info << "Full tree");
432  m_FullTree->LogPost();
433 
434  LOG_POST(Info << "\n");
435 
436  if (m_FullTree->m_Root)
438 #endif
439 }
440 
441 
442 // returns CDockPanel for a window (CDockPanel or IWMClient)
443 // create a new CDockPanel if needed
445 {
446  wxWindow* window = client.GetWindow();
447  _ASSERT(window);
448 
449  CDockPanel* panel = dynamic_cast<CDockPanel*>(window);
450  if (panel == NULL) {
451  // window is not the panel
452  wxWindow* parent = window->GetParent();
453  panel = dynamic_cast<CDockPanel*>(parent);
454 
455  if(panel == NULL) {
456  // create a new one
457  wxString pname = wxT("panel_");
458  IWMClient::CFingerprint fp = client.GetFingerprint();
459  string s = fp.GetId();
460  pname << ToWxString(s);
461  panel = new CDockPanel(this, &GetDockManager(), &client, pname);
462  }
463  }
464  return panel;
465 }
466 
467 
468 // returns an existing Dock Panel for the given client
470 {
471  wxWindow* window = client.GetWindow();
472  for (;window;) {
473  wxWindow* parent = window->GetParent();
474  CDockPanel* panel = dynamic_cast<CDockPanel*>(parent);
475  if (panel)
476  return panel;
477  window = parent;
478  }
479  return 0;
480 }
481 
482 
483 // Functor returns true if a node (visible or not) has a fingerprint
485 {
486 public:
488  : m_Print(print) {}
489 
491  bool res = false;
492 
493  if (!node.IsVisible())
494  res = (node.GetFingerprint() == m_Print);
495 
496  if (res) {
497  m_Node.Reset(&node);
498  }
499  return res;
500  }
501 
504 };
505 
506 
507 // Functor tests whether a node is visible
509 {
511  {
512  if (node.IsVisible()) {
513  m_Node.Reset(&node);
514  return true;
515  }
516  return false;
517  }
519 };
520 
521 
522 // adds a new client into a reasonable default location
524 {
525  //Freeze();
526 
527  BlockSplittersLayout(true);
528 
529  CRef<TNode> full_layout_node;
530 
531  // find a node that has the same fingerprint as the client
532  CRef<TNode> full_node;
533  TFingerprint p = client.GetFingerprint();
534  if( ! p.IsEmpty()) {
537  full_node = f.m_Node;
538  }
539 
540  if (full_node) {
541  LogPostTrees("CDockContainer::AddClientToDefaultLocation() start");
542 
543  // the node with matching fingerprint is hidden, we need
544  // to modify the layout tree so that this hidden node becomes visible
545  // this may require unhiding some of the hidden parent containers
546  TNode* full_cont = x_AddClientToHiddenPos(client, full_node);
547  full_layout_node.Reset(full_cont);
548 
549  Layout();
550  LogPostTrees("CDockContainer::AddClientToDefaultLocation() end");
551  } else {
552  // no positional information - add to the central Tab pane of the main container
553 
554  CDockPanel* panel = x_GetDockPanel(client);
555  CRef<TNode> full_client(new TNode(CDockLayoutTree::eClient, panel));
556  full_client->Link(*new TNode(*full_client));
557 
558  full_client->SetFingerprint(p);
559  full_client->GetClone()->SetFingerprint(p);
560 
561  AddClientToCentralPane(full_client);
562  }
563 
564  BlockSplittersLayout(false);
565 
566  //Thaw();
567 
568  // tereshko: this is the only thing that works to properly
569  // initialize some views inserted to an _empty_ container
570  // Refresh and Focus is not working
571 #ifdef __WXMAC__
572  wxWindow* client_w = client.GetWindow();
573  client_w->Hide();
574  client_w->Show();
575 #endif
576 }
577 
578 
581 {
582  // instantiate the client node
583  CDockPanel* panel = x_GetDockPanel(client);
584  full_node->SetWindow(panel);
585  full_node->Link(*new TNode(*full_node));
586 
587  TNode* full_cont = full_node->GetParent();
588  TNode* full_cont_child = full_node;
589 
590  // we are traversing parent nodes looking for a hidden container that should
591  // become visible or for a visible container
592  while(full_cont) {
593  if (full_cont->IsHidden()) {
595  if (full_cont->DepthFirstSearch(test)) {
596  WM_POST("Unhiding a hidden container with one child");
597  // a container having a visible child can be hidden only if it
598  // has exactly one visible child
599  TNode& full_vis_child = *test.m_Node;
600  x_Full_UnhideContainer_AddChildren(*full_cont, full_vis_child, *full_node);
601  break;
602  }
603  } else {
604  WM_POST("Add the client to a visible parent container");
605  // found a visible container - add child to it
606  x_InstantiateNode(*full_node, false);
607  x_Visible_AddChildToContainer(*full_cont->GetClone(), *full_node->GetClone());
608  break;
609  }
610  // move one step up in the tree
611  full_cont_child = full_cont;
612  full_cont = full_cont->GetParent();
613  }
614 
615  if (full_cont == NULL) {
616  WM_POST("we did not find an appropriate parent container");
617  // we did not find an appropriate parent container
618  // instantiate the topmost hidden container
619  full_cont = full_cont_child; // tompost container
620  CRef<TNode> old_root = m_VisibleTree->GetRoot();
621 
622  if (old_root) {
623  WM_POST("Unhide root container");
624  x_Full_UnhideContainer_AddChildren(*full_cont, *old_root->GetClone(), *full_node);
625  } else {
626  WM_POST("Create as central component");
627  // create as central component
628  x_InstantiateNode(*full_node, true);
629 
630  m_VisibleTree->m_Root.Reset(full_node->GetClone());
631  x_SetRootWindow(m_VisibleTree->GetRoot()->GetWindow());
632  panel->Show();
633  }
634  }
635  return full_cont;
636 }
637 
638 // add the given client node to Dock Manager's Main Tabbed Pane
640 {
641  //WM_POST("\nCwxDockContainer::AddClientToCentralPane(TNode)");
642 
644  if (pane) {
645  _ASSERT(pane->IsTab());
646  x_InstantiateNode(*full_client, true);
647  x_AddClientInTab(full_client, CRef<TNode>(pane->GetClone()));
648  x_SetRootWindow(m_VisibleTree->GetRoot()->GetWindow());
649  Layout();
650  } else {
651  x_InstantiateNode(*full_client, true);
652 
653  if(m_VisibleTree->m_Root) {
654  CRef<TNode> full_root(m_VisibleTree->m_Root->GetClone());
655  x_AddClientInTab(full_client, full_root);
656 
657  wxWindow* new_root_window = m_VisibleTree->GetRoot()->GetWindow();
658  x_SetRootWindow(new_root_window);
659 
660  Layout();
661  } else {
662  // there is no central pane - client becomes the Root Window of this Dock Container
663 
664  m_FullTree->m_Root.Reset(full_client);
665  m_VisibleTree->m_Root.Reset(full_client->GetClone());
666 
667  x_SetRootWindow(m_VisibleTree->GetRoot()->GetWindow());
668  }
669  }
670 }
671 
672 void CDockContainer::AddClient(CRef<TNode> full_client, EDockEffect effect, wxWindow* target_w)
673 {
674  //WM_POST("\nCwxDockContainer::AddClient() " << kStartSep);
675  //WM_POST("\t\teffect " << effect << ", target window " << target_w);
676  LogPostTrees("CDockContainer::AddClient() start");
677 
678  BlockSplittersLayout(true);
679 
680  // find the node that is the target of the drop operation
681  CRef<TNode> full_target(x_FindNodeByWindow(target_w));
682 
683  x_InstantiateNode(*full_client, true);
684 
685  if (effect == ePutInTab) {
686  x_AddClientInTab(full_client, full_target);
687  } else {
688  x_AddClientInSplitter(full_client, full_target, effect);
689  }
690 
691  wxWindow* new_root_window = m_VisibleTree->GetRoot()->GetWindow();
692  x_SetRootWindow(new_root_window);
693 
694  Layout();
695  BlockSplittersLayout(false);
696 
697  LogPostTrees("CDockContainer::AddClient() end");
698  //WM_POST("CDockContainer::AddClient() END " << kEndSep);
699 }
700 
701 
702 // add the given client in a tab with the given target
703 // client node must be already instantiated (window created)
705 {
706  _ASSERT(full_client->IsClient());
707 
708  TNode* fullTab = 0;
709 
710  if (full_target->IsTab()) {
711  fullTab = full_target;
712  }
713  else {
714  // target is not a Tab Control
715  CRef<TNode> full_parent(full_target->GetParent());
716  if (full_parent) {
717  if (full_parent->IsTab()) {
718  if (full_parent->IsHidden()) {
719  CRef<TNode> tab(new TNode(*full_parent));
720  tab->Link(*full_parent);
721  x_InstantiateNode(*full_parent, false);
722 
723  x_Visible_ReplaceChildWithContainer(*full_target->GetClone(), *tab);
724  x_Visible_AddChildToContainer(*tab, *full_target->GetClone());
725  }
726  fullTab = full_parent;
727  }
728  else {
729  CRef<TNode> fullNewTab(new TNode(CDockLayoutTree::eTab, NULL, true));
730  fullNewTab->Link(*new TNode(*fullNewTab));
731  x_InstantiateNode(*fullNewTab, false);
732 
733  full_parent->ReplaceChild(*full_target, *fullNewTab);
734  fullNewTab->AddChild(*full_target);
735 
736  x_Visible_ReplaceChildWithContainer(*full_target->GetClone(), *fullNewTab->GetClone());
737  x_Visible_AddChildToContainer(*fullNewTab->GetClone(), *full_target->GetClone());
738  fullTab = fullNewTab;
739  }
740  }
741  else { // full_target is a single node/window in container
742  CRef<TNode> fullNewTab(new TNode(CDockLayoutTree::eTab, NULL, true));
743  fullNewTab->Link(*new TNode(*fullNewTab));
744  x_InstantiateNode(*fullNewTab, false);
745 
746  m_FullTree->m_Root.Reset(fullNewTab);
747  fullNewTab->AddChild(*full_target);
748 
749  x_Visible_ReplaceChildWithContainer(*full_target->GetClone(), *fullNewTab->GetClone());
750  x_Visible_AddChildToContainer(*fullNewTab->GetClone(), *full_target->GetClone());
751  fullTab = fullNewTab;
752  }
753  }
754 
755  _ASSERT(fullTab);
756  fullTab->AddChild(*full_client);
757  x_Visible_AddChildToContainer(*fullTab->GetClone(), *full_client->GetClone());
758  _ASSERT(full_client->GetParent());
759 }
760 
761 void sGetSplitSizes(int total_size, vector<int>& sizes, bool split_left)
762 {
763  int s1 = total_size / 3;
764  int s2 = total_size - s1;
765  sizes.push_back(split_left ? s1 : s2);
766  sizes.push_back(split_left ? s2 : s1);
767 }
768 
769 // add the given client to the target with the specified split effect
771  CRef<TNode> full_target,
772  EDockEffect effect)
773 {
774  // need to split either target or root container
775  wxDirection dir = sGetDirectionByEffect(effect);
776 
777  // create a node for the new splitter
778  CDockLayoutTree::ENodeType type = (dir == wxLEFT || dir == wxRIGHT) ?
780 
781  // TODO - revise - we may want to reuse hidden splitters
782  CRef<TNode> full_sp_node(new TNode(type, NULL, true));
783  full_sp_node->Link(*new TNode(*full_sp_node));
784  x_InstantiateNode(*full_sp_node, false);
785 
786  // insert container instead of child_1 (update data structure)
787  bool reverse = (dir == wxLEFT) || (dir == wxTOP);
788  CRef<TNode> full_node_to_split = full_target;
789 
790  if (sRootSplit(effect)) {
791  full_node_to_split.Reset(m_VisibleTree->GetRoot()->GetClone());
792  }
793 
794  CRef<TNode> full_parent(full_node_to_split->GetParent());
795 
796  // disconnect full_node_to_split
797  if (full_parent) {
798  full_parent->ReplaceChild(*full_node_to_split, *full_sp_node);
799  }
800  else {
801  // full_child_1 does not have a parent - it is the Root, update the Root
802  m_FullTree->m_Root.Reset(full_sp_node);
803  }
804 
805  x_Visible_ReplaceChildWithContainer(*full_node_to_split->GetClone(), *full_sp_node->GetClone());
806 
807  // remember the size
808  wxSize size = full_node_to_split->GetWindow()->GetSize();
809 
810  TNode& cont = *full_sp_node->GetClone();
811 
812  if (reverse) {
813  full_sp_node->AddChild(*full_client);
814  x_Visible_AddChildToContainer(cont, *full_client->GetClone());
815 
816  full_sp_node->AddChild(*full_node_to_split);
817  x_Visible_AddChildToContainer(cont, *full_node_to_split->GetClone());
818  }
819  else {
820  full_sp_node->AddChild(*full_node_to_split);
821  x_Visible_AddChildToContainer(cont, *full_node_to_split->GetClone());
822 
823  full_sp_node->AddChild(*full_client);
824  x_Visible_AddChildToContainer(cont, *full_client->GetClone());
825  }
826 
827  // correct splitter sizes TODO - need a more elegant solution
828  wxWindow* cont_w = cont.GetWindow();
829 
830  switch (cont.GetType()) {
832  CDockSplitter* splitter = dynamic_cast<CDockSplitter*>(cont_w);
833  vector<int> heights;
834  sGetSplitSizes(size.y, heights, reverse);
835  splitter->SetHeights(heights);
836  break;
837  }
839  CDockSplitter* splitter = dynamic_cast<CDockSplitter*>(cont_w);
840  vector<int> widths;
841  sGetSplitSizes(size.x, widths, reverse);
842  splitter->SetWidths(widths);
843  break;
844  }
845  default:
846  break;
847  }
848 }
849 
850 
853 {
854  //WM_POST("\nCwxDockContainer::RemoveWindow(): " << window << kStartSep);
855  LogPostTrees("CDockContainer::RemoveWindow() start");
856 
857  wxWindow* window = dynamic_cast<wxWindow*>(&dockable);
858 
859  //Freeze();
860 
861  CRef<TNode> full_node(x_FindNodeByWindow(window));
862 
863  _ASSERT(full_node); // window must be in this container
864 
865  if (full_node) {
867 
868  TNode* node = full_node->GetClone();
869  CRef<TNode> parent_node = node->GetParent();
870  CRef<TNode> full_parent_node(full_node->GetParent());
871 
872  x_Full_RemoveNode(*full_node, action);
873 
874  // check whether we need to drop the full_node's visible parent container
875  bool central_pane = (m_VisibleTree->GetCentralPane() == parent_node);
876 
877  // we never destroy the Central Pane
878  if ( ! central_pane && parent_node) {
879  if (parent_node->HasOnlyOneChild()) {
880  x_Full_ReduceContainer(*parent_node->GetClone());
881  }
882  }
883 
884  // may need to destroy its immediate hidden container node
885  if (full_parent_node) {
886  x_Full_ReduceHiddenContainer_IfNeeded(*full_parent_node);
887  }
888  }
889 
890  //Thaw();
891 
892  Layout();
893 
894  //WM_POST("\nAfter RemoveWindow() " << kEndSep);
895  LogPostTrees("CDockContainer::RemoveWindow() end");
896 
897  return full_node;
898 }
899 
900 
902 {
903  FNodeFingerprintEquals f(fingerprint);
904  bool ok = m_FullTree->DepthFirstSearch(f);
905  return ok;
906 }
907 
908 
909 //// Functor returns true if a node (visible or not) has a fingerprint
911 {
912 public:
914  {
915  if (node.IsVisible()) {
916  CDockPanel* panel = dynamic_cast<CDockPanel*>(node.GetWindow());
917  if (panel) {
918  IWMClient* client = panel->GetClient();
919  IWMClient::CFingerprint p = client->GetFingerprint();
920  return ! p.IsEmpty();
921  }
922  } else {
923  return ! node.GetFingerprint().IsEmpty();
924  }
925  return false;
926  }
927 };
928 
929 
930 // save positions if there are windows or hidden nodes with fingerprints
932 {
933  if (m_DockManager.GetMainContainer() == this)
934  return true;
935 
937  bool ok = m_FullTree->DepthFirstSearch(f);
938  return ok;
939 }
940 
941 
943 {
944 public:
945  FBlockSplitterLayout(bool block) : m_Block(block) {}
946 
948  if (node.IsSplitter()) {
949  CDockSplitter* splitter = dynamic_cast<CDockSplitter*>(node.GetWindow());
950  splitter->BlockLayout(m_Block);
951  }
952  }
953 protected:
954  bool m_Block;
955 };
956 
957 
958 /// Iterates through all splitters and blocks / unblocks layout.
960 {
962  if (root) {
963  FBlockSplitterLayout blocker(block);
964  root->DepthFirstForEach(blocker);
965  }
966 }
967 
968 
969 ///////////////////////////////////////////////////////////////////////////////
970 // Functions operating on the Full Tree (update visible tree and windows as well)
971 // Functions starting from Full_ update the full tree and then visible tree and
972 // windows to bring them in accordance with the full tree.
973 
975 {
976  wxWindow* win = full_node.GetWindow();
977 
978  switch(full_node.GetType()) {
980  CDockSplitter* splitter = dynamic_cast<CDockSplitter*>(win);
981  splitter->SetHeights(full_node.GetSplitterSizes());
982  break;
983  }
985  CDockSplitter* splitter = dynamic_cast<CDockSplitter*>(win);
986  splitter->SetWidths(full_node.GetSplitterSizes());
987  break;
988  }
989  default:
990  break;
991  }
992 }
993 
994 // Instantiates the given hidden container.
995 // Replaces vis_child (already visible) with the container and adds both
996 // visible and previously hidden child to the container.
997 // The children may be separated from the container by several hidden container nodes
998 // in the full tree.
1000  TNode& full_vis_child,
1001  TNode& full_new_child)
1002 {
1003  TNode& vis_child = *full_vis_child.GetClone();
1004 
1005  // create a container node and window, but do not add children
1006  CRef<TNode> cont(new TNode(full_cont));
1007  full_cont.Link(*cont);
1008  x_InstantiateNode(full_cont, false, fCreateWindow); // only create the container window
1009 
1010  // add child and client in the right order
1011  auto vis_index = full_cont.GetBranchIndex(full_vis_child);
1012  auto new_index = full_cont.GetBranchIndex(full_new_child);
1013  _ASSERT(vis_index >= 0 && new_index >= 0); // must be related
1014 
1015  // replace visible child with the container
1016  x_Visible_ReplaceChildWithContainer(vis_child, *cont);
1017 
1018  // instantiate new child node
1019  x_InstantiateNode(full_new_child, false);
1020  TNode& new_child = *full_new_child.GetClone();
1021 
1022  // establish parent-child relations in visible tree
1023  cont->RemoveAllChildren();
1024  if (vis_index < new_index) {
1025  cont->AddChild(vis_child);
1026  cont->AddChild(new_child);
1027  } else {
1028  cont->AddChild(new_child);
1029  cont->AddChild(vis_child);
1030  }
1031 
1032  // insert child windows into the container window
1033  x_InstantiateNode(full_cont, false, fAddChildWindows);
1034 
1035  sRestoreSplitterSizes(full_cont);
1036 }
1037 
1038 
1039 /// Disconnect all child nodes from the given node in all 3 trees (Full Tree,
1040 /// Visible Tree and Window Tree).
1041 /// The function does not destroy the children.
1043 {
1044  wxWindow* node_w = full_node.GetWindow();
1045  IDockContWindow* cont = dynamic_cast<IDockContWindow*>(node_w);
1046 
1047  // disconnect windows
1048  TNodeVector& children = full_node.GetChildren();
1049  for( size_t i = 0; i < children.size(); i++) {
1050  TNode& full_child = *children[i];
1051  wxWindow* w = full_child.GetWindow();
1052  cont->Cont_Remove(w);
1053  }
1054 
1055  // disconnect nodes
1056  full_node.RemoveAllChildren();
1057  full_node.GetClone()->RemoveAllChildren();
1058 }
1059 
1060 
1061 // removes a node from all 3 trees
1063 {
1064  //WM_POST("CDockContainer::x_Full_RemoveNode()");
1065  TFingerprint fingerprint;
1066  if (action != eMoveWin) {
1067  CDockPanel* panel = dynamic_cast<CDockPanel*>(full_node.GetWindow());
1068  _ASSERT(panel);
1069 
1070  IWMClient* client = panel->GetClient();
1071  fingerprint = client->GetFingerprint();
1072  }
1073 
1074  // remove visible node and destroy windows
1075  x_Visible_RemoveNode(*full_node.GetClone(), action);
1076 
1077  if (action != eMoveWin) {
1078  full_node.Unlink();
1079  }
1080 
1081  bool keep_node = false;
1082 
1083  if(action == eMinimizeWin) {
1084  keep_node = true; // window is being minimized - preserve layout nodes
1085  } else {
1086  // windows is being moved or deleted
1087 
1088  if ( ! fingerprint.IsEmpty()) {
1089  keep_node = true;
1090  }
1091  }
1092 
1093  if (keep_node) {
1094  // keep the node in the Full tree as hidden to preserve this position
1095  // as the default position for clients with the same fingerprint
1096  full_node.SetFingerprint(fingerprint);
1097  } else {
1098  CRef<TNode> full_parent = full_node.GetParent();
1099  if (full_parent) {
1100  full_parent->RemoveChild(full_node);
1101  } else {
1102  // full_node is the root
1103  _ASSERT(m_FullTree->m_Root.GetPointer() == &full_node);
1104  m_FullTree->m_Root.Reset();
1105  }
1106  }
1107 }
1108 
1109 
1110 // replaces the given container with it's only child (lifts the child to the container's place)
1111 // if the child became hidden - hide the container
1112 // if the child was destroyed - destroy the container
1114 {
1115  //WM_POST("x_Full_ReduceContainer()...");
1116 
1117  _ASSERT(full_cont.IsVisible()); // precondition
1118 
1119  TNode& cont = *full_cont.GetClone();
1120  CRef<TNode> the_child = cont.GetTheOnlyChild();
1121 
1122  // modify visible tree
1124 
1125  full_cont.Unlink(); // unlink from visible node
1126 
1127  // update full tree
1128  if (full_cont.HasOnlyOneChild()) {
1129  // destroy the container as it has only 1 child in both trees
1130  CRef<TNode> full_child = full_cont.GetTheOnlyChild();
1131  full_cont.RemoveChild(*full_child);
1132 
1133  CRef<TNode> full_parent = full_cont.GetParent(); // the parent of this container
1134  if (full_parent) {
1135  // node's parent now should point to the node's only child
1136  full_parent->ReplaceChild(full_cont, *full_child);
1137  // child becomes connected to its previous grandparent
1138  _ASSERT(full_child->GetParent() == full_parent);
1139  } else {
1140  _ASSERT(full_child->GetParent() == NULL); // child becomes the root
1141  m_FullTree->m_Root.Reset(full_child);
1142  }
1143  } else {
1144  // hide the container, but let it keep its children
1145  _ASSERT(full_cont.IsHidden());
1146  }
1147  // container must be disconnected or invisible now
1148  _ASSERT(full_cont.IsHidden() || full_cont.GetParent() == NULL);
1149 }
1150 
1151 
1152 
1153 // remove a hidden container node from full tree only
1155 {
1156  //WM_POST("x_Full_ReduceHiddenContainer_IfNeeded()...");
1157 
1158  // preconditions - container is hidden and has exactly one hidden child
1159  if (full_cont.IsHidden() && full_cont.HasOnlyOneChild()) {
1160  CRef<TNode> full_child = full_cont.GetTheOnlyChild();
1161 
1162  if (full_child->IsHidden() && full_cont.GetClone() == NULL) {
1163  // destroy the container as it has only 1 child in both trees
1164  CRef<TNode> full_parent = full_cont.GetParent();// the parent of this container
1165  full_cont.RemoveChild(*full_child);
1166 
1167  if (full_parent) {
1168  // node's parent now should point to the node's only child
1169  full_parent->ReplaceChild(full_cont, *full_child);
1170  // child becomes connects to its previous grandparent
1171  _ASSERT(full_child->GetParent() == full_parent);
1172  } else {
1173  _ASSERT(full_child->GetParent() == NULL &&
1174  m_FullTree->m_Root.GetPointerOrNull() == &full_cont);
1175  // child becomes the root
1176  m_FullTree->m_Root.Reset(full_child);
1177  }
1178  }
1179  }
1180 }
1181 
1182 
1183 ///////////////////////////////////////////////////////////////////////////////
1184 /// Functions updating visible tree and windows based on the full tree.
1185 /// Functions names start from Visible_.
1186 
1187 
1189 {
1190  CRef<TNode> parent = node.GetParent();
1191 
1192  if (parent) {
1193  // remove the node from the visible tree
1194  parent->RemoveChild(node);
1195 
1196  // disconnect from the parent container window
1197  wxWindow* win = node.GetWindow();
1198  wxWindow* parent_w = parent->GetWindow();
1199 
1200  IDockContWindow* parent_cont = dynamic_cast<IDockContWindow*>(parent_w);
1201  parent_cont->Cont_Remove(win);
1202  } else {
1203  _ASSERT(m_VisibleTree->m_Root.GetPointer() == &node);
1204  wxWindow* win = node.GetWindow();
1205  GetSizer()->Detach(win);
1206  m_VisibleTree->m_Root.Reset();
1207  }
1208 
1209  TNode& full_node = *node.GetClone();
1210  x_DestroyNode(full_node, action);
1211 }
1212 
1213 // Replaces the child node with the given container in visible tree in window hierarchy
1214 // the child node becomes disconnected
1216 {
1217  wxWindow* child_w = child.GetWindow();
1218  wxWindow* cont_w = cont.GetWindow();
1219 
1220  _ASSERT(cont_w && child_w); // both windows must exist
1221 
1222  CRef<TNode> parent = child.GetParent();
1223 
1224  if (parent) {
1225  wxWindow* parent_w = parent->GetWindow();
1226  /// remove the child window from the parent and replace it with container window
1227  IDockContWindow* parent_cont = dynamic_cast<IDockContWindow*>(parent_w);
1228  parent_cont->Cont_Replace(child_w, cont_w);
1229 
1230  // update visible tree - replace child the node with the container node
1231  parent->ReplaceChild(child, cont);
1232 
1233  // container now must be a child of the "parent" node
1234  _ASSERT(cont.GetParent() == parent.GetPointer());
1235  } else {
1236  // no - parent, child node is the root, update the root
1237  x_SetRootWindow(cont_w); // TODO move up
1238  m_VisibleTree->m_Root.Reset(&cont);
1239  }
1240 
1241  _ASSERT(child.GetParent() == NULL); // child node becomes diconnected
1242 }
1243 
1244 
1245 void sDockPanel_ShowBorder(wxWindow* w, bool show)
1246 {
1247  CDockPanel* panel = dynamic_cast<CDockPanel*>(w);
1248  if(panel) {
1249  panel->ShowBorder(show);
1250  }
1251 }
1252 
1253 
1254 /// Adds a child to a visible node. This function establishes parent-child
1255 /// connection between visible nodes and betwee the windows corresponding to
1256 /// the nodes.
1258 {
1259  _ASSERT(child.GetWindow() && cont.IsContainer());
1260 
1261  wxWindow* cont_w = cont.GetWindow();
1262  wxWindow* child_w = child.GetWindow();
1263 
1264  // enable / disable border rendering in the panel depending on the container type
1265  sDockPanel_ShowBorder(child_w, cont.IsSplitter());
1266 
1267  switch(cont.GetType()) {
1269  CDockSplitter* splitter = dynamic_cast<CDockSplitter*>(cont_w);
1270  size_t child_count = splitter->GetChildren().GetCount();
1271  if (child_count > 0) {
1272  splitter->AddRow();
1273  }
1274  int row = splitter->GetRowsCount() - 1;
1275  splitter->InsertToCell(child_w, 0, row);
1276  if (x_IsElastic(child)) {
1277  splitter->SetResizableCell(-1, row);
1278  }
1279  break;
1280  }
1282  CDockSplitter* splitter = dynamic_cast<CDockSplitter*>(cont_w);
1283  size_t child_count = splitter->GetChildren().GetCount();
1284  if (child_count > 0) {
1285  splitter->AddColumn();
1286  }
1287  int col = splitter->GetColumnsCount() - 1;
1288  splitter->InsertToCell(child_w, col, 0);
1289  if (x_IsElastic(child)) {
1290  splitter->SetResizableCell(col, -1);
1291  }
1292  break;
1293  }
1294  case CDockLayoutTree::eTab: {
1295  CDockNotebook* notebook = dynamic_cast<CDockNotebook*>(cont_w);
1296  string label = x_GetPageNameByWindow(child_w);
1297  notebook->InsertPageAtHitPoint(child_w, ToWxString(label));
1298  child_w->Reparent(notebook);
1299 
1300  size_t index = notebook->GetPageIndex(child_w);
1301  notebook->SetSelection(index);
1302 
1303  notebook->MakeSelectionVisible();
1304 
1305  break;
1306  }
1307  default:
1308  _ASSERT(false); // invalid container type
1309  }
1310 
1311  // establish parent-child connections between the nodes
1312  cont.AddChild(child);
1313 }
1314 
1315 
1316 // Replaces a container having exactly one child with the child;
1317 // destroys the container
1319 {
1320  // can lift only containers having a single child
1321  CRef<TNode> child = cont.GetTheOnlyChild();
1322  CRef<TNode> parent = cont.GetParent();
1323 
1324  // update window connections
1325  wxWindow* child_w = child->GetWindow();
1326  wxWindow* cont_w = cont.GetWindow();
1327  cont_w->Hide();
1328 
1329  // disconnect child from cont in Visible and Window Trees
1330  cont.RemoveChild(*child);
1331  IDockContWindow* cont_dw = dynamic_cast<IDockContWindow*>(cont_w);
1332  cont_dw->Cont_Remove(child_w);
1333 
1334  /// remove cont_w window from Window Manager
1335  if (parent) {
1336  // node's parent now should point to the node's only child
1337  parent->ReplaceChild(cont, *child);
1338 
1339  // in the parent window replace container window with the child window
1340  IDockContWindow* parent_dw = dynamic_cast<IDockContWindow*>(parent->GetWindow());
1341  parent_dw->Cont_Replace(cont_w, child_w);
1342 
1343  // child becomes connect to its previous grandparent
1344  _ASSERT(child->GetParent() == parent);
1345  } else {
1346  _ASSERT(child->GetParent() == NULL); // child becomes the root
1347  // this is a root node - update m_VisibleTree root
1348 
1349  m_VisibleTree->m_Root = child;
1350  x_SetRootWindow(child->GetWindow());
1351  }
1352 
1353  // now we can safely destroy the container node and window
1354  x_DestroyNode(cont, eDestroyWin);
1355 }
1356 
1357 
1358 /// Ensures that a node has a window and this window is properly connected with
1359 /// its child and parent windows. This is a potentially recursive function
1360 /// (controlled by "recursive" parameter).
1361 /// For a container node it will create a window if needed.
1362 void CDockContainer::x_InstantiateNode(TNode& full_node, bool recursive, EInstFlags flags)
1363 {
1364  wxWindow* window = full_node.GetWindow();
1365  bool create = (flags & fCreateWindow) != 0;
1366  bool add_children = (flags == fAddChildWindows) ||
1367  ( (flags == (fCreateWindow | fAddChildWindows)) && window == NULL);
1368 
1369  if (full_node.IsContainer()) {
1370  // this is a Container window - inspect child nodes
1371  TNode& node = *full_node.GetClone();
1372  for( size_t i = 0; i < node.GetChildren().size(); i++ ) {
1373  TNode& child_node = *node.GetChildren()[i];
1374  if (recursive) {
1375  // instantiate nodes for the child windows
1376  x_InstantiateNode(*child_node.GetClone(), recursive, flags);
1377  }
1378  // otherwise expect child window to exist
1379  }
1380 
1381  // create a window for "full_node" if needed
1382  if ( ! window && create) {
1383  window = x_CreateContainerWindow(full_node.GetType());
1384  window->Hide();
1385  }
1386  }
1387 
1388  _ASSERT(window);
1389 
1390  if (create && window) {
1391  TNode& node = *full_node.GetClone();
1392  full_node.SetWindow(window);
1393  node.SetWindow(window);
1394 
1395  // mark nodes as visble
1396  full_node.SetHidden(false);
1397  node.SetHidden(false);
1398 
1399  IDockableWindow* dockable = dynamic_cast<IDockableWindow*>(window);
1400  if (dockable) {
1401  dockable->SetDockContainer(this);
1402  }
1403 
1404  // update indexes
1405  m_WindowToNode[window] = &full_node;
1406  }
1407 
1408  /// optionally add child windows to this node's window
1409  if (add_children) {
1411  }
1412  _ASSERT(window && full_node.GetClone());
1413 }
1414 
1415 
1417 {
1418  switch(type) {
1420  CDockSplitter* splitter = new CDockSplitter(*this, CDockSplitter::eHorizontal);
1421  splitter->BlockLayout(true);
1422  return splitter;
1423  }
1425  CDockSplitter* splitter = new CDockSplitter(*this, CDockSplitter::eVertical);
1426  splitter->BlockLayout(true);
1427  return splitter;
1428  }
1429  case CDockLayoutTree::eTab: {
1430  CDockNotebook* notebook = new CDockNotebook(*this);
1431  return notebook;
1432  }
1433  default:
1434  _ASSERT(false);
1435  return NULL;
1436  }
1437 }
1438 
1439 
1440 /// Iterates child windows of the given container node and inserts them into
1441 /// the container window.
1443 {
1444  if (full_node.IsContainer()) {
1445  // accumulate windows for child nodes of the visible container node (real visible children)
1446  TNode& node = *full_node.GetClone();
1447  vector<wxWindow*> child_windows;
1448  for( size_t i = 0; i < node.GetChildren().size(); i++ ) {
1449  TNode& child_node = *node.GetChildren()[i];
1450  child_windows.push_back(child_node.GetWindow());
1451  }
1452  size_t n = child_windows.size();
1453 
1454  // get the container window
1455  wxWindow* window = full_node.GetWindow();
1456  _ASSERT(window);
1457 
1458  // add child windows to the container window
1459  switch(node.GetType()) {
1461  CDockSplitter* splitter = dynamic_cast<CDockSplitter*>(window);
1462  splitter->Split(0, (int)n);
1463  for( size_t i = 0; i < n; i++ ) {
1464  wxWindow* child_w = child_windows[i];
1465 
1466  sDockPanel_ShowBorder(child_w, true);
1467  splitter->InsertToCell(child_w, 0, (int)i);
1468  if (x_IsElastic(child_w)) {
1469  splitter->SetResizableCell(-1, (int)i);
1470  }
1471  }
1472  break;
1473  }
1475  CDockSplitter* splitter = dynamic_cast<CDockSplitter*>(window);
1476  splitter->Split((int)n, 0);
1477  for( size_t i = 0; i < n; i++ ) {
1478  wxWindow* child_w = child_windows[i];
1479 
1480  sDockPanel_ShowBorder(child_w, true);
1481  splitter->InsertToCell(child_w, (int)i, 0);
1482  if (x_IsElastic(child_w)) {
1483  splitter->SetResizableCell((int)i, -1);
1484  }
1485  }
1486  break;
1487  }
1488  case CDockLayoutTree::eTab: {
1489  CDockNotebook * notebook = dynamic_cast<CDockNotebook*>(window);
1490  for( size_t i = 0; i < n; i++ ) {
1491  wxWindow* child_w = child_windows[i];
1492 
1493  sDockPanel_ShowBorder(child_w, false);
1494 
1495  child_w->Reparent(notebook);
1496  string label = x_GetPageNameByWindow(child_w);
1497  notebook->AddPage(child_w, ToWxString(label));
1498 
1499  int index = notebook->GetPageIndex(child_w);
1500  notebook->SetSelection(index);
1501  }
1502  break;
1503  }
1504  default:
1505  _ASSERT(false);
1506  }
1507  }
1508 }
1509 
1510 
1511 // disconnects node window from the node and destroys the window
1512 // removes window for layout tree maps
1514 {
1515  wxWindow* win = full_node.GetWindow();
1516  _ASSERT(win);
1517 
1518  IWMClient* client = 0;
1519  for (wxWindow* w = win; w; w = w->GetParent()) {
1520  CDockPanel* panel = dynamic_cast<CDockPanel*>(w);
1521  if (panel) {
1522  client = panel->GetClient();
1523  break;
1524  }
1525  }
1526 
1527  if (client) {
1528  TFingerprint p = client->GetFingerprint();
1529  full_node.SetFingerprint(p);
1530  }
1531 
1532  IDockableWindow* dockable = dynamic_cast<IDockableWindow*>(win);
1533  if (dockable) {
1534  dockable->SetDockContainer(NULL);
1535  }
1536 
1537  if (full_node.IsContainer()) {
1538  _ASSERT(action != eMinimizeWin); // cannot minimize containers
1539 
1540  vector<wxWindow*> child_windows;
1541  for( size_t i = 0; i < full_node.GetChildren().size(); i++ ) {
1542  TNode& full_child_node = *full_node.GetChildren()[i];
1543  if (full_child_node.IsVisible()) {
1544  x_DestroyNode(full_child_node, action);
1545  }
1546  }
1547 
1548  if (action == eDestroyWin) {
1549  //WM_POST("Destroying container window");
1550  win->Destroy();
1551  }
1552  } else {
1553  if (action == eDestroyWin) {
1554  CDockPanel* panel = dynamic_cast<CDockPanel*>(win);
1555  panel->RemoveClient(this);
1556  panel->Destroy();
1557  }
1558  }
1559  _ASSERT(full_node.GetClone());
1560 
1561  TNode& node = *full_node.GetClone();
1562 
1563  if (action != eMoveWin) {
1564  // mark nodes as invisible
1565  full_node.SetHidden(true);
1566  node.SetHidden(true);
1567 
1568  // disconnect nodes from the window
1569  full_node.SetWindow(NULL);
1570  node.SetWindow(NULL);
1571  }
1572 
1573  // remove window from tree index
1574  m_WindowToNode.erase(win);
1575 }
1576 
1577 
1578 // returns true if the given node belongs to the resizable branch
1579 // (the branch of the visible tree containing the central tab control)
1581 {
1582  TNode* curr_node = m_VisibleTree->GetCentralPane().GetPointer();
1583  while(curr_node) {
1584  if (curr_node == &node)
1585  return true;
1586  curr_node = curr_node->GetParent();
1587  }
1588  return false;
1589 }
1590 
1591 
1592 bool CDockContainer::x_IsElastic(wxWindow* win)
1593 {
1594  TNode* curr_node = m_VisibleTree->GetCentralPane().GetPointer();
1595  if (curr_node) {
1596  wxWindow* curr_w = curr_node->GetWindow();
1597  while(curr_w) {
1598  if (curr_w == win)
1599  return true;
1600  curr_w = curr_w->GetParent();
1601  }
1602  }
1603  return false;
1604 }
1605 
1607 {
1608  if (window) {
1609  CDockPanel* panel = dynamic_cast<CDockPanel*>(window);
1610  if (panel) {
1611  return panel->GetClient()->GetClientLabel();
1612  }
1613  CDockSplitter* splitter = dynamic_cast<CDockSplitter*>(window);
1614  if (splitter) {
1615  return "Splitter";
1616  }
1617  }
1618  return "";
1619 }
1620 
1621 
1622 // get all IWMCient-s in a window hosted in the container
1623 void CDockContainer::GetClientsInWindow(wxWindow* window, vector<IWMClient*>& clients)
1624 {
1625  TNode* node = x_FindNodeByWindow(window);
1626  _ASSERT(node);
1627  if (node) {
1628  x_GetClientsInNode(*node, clients);
1629  }
1630 }
1631 
1632 
1633 // makes the given clients visible (if possible),
1634 // if a client does not belong to the container it is simply ignored
1635 void CDockContainer::ActivateClients(vector<IWMClient*>& clients)
1636 {
1637  _ASSERT(m_VisibleTree); // the operation is meaningless otherwise
1638 
1639  // we can active only one tab in each Notebook, here we keep the list of
1640  // visited notebooks
1641  set<CDockNotebook*> visited;
1642 
1643  for( size_t i = 0; i < clients.size(); i++ ) {
1644  IWMClient* client = clients[i];
1645  _ASSERT(client);
1646 
1647  // get window and Node corresponding to the Client
1648  wxWindow* window = x_DockPanelForClient(*client);
1649  _ASSERT(window);
1650 
1651  if (x_FindNodeByWindow(window)) {
1652  // this is our client - iterate client's parents and activate tabs
1653  wxWindow* parent = window->GetParent();
1654  while(parent && parent != this) {
1655  CDockNotebook* notebook = dynamic_cast<CDockNotebook*>(parent);
1656 
1657  if (notebook && visited.find(notebook) == visited.end()) {
1658  // activate the page
1659  int index = notebook->GetPageIndex(window);
1660  notebook->SetSelection(index);
1661  visited.insert(notebook);
1662  }
1663 
1664  window = parent;
1665  parent = parent->GetParent();
1666  }
1667  }
1668  }
1669 }
1670 
1671 
1672 // get all IWMCient-s in a Node hosted in the container
1673 void CDockContainer::x_GetClientsInNode(TNode& node, vector<IWMClient*>& clients)
1674 {
1675  CDockPanel* panel = dynamic_cast<CDockPanel*>(node.GetWindow());
1676  if (panel) {
1677  IWMClient* client = panel->GetClient();
1678  _ASSERT(client);
1679  clients.push_back(client);
1680  } else if (node.IsContainer()) {
1681  // process child nodes recursively
1682  for( size_t i = 0; i < node.GetChildren().size(); i++ ) {
1683  TNode& child_node = *node.GetChildren()[i];
1684  x_GetClientsInNode(child_node, clients);
1685  }
1686  }
1687 }
1688 
1689 
1690 // this function is called by Dock Manager during D&D docking session
1691 // when mouse pointer enters the container
1692 void CDockContainer::OnBeginDragOver(const wxPoint& sc_mouse_pos)
1693 {
1694  //WM_POST("\nCwxDockContainer::OnBeginDragOver() pos - " << sc_mouse_pos.x << ", " << sc_mouse_pos.y);
1695 
1696  wxWindow* parent = m_DockManager.GetTopAppWindow();
1697 
1698  m_MarkersWindow = new CDockMarkerWindow(*this, parent);
1699 
1701  m_DragTarget = NULL;
1702 
1703  OnDragOver(sc_mouse_pos);
1704 }
1705 
1706 
1707 // this function is called by Dock Manager during D&D docking session when
1708 // mouse pointer moves inside the container
1709 void CDockContainer::OnDragOver(const wxPoint& sc_mouse_pos)
1710 {
1711  //WM_POST("CDockContainer::OnDragOver() pos - " << sc_mouse_pos.x << ", " << sc_mouse_pos.y);
1712 
1713  wxMouseState ms_state = wxGetMouseState();
1714  bool split_tab_panes = ms_state.ShiftDown();
1715 
1716  // perform hit testing
1717  wxWindow* old_target = m_DragTarget;
1718  m_Effect = x_HitTest(sc_mouse_pos, m_DragTarget, split_tab_panes);
1719 
1720  if (m_DragTarget != old_target) {
1721  wxRect root_rc = ncbi::GetScreenRect(*m_RootWindow);
1722  wxRect target_rc(0, 0, 0, 0);
1723  if (m_DragTarget) {
1724  target_rc = ncbi::GetScreenRect(*m_DragTarget);
1725  }
1726 
1727  m_MarkersWindow->SetTargetRect(root_rc, target_rc);
1728  }
1729 
1730  EDockEffect marker_effect = m_MarkersWindow->HitTest(sc_mouse_pos);
1731  //WM_POST("m_MarkersWindow->HitTest(sc_mouse_pos) - effect " << marker_effect);
1732 
1733  if (marker_effect != eNoEffect) {
1734  m_Effect = marker_effect; // marker_effect overrides the target effect
1735  }
1736 
1737  // Update hint window
1738  if (m_Effect != eNoEffect) {
1739  // hint visible, may be requires updates
1740  wxRect rc_hint = x_CalculateHintRect();
1741 
1742  //WM_POST(" m_HintWindow->SetSize(rc_hint) x " << rc_hint.x << " y " << rc_hint.y);
1743  m_HintWindow->SetSize(rc_hint);
1744 
1745  if ( ! m_HintWindow->IsShown()) {
1746  m_HintWindow->Raise();
1747  m_HintWindow->Show();
1748  }
1749  } else {
1750  if(m_HintWindow->IsShown()) {
1751  m_HintWindow->Hide();
1752  }
1753  }
1754  //WM_POST("CDockContainer::OnDrag() pos - " << sc_mouse_pos.x << ", " << sc_mouse_pos.y
1755  // << " m_Effect " << m_Effect);
1756 }
1757 
1758 // This function is called by Dock Manager during D&D docking session when
1759 // mouse pointer leaves the container or if sessions ends (drop or cancel)
1760 // The function returns Dock Effect and the target window that should be
1761 // modified (drop target).
1763 {
1764  //WM_POST("CDockContainer::OnEndDragOver()");
1765 
1766  EDockEffect effect = m_Effect;
1767  target = m_DragTarget;
1768 
1769  m_Effect = eNoEffect;
1770  m_DragTarget = NULL;
1771 
1772  m_MarkersWindow->Close();
1774 
1775  m_HintWindow->Close();
1776  m_HintWindow = NULL;
1777 
1778  return effect;
1779 }
1780 
1781 
1783 {
1784  return m_HintWindow && m_HintWindow->IsShown();
1785 }
1786 
1787 
1789 {
1790  //WM_POST("CDockContainer #" << m_Number << " (total " << m_Count << ")");
1791  //wxRect rc = ncbi::GetScreenRect(*this);
1792  //WM_POST(" rect " << ToString(rc));
1793 }
1794 
1795 
1797 {
1798  // traverse children recusrsively, find one that contains the point
1799  // and can perform hit testing
1800  IDockDropTarget* top_dock = NULL;
1801 
1802  for( wxWindow* curr_w = m_RootWindow; curr_w; ) {
1803  IDockDropTarget* dock = dynamic_cast<IDockDropTarget*>(curr_w);
1804  if (dock) {
1805  top_dock = dock;
1806  }
1807  wxPoint pt = curr_w->ScreenToClient(screen_pt);
1808 
1809  // find a child window containing the mouse position
1810  wxWindowList& children = curr_w->GetChildren();
1811  wxWindow* child_w = NULL;
1812  for( wxWindowList::iterator it = children.begin(); it != children.end(); ++it ) {
1813  wxWindow* w = *it;
1814  if (w->IsShown()) {
1815  wxRect rc = w->GetRect();
1816  if (rc.Contains(pt)) {
1817  child_w = w;
1818  break;
1819  }
1820  }
1821  }
1822  curr_w = child_w; // continue with child window
1823  }
1824  return top_dock;
1825 }
1826 
1827 
1828 EDockEffect CDockContainer::x_HitTest(const wxPoint& screen_pt,
1829  wxWindow*& target,
1830  bool split_tab_pane)
1831 {
1832  // the topmost in Z-order dock client that contains the given point
1833  IDockDropTarget* top_dock = x_FindDockDropTargetByPos(screen_pt);
1834 
1835  EDockEffect effect = eNoEffect;
1836  target = NULL;
1837 
1838  if (top_dock) {
1839  // perform hit testing in the found Dock Drop Target
1840  wxWindow* top_dock_w = dynamic_cast<wxWindow*>(top_dock);
1841  effect = top_dock->DropTest(screen_pt, target);
1842 
1843  if(effect != ePutInTab && ! split_tab_pane) {
1844  // do not split tabbed panes - split the tab control instead
1845  wxWindow* parent_w = top_dock_w->GetParent();
1846 
1847  if(parent_w && dynamic_cast<CDockNotebook*>(parent_w)) {
1848  top_dock = dynamic_cast<IDockDropTarget*>(parent_w);
1849  top_dock_w = dynamic_cast<wxWindow*>(top_dock);
1850 
1851  effect = top_dock->DropTest(screen_pt, target);
1852  if(effect == ePutInTab) {
1853  effect = eNoEffect;
1854  }
1855  }
1856  }
1857 
1858  target = top_dock_w;
1859  }
1860  //WM_POST("CDockContainer::x_HitTest() target " << target << " " << typeid(*target).name());
1861  return effect;
1862 }
1863 
1864 
1865 // For a given Dock Effect calculates a rectangle for Hint Window (screen coords)
1867 {
1868  wxRect root_rc = ncbi::GetScreenRect(*m_RootWindow);
1869  wxRect rc(root_rc);
1870 
1871  switch(m_Effect) {
1872  case eSplitLeft: {
1873  rc.width = rc.width / 3;
1874  break;
1875  }
1876  case eSplitRight: {
1877  rc.width = rc.width / 3;
1878  rc.x = root_rc.GetRight() - rc.width;
1879  break;
1880  }
1881  case eSplitTop: {
1882  rc.height = rc.height / 3;
1883  break;
1884  }
1885  case eSplitBottom: {
1886  rc.height = rc.height / 3;
1887  rc.y = root_rc.GetBottom() - rc.height;
1888  break;
1889  }
1890  default: {
1891  if (m_DragTarget) {
1892  wxRect target_rc = ncbi::GetScreenRect(*m_DragTarget);
1893  rc = target_rc;
1894 
1895  switch(m_Effect) {
1896  case eSplitTargetLeft: {
1897  rc.width = rc.width / 3;
1898  break;
1899  }
1900  case eSplitTargetRight: {
1901  rc.width = rc.width / 3;
1902  rc.x = target_rc.GetRight() - rc.width;
1903  break;
1904  }
1905  case eSplitTargetTop: {
1906  rc.height = rc.height / 3;
1907  break;
1908  }
1909  case eSplitTargetBottom: {
1910  rc.height = rc.height / 3;
1911  rc.y = target_rc.GetBottom() - rc.height;
1912  break;
1913  }
1914  case ePutInTab: {
1915  // if this is a tab - select the whole Tab Control
1916  CDockNotebook* notebook = dynamic_cast<CDockNotebook*>(m_DragTarget->GetParent());
1917  if (notebook)
1918  rc = ncbi::GetScreenRect(*notebook);
1919  break;
1920  }
1921  default:
1922  rc.SetSize(wxSize(-1, -1));
1923  }
1924  } else {
1925  rc.SetSize(wxSize(-1, -1));
1926  }
1927  }
1928  }
1929 
1930  //WM_POST("CDockContainer::x_CalculateHintRect() effect " << effect << " rect > " << ToString(rc));
1931  return rc;
1932 }
1933 
1934 
1936 {
1937  vector<IWMClient*> clients;
1938  GetClientsInWindow(page, clients);
1939 
1940  _ASSERT(clients.size());
1941 
1943 }
1944 
1945 
1947 {
1948  //WM_POST("CDockContainer::OnTabBeginDragOutside()");
1949 
1950  // now we will be handling mouse events instead of the Tab Control
1951  m_TabDockable = event.GetWindow();
1952 
1953  //WM_POST("CDockContainer - capturing mouse...");
1954  CaptureMouse();
1955 
1956  wxPoint sc_mouse_pos = ::wxGetMousePosition();
1957  m_DockManager.OnBeginDrag(*m_TabDockable, sc_mouse_pos);
1958 }
1959 
1960 
1961 // order of tab pages has changed - rearrange nodes in layout trees
1962 // according to the new order
1964 {
1965  TNode* node = x_FindNodeByWindow(&notebook);
1966  _ASSERT(node);
1967 
1968  if (node) {
1969  vector<wxWindow*> pages;
1970  for( size_t i = 0; i < notebook.GetPageCount(); i++ ) {
1971  pages.push_back(notebook.GetPage(i));
1972  }
1973  // update both Visible and Full trees
1974  node->EnforceChildOrder(pages);
1975  node->GetClone()->EnforceChildOrder(pages);
1976  }
1977 }
1978 
1979 
1980 ///////////////////////////////////////////////////////////////////////////////
1981 /// Mouse handling functions handle mouse events in case when a tab is dragged
1982 /// from a tab control and the component that originaly handled mouse input is
1983 /// destroyed as a result. In this case Dock Container captures mouse input
1984 /// and relays events to Dock Manager to support the D&D session.
1985 
1986 void CDockContainer::OnLeftDown(wxMouseEvent& event)
1987 {
1988  //WM_POST("CDockContainer::OnLeftDown");
1989  event.Skip();
1990 }
1991 
1992 
1993 void CDockContainer::OnLeftUp(wxMouseEvent& event)
1994 {
1995  //WM_POST("CDockContainer::OnLeftUp");
1996 
1997  if (HasCapture()) {
1998  //WM_POST("CDockContainer - releasing mouse...");
1999  ReleaseMouse();
2000  }
2001 
2002  if (m_TabDockable) {
2003  wxPoint sc_mouse_pos = ::wxGetMousePosition();
2004 
2006  }
2007 }
2008 
2009 
2010 void CDockContainer::OnMouseMove(wxMouseEvent& event)
2011 {
2012  //WM_POST("CDockContainer::OnMouseMove()");
2013 
2014  if (HasCapture()) {
2016 
2017  if (m_TabDockable) {
2018  wxPoint sc_mouse_pos = ::wxGetMousePosition();
2019  m_DockManager.OnDrag(*m_TabDockable, sc_mouse_pos);
2020  }
2021  }
2022 }
2023 
2024 
2025 void CDockContainer::OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event))
2026 {
2027  //WM_POST("CDockContainer::OnMouseCaptureLost()");
2028  // we have lost mouse capture and so we must cancel D&D session
2029  wxPoint sc_mouse_pos = ::wxGetMousePosition();
2031 }
2032 
2033 
2034 ///////////////////////////////////////////////////////////////////////////////
2035 /// Saving and Loading Layouts
2036 /// Loads a full layout tree from the given CUser_object
2037 /// IWMClientFactory is used for instantiating the clients refered by the layout
2038 
2040 {
2041  if (m_VisibleTree && m_VisibleTree->GetRoot()) {
2042  // delete the root window (no others should exist)
2043  CRef<TNode> vis_root = m_VisibleTree->GetRoot();
2044  x_DestroyNode(*vis_root->GetClone(), eDestroyWin);
2046  }
2047 }
2048 
2050 {
2052  return (it == m_WindowToNode.end()) ? NULL : it->second;
2053 }
2054 
2055 
2057 {
2058  bool failed = false;
2059  //Freeze();
2060  try {
2062  //process the Full Tree, remove all hidden clients and containers that have less than one child node
2063 
2064  tree.HideAll();
2065  tree.GetCentralPane()->SetHidden(false);
2066 
2067  //WM_POST("Loaded Full Tree ");
2068  //tree.LogPost();
2069 
2070  SetFullTree(tree);
2071 
2072  //WM_POST("Trees after clean-up");
2073  LogPostTrees("CDockContainer::ApplyLayout()");
2074 
2075  } catch(std::exception&) {
2076  failed = true;
2077  ERR_POST("CDockContainer::ApplyLayout() - error loading layout - ");
2078  }
2079 
2080  if (failed)
2082 
2083  //Thaw();
2084 }
2085 
2086 static const char* kWindowPos = "WindowPos";
2087 static const char* kXTag = "x";
2088 static const char* kYTag = "y";
2089 static const char* kWidthTag = "width";
2090 static const char* kHeightTag = "height";
2091 static const char* kMaximizedTag = "maximized";
2092 
2093 static CUser_object* sWindowPosToUserObject(const wxRect& rc, bool maximized)
2094 {
2095  CRef<CUser_object> pos(new CUser_object());
2096  pos->SetType().SetStr(kWindowPos);
2097  pos->AddField(kXTag, rc.x);
2098  pos->AddField(kYTag, rc.y);
2099  pos->AddField(kWidthTag, rc.width);
2100  pos->AddField(kHeightTag, rc.height);
2101  pos->AddField(kMaximizedTag, maximized);
2102  return pos.Release();
2103 }
2104 
2105 static void sWindowPosFromUserObject(const CUser_object& obj, wxRect& rc, bool& maximized)
2106 {
2107  rc.x = obj.GetField(kXTag).GetData().GetInt();
2108  rc.y = obj.GetField(kYTag).GetData().GetInt();
2109  rc.width = obj.GetField(kWidthTag).GetData().GetInt();
2110  rc.height = obj.GetField(kHeightTag).GetData().GetInt();
2111  maximized = obj.GetField(kMaximizedTag).GetData().GetBool();
2112 }
2113 
2114 static const char* kDockContainer = "DockContainer";
2115 static const char* kTreeTag = "Tree";
2116 
2118 {
2119  CRef<CUser_object> container;
2120 
2122  if (tree) {
2123  container.Reset(new CUser_object());
2124  container->SetType().SetStr(kDockContainer);
2125  container->AddField(kTreeTag, *tree);
2126 
2128  container->AddField(kWindowPos, *windowPos);
2129  }
2130 
2131  return container.ReleaseOrNull();
2132 }
2133 
2135 {
2137  wxRect rc;
2138  bool maximized = false;
2140  return new CDockContainerDescr(rc, maximized, tree);
2141 }
2142 
2144 {
2145  CRef<CUser_object> container;
2146 
2147  if (m_FullTree && NeedToSavePositions()) {
2149 
2151  x_Full_CleanLayoutTree(*treeClone);
2152  CRef<CUser_object> tree(treeClone->ToUserObject());
2153  if (tree) {
2154  container.Reset(new CUser_object());
2155  container->SetType().SetStr(kDockContainer);
2156 
2157  container->AddField(kTreeTag, *tree);
2158 
2159  wxFrame* frame = GetDockFrame();
2160  if (!frame) frame = mainFrame;
2161 
2162  if (frame) {
2163  CRef<CUser_object> windowPos(sWindowPosToUserObject(frame->GetRect(), frame->IsMaximized()));
2164  container->AddField(kWindowPos, *windowPos);
2165  }
2166  } else {
2167  _ASSERT(false);
2168  }
2169  }
2170 
2171  return container.ReleaseOrNull();
2172 }
2173 
static CDockContainerDescr * FromUserObject(const objects::CUser_object &obj)
CDockContainerDescr(wxPoint pos, wxSize size, bool maximized, CRef< CDockLayoutTree > tree)
CRef< CDockLayoutTree > m_Tree
objects::CUser_object * ToUserObject() const
CDockContainer is a window that hosts docked windows.
void x_Full_ReduceContainer(TNode &full_cont)
void x_Full_RemoveNode(TNode &full_node, ERemoveAction action)
bool HasDefaultPositionFor(const TFingerprint &fingerprint)
void OnBeginDragOver(const wxPoint &sc_mouse_pt)
EDockEffect x_HitTest(const wxPoint &screen_pt, wxWindow *&target, bool split_tab_pane)
CDockMarkerWindow * m_MarkersWindow
bool IsRootWindow(wxWindow *window)
void x_Full_ReduceHiddenContainer_IfNeeded(TNode &full_cont)
bool x_IsElastic(TNode &node)
EDockEffect OnEndDragOver(wxWindow *&target)
CDockPanel * x_DockPanelForClient(IWMClient &client)
void OnLeftUp(wxMouseEvent &event)
wxWindow * m_RootWindow
void x_GetClientsInNode(TNode &node, vector< IWMClient * > &clients)
void x_DestroyEmptyLayout()
Saving and Loading Layouts Loads a full layout tree from the given CUser_object IWMClientFactory is u...
CRef< CDockLayoutTree > m_FullTree
string x_GetPageNameByWindow(wxWindow *window)
CFloatingFrame * m_DockFrame
CRef< CDockLayoutTree > m_VisibleTree
CRef< TNode > RemoveWindow(IDockableWindow &dockable, ERemoveAction action)
void x_Visible_RemoveNode(TNode &node, ERemoveAction action)
Functions updating visible tree and windows based on the full tree.
IDockDropTarget * x_FindDockDropTargetByPos(const wxPoint &screen_pt)
void OnMouseCaptureLost(wxMouseCaptureLostEvent &event)
void OnMouseMove(wxMouseEvent &event)
void OnTabClosePressed(wxWindow *page)
TNode * x_FindNodeByWindow(wxWindow *window)
CDockLayoutTree::CNode TNode
ERemoveAction
describes
CDockManager & GetDockManager()
EDockEffect m_Effect
CFloatingFrame * GetDockFrame()
returns floating frame hosting this container
wxWindow * x_CreateContainerWindow(CDockLayoutTree::ENodeType type)
wxWindow * m_DragTarget
void x_SetRootWindow(wxWindow *window)
void x_AddClientInTab(CRef< TNode > full_client, CRef< TNode > full_target)
TWindowToNode m_WindowToNode
void OnLeftDown(wxMouseEvent &event)
Mouse handling functions handle mouse events in case when a tab is dragged from a tab control and the...
virtual bool Layout()
void OnTabBeginDragOutside(CBeginDragOutsideEvent &event)
void x_Visible_ReplaceContainerWithChild(TNode &cont)
void x_Full_CleanLayoutTreeBranch(TNode *centralPane, TNode &full_node)
Cleans the given tree starting from the given node.
void x_Full_DisconnectChildren(TNode &full_node)
Disconnect all child nodes from the given node in all 3 trees (Full Tree, Visible Tree and Window Tre...
void ApplyLayout(CDockLayoutTree &tree)
bool NeedToSavePositions()
void OnUpdateTabOrder(CDockNotebook &notebook)
CDockPanel * x_GetDockPanel(IWMClient &client)
void x_AddClientInSplitter(CRef< TNode > full_client, CRef< TNode > full_target, EDockEffect effect)
void x_Full_UnhideContainer_AddChildren(TNode &full_cont, TNode &full_vis_child, TNode &full_new_child)
void AddClientToDefaultLocation(IWMClient &client)
void GetClientsInWindow(wxWindow *window, vector< IWMClient * > &clients)
void x_InstantiateNode_AddChildWindows(TNode &full_node)
Iterates child windows of the given container node and inserts them into the container window.
virtual ~CDockContainer()
wxWindow * GetRootWindow()
returns window representing the root of the layout hosted by the container
void GetAllClients(vector< IWMClient * > &clients)
void x_Visible_ReplaceChildWithContainer(TNode &child, TNode &cont)
void x_DestroyNode(TNode &full_node, ERemoveAction action)
void SetFullTree(CDockLayoutTree &full_tree)
initialize the container with the layout tree
CDockManager & m_DockManager
TNode * x_AddClientToHiddenPos(IWMClient &client, CRef< TNode > full_node)
void OnDragOver(const wxPoint &sc_mouse_pt)
objects::CUser_object * SaveLayout(wxFrame *mainFrame)
wxRect x_CalculateHintRect()
wxWindow * m_HintWindow
void x_Full_CleanLayoutTree(CDockLayoutTree &full_ree)
This clean-up normalizes the tree, so that it can be instantiated as a layout.
void x_InstantiateNode(TNode &full_node, bool recursive, EInstFlags flags=fAll)
Ensures that a node has a window and this window is properly connected with its child and parent wind...
void AddClient(CRef< TNode > full_client, EDockEffect effect, wxWindow *target_w)
void x_Visible_AddChildToContainer(TNode &cont, TNode &child)
Adds a child to a visible node.
CDockLayoutTree::TNodeVector TNodeVector
void AddClientToCentralPane(CRef< TNode > full_client)
void BlockSplittersLayout(bool block)
Iterates through all splitters and blocks / unblocks layout.
CRef< CDockLayoutTree > DisconnectTrees()
void LogPostTrees(const string &test)
void ActivateClients(vector< IWMClient * > &clients)
IDockableWindow * m_TabDockable
bool HasNoWMClients()
returns true if Dock Container does not have any IWMClients as children
void x_InitDefaultTree(bool create_tab)
bool IsHintShown() const
CNode - a node in layout tree corresponding to a window.
Definition: dock_layout.hpp:77
CRef< CNode > GetTheOnlyChild()
Definition: dock_layout.cpp:85
void SetHidden(bool set)
Definition: dock_layout.hpp:98
ENodeType GetType() const
Definition: dock_layout.hpp:91
const vector< int > & GetSplitterSizes() const
bool IsVisible() const
Definition: dock_layout.hpp:99
void RemoveChild(CNode &node)
void SetWindow(wxWindow *window)
void AddChild(CNode &node)
CRef< CNode > GetParent()
bool DepthFirstSearch(F &func)
Inline functions.
void EnforceChildOrder(const vector< wxWindow * > &windows)
TNodeVector & GetChildren()
bool IsContainer() const
Definition: dock_layout.hpp:93
void Link(CNode &clone)
void SetFingerprint(const TFingerprint &p)
TFingerprint GetFingerprint() const
long GetBranchIndex(CNode &grandchild_node) const
bool IsSplitter() const
Definition: dock_layout.hpp:95
bool HasOnlyOneChild() const
size_t ReplaceChild(CNode &old_node, CNode &new_node)
CDockLayoutTree - represents hierarchical layout in a Dock Container as a tree where nodes correspond...
Definition: dock_layout.hpp:64
void LogPost() const
void SaveSplitterLayout()
CRef< CNode > m_Root
CDockLayoutTree * CloneTree() const
void Validate(const CNode &node, bool vis_tree) const
vector< CRef< CNode > > TNodeVector
CConstRef< CNode > GetRoot() const
CConstRef< CNode > GetCentralPane() const
objects::CUser_object * ToUserObject() const
static CRef< CDockLayoutTree > FromUserObject(const objects::CUser_object &obj)
bool DepthFirstSearch(F &func)
void DisconnectAllNodes()
CDockManager CDockManager sends requests to Window Manager, Window Manager makes decisions about dele...
wxWindow * GetTopAppWindow()
void OnBeginDrag(IDockableWindow &dockable, const wxPoint &sc_mouse_pos)
CDockContainer * GetMainContainer()
bool OnDrag(IDockableWindow &dockable, const wxPoint &sc_mouse_pos)
void OnTabClosePressed(const vector< IWMClient * > &clients)
void OnEndDrag(IDockableWindow &dockable, EDragResult result, const wxPoint &sc_mouse_pos)
CDockMarkerWindow - top level window with docking markers displayed on top of the application window.
Definition: dock_frames.hpp:62
virtual EDockEffect HitTest(const wxPoint &screen_pt)
determines whether a given position is inside one of the 9 markers and returns the corresponding dock...
void SetTargetRect(const wxRect &root_rc, const wxRect &target_rc)
CDockNotebook - an extended version of wxAuiNotebook capable of working with Dock Manager and Window ...
void InsertPageAtHitPoint(wxWindow *page, const wxString &caption)
void MakeSelectionVisible()
CDockPanel - a container with a title bar (caption) hosting a single client window (IWMClient).
Definition: dock_panel.hpp:73
virtual void ShowBorder(bool show)
Definition: dock_panel.cpp:132
void RemoveClient(wxWindow *new_parent)
disconnect the client and re-parent it to the given window
Definition: dock_panel.cpp:208
IWMClient * GetClient()
Definition: dock_panel.hpp:93
CDockSplitter = an extended version of CSplitter capable of working with Dock Manager and Window Mana...
void SetResizableCell(int col, int row)
Definition: splitter.cpp:321
void AddColumn()
Definition: splitter.cpp:407
void AddRow()
Definition: splitter.cpp:395
virtual void BlockLayout(bool block=true)
Definition: splitter.cpp:621
bool InsertToCell(wxWindow *child, int col, int row)
If cell [col, row] exists and vacant - adds widget to the container.
Definition: splitter.cpp:374
void SetWidths(const TPosVector &widths)
Definition: splitter.cpp:297
void SetHeights(const TPosVector &heights)
Definition: splitter.cpp:344
int GetRowsCount() const
Definition: splitter.cpp:285
@ eHorizontal
vertical space is splitted
Definition: splitter.hpp:64
virtual void Split(ESplitType type)
Creates a splitter with a single cell.
Definition: splitter.cpp:147
int GetColumnsCount() const
Definition: splitter.cpp:279
CUser_object & AddField(const string &label, const string &value, EParseField parse=eParse_String)
add a data field to the user object that holds a given value
const CUser_field & GetField(const string &str, const string &delim=".", NStr::ECase use_case=NStr::eCase) const
Access a named field in this user object.
Definition: User_object.cpp:71
FBlockSplitterLayout(bool block)
void operator()(CDockLayoutTree::CNode &node)
FClientCreator(CDockContainer &cont, IWMClientFactory *factory)
CDockContainer & m_DockContainer
IWMClientFactory * m_Factory
void operator()(CDockLayoutTree::CNode &node)
bool operator()(CDockLayoutTree::CNode &node)
CRef< CDockContainer::TNode > m_FoundNode
bool operator()(CDockLayoutTree::CNode &node)
IWMClient::CFingerprint m_Print
CRef< CDockLayoutTree::CNode > m_Node
FNodeFingerprintEquals(const IWMClient::CFingerprint &print)
bool operator()(CDockLayoutTree::CNode &node)
IDockContWindow - abstract window container for use with Dock Manager.
virtual void Cont_Replace(wxWindow *old_child, wxWindow *new_child)=0
virtual void Cont_Remove(wxWindow *child)=0
IDockDropTarget - interface representing a component that can serve as a drop target during D&D docki...
Definition: dock_window.hpp:83
virtual EDockEffect DropTest(const wxPoint &screen_pt, wxWindow *&target)=0
IDockableWindow - repersents a window that can be docked in Dock Manager.
Definition: dock_window.hpp:53
virtual void SetDockContainer(CDockContainer *cont)=0
IWMClientFactory - IWMClient factory.
Definition: wm_client.hpp:133
virtual IWMClient * CreateClient(const TFingerprint &fingerprint, wxWindow *parent)=0
creates a client by fingerprint returns NULL if fingerprint is not recognized.
CFingerprint identifies an instance of IWMClient and is used for labeling layout positions.
Definition: wm_client.hpp:58
const string GetId() const
IWClient - abstract Window Manager client.
Definition: wm_client.hpp:50
virtual string GetClientLabel(IWMClient::ELabel ltype=IWMClient::eDefault) const =0
returns the client label (name) to be displayed in UI
void erase(iterator pos)
Definition: map.hpp:167
const_iterator end() const
Definition: map.hpp:152
const_iterator find(const key_type &key) const
Definition: map.hpp:153
Definition: set.hpp:45
iterator_bool insert(const value_type &val)
Definition: set.hpp:149
const_iterator find(const key_type &key) const
Definition: set.hpp:137
const_iterator end() const
Definition: set.hpp:136
#define _(proto)
Definition: ct_nlmzip_i.h:78
static uch flags
static const char fp[]
Definition: des.c:87
USING_SCOPE(objects)
void sDockPanel_ShowBorder(wxWindow *w, bool show)
static const char * kYTag
void sRestoreSplitterSizes(CDockLayoutTree::CNode &full_node)
void sGetSplitSizes(int total_size, vector< int > &sizes, bool split_left)
static const char * kHeightTag
static CUser_object * sWindowPosToUserObject(const wxRect &rc, bool maximized)
wxDirection sGetDirectionByEffect(EDockEffect effect)
static const char * kDockContainer
static const char * kMaximizedTag
static const char * kWindowPos
static const char * kTreeTag
static const char * kXTag
static const char * kWidthTag
bool sRootSplit(EDockEffect effect)
static void sWindowPosFromUserObject(const CUser_object &obj, wxRect &rc, bool &maximized)
#define WM_POST(text)
#define EVT_BEGIN_DRAG_OUTSIDE(fn)
wxWindow * CreateDockHintFrame(wxWindow &parent, CDockManager &manager)
This functions create a platform-dependent Hint Window for Dock Manager.
EDockEffect
EDockEffect.
Definition: dock_window.hpp:65
@ eSplitBottom
Definition: dock_window.hpp:70
@ eSplitTargetLeft
Definition: dock_window.hpp:71
@ ePutInTab
Definition: dock_window.hpp:75
@ eSplitLeft
Definition: dock_window.hpp:67
@ eSplitTargetBottom
Definition: dock_window.hpp:74
@ eNoEffect
Definition: dock_window.hpp:66
@ eSplitTargetRight
Definition: dock_window.hpp:72
@ eSplitTargetTop
Definition: dock_window.hpp:73
@ eSplitTop
Definition: dock_window.hpp:69
@ eSplitRight
Definition: dock_window.hpp:68
int failed
Definition: dbmorecmds.c:10
#define test(a, b, c, d, e)
Definition: numeric.c:170
static FILE * f
Definition: readconf.c:23
#define NULL
Definition: ncbistd.hpp:225
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
Definition: ncbidiag.hpp:186
#define LOG_POST(message)
This macro is deprecated and it's strongly recomended to move in all projects (except tests) to macro...
Definition: ncbidiag.hpp:226
void Info(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1185
TObjectType * ReleaseOrNull(void)
Release a reference to the object and return a pointer to the object.
Definition: ncbiobj.hpp:816
TObjectType * GetPointer(void) THROWS_NONE
Get pointer,.
Definition: ncbiobj.hpp:998
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:773
TObjectType * Release(void)
Release a reference to the object and return a pointer to the object.
Definition: ncbiobj.hpp:846
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
static const char label[]
const TData & GetData(void) const
Get the Data member data.
TBool GetBool(void) const
Get the variant data.
TInt GetInt(void) const
Get the variant data.
const TObject & GetObject(void) const
Get the variant data.
void SetType(TType &value)
Assign a value to Type data member.
END_EVENT_TABLE()
int i
yy_size_t n
static void text(MDB_val *v)
Definition: mdb_dump.c:62
#define wxT(x)
Definition: muParser.cpp:41
const struct ncbi::grid::netcache::search::fields::SIZE size
static static static wxID_ANY
static sljit_uw total_size
static CNamedPipeClient * client
#define row(bind, expected)
Definition: string_bind.c:73
bool operator()(CDockLayoutTree::CNode &node)
CRef< CDockLayoutTree::CNode > m_Node
Definition: type.c:6
#define _ASSERT
wxString ToWxString(const string &s)
Definition: wx_utils.hpp:173
wxRect GetScreenRect(const wxWindow &win)
Definition: wx_utils.cpp:783
Modified on Fri Sep 20 14:57:06 2024 by modify_doxy.py rev. 669887