Fix tabbed area header select.
[gpl/argeo-suite.git] / core / org.argeo.suite.ui / src / org / argeo / suite / ui / widgets / TabbedArea.java
1 package org.argeo.suite.ui.widgets;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import javax.jcr.Node;
7
8 import org.argeo.cms.ui.CmsUiProvider;
9 import org.argeo.cms.ui.util.CmsUiUtils;
10 import org.argeo.cms.ui.viewers.Section;
11 import org.argeo.eclipse.ui.Selected;
12 import org.argeo.jcr.Jcr;
13 import org.eclipse.swt.SWT;
14 import org.eclipse.swt.custom.StackLayout;
15 import org.eclipse.swt.graphics.Image;
16 import org.eclipse.swt.layout.GridData;
17 import org.eclipse.swt.layout.GridLayout;
18 import org.eclipse.swt.widgets.Button;
19 import org.eclipse.swt.widgets.Composite;
20 import org.eclipse.swt.widgets.Control;
21 import org.eclipse.swt.widgets.Label;
22 import org.eclipse.swt.widgets.ToolBar;
23 import org.eclipse.swt.widgets.ToolItem;
24
25 /** Manages {@link Section} in a tab-like structure. */
26 public class TabbedArea extends Composite {
27         private static final long serialVersionUID = 8659669229482033444L;
28
29         private Composite headers;
30         private Composite body;
31
32         private List<Section> sections = new ArrayList<>();
33
34         private Node previousNode;
35         private CmsUiProvider previousUiProvider;
36         private CmsUiProvider currentUiProvider;
37
38         private String tabStyle;
39         private String tabSelectedStyle;
40         private String bodyStyle;
41         private Image closeIcon;
42
43         private StackLayout stackLayout;
44
45         private boolean singleTab = false;
46
47         public TabbedArea(Composite parent, int style) {
48                 super(parent, style);
49                 CmsUiUtils.style(parent, bodyStyle);
50
51                 setLayout(CmsUiUtils.noSpaceGridLayout());
52
53                 // TODO manage tabs at bottom or sides
54                 headers = new Composite(this, SWT.NONE);
55                 headers.setLayoutData(CmsUiUtils.fillWidth());
56                 body = new Composite(this, SWT.NONE);
57                 body.setLayoutData(CmsUiUtils.fillAll());
58                 // body.setLayout(new FormLayout());
59                 stackLayout = new StackLayout();
60                 body.setLayout(stackLayout);
61                 emptyState();
62         }
63
64         protected void refreshTabHeaders() {
65                 int tabCount = sections.size() > 0 ? sections.size() : 1;
66                 for (Control tab : headers.getChildren())
67                         tab.dispose();
68
69                 headers.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(tabCount, true)));
70
71                 if (sections.size() == 0) {
72                         Composite emptyHeader = new Composite(headers, SWT.NONE);
73                         emptyHeader.setLayoutData(CmsUiUtils.fillAll());
74                         emptyHeader.setLayout(new GridLayout());
75                         Label lbl = new Label(emptyHeader, SWT.NONE);
76                         lbl.setText("");
77                         lbl.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
78
79                 }
80
81                 Section currentSection = getCurrentSection();
82                 for (Section section : sections) {
83                         boolean selected = section == currentSection;
84                         Composite sectionHeader = section.createHeader(headers);
85                         CmsUiUtils.style(sectionHeader, selected ? tabSelectedStyle : tabStyle);
86                         int headerColumns = singleTab ? 1 : 2;
87                         sectionHeader.setLayout(new GridLayout(headerColumns, false));
88                         sectionHeader.setLayout(CmsUiUtils.noSpaceGridLayout(headerColumns));
89                         Button title = new Button(sectionHeader, SWT.FLAT);
90                         CmsUiUtils.style(title, selected ? tabSelectedStyle : tabStyle);
91                         title.setLayoutData(CmsUiUtils.fillWidth());
92                         title.addSelectionListener((Selected) (e) -> showTab(tabIndex(section.getNode())));
93                         Node node = section.getNode();
94                         title.setText(Jcr.getTitle(node));
95                         if (!singleTab) {
96                                 ToolBar toolBar = new ToolBar(sectionHeader, SWT.NONE);
97                                 ToolItem closeItem = new ToolItem(toolBar, SWT.FLAT);
98                                 if (closeIcon != null)
99                                         closeItem.setImage(closeIcon);
100                                 else
101                                         closeItem.setText("X");
102                                 CmsUiUtils.style(closeItem, selected ? tabSelectedStyle : tabStyle);
103                                 closeItem.addSelectionListener((Selected) (e) -> closeTab(section));
104                         }
105                 }
106
107         }
108
109         public void view(CmsUiProvider uiProvider, Node context) {
110                 if (body.isDisposed())
111                         return;
112                 int index = tabIndex(context);
113                 if (index >= 0) {
114                         showTab(index);
115                         previousNode = context;
116                         previousUiProvider = uiProvider;
117                         return;
118                 }
119                 Section section = (Section) body.getChildren()[0];
120                 previousNode = section.getNode();
121                 if (previousNode == null) {// empty state
122                         previousNode = context;
123                         previousUiProvider = uiProvider;
124                 } else {
125                         previousUiProvider = currentUiProvider;
126                 }
127                 currentUiProvider = uiProvider;
128                 section.setNode(context);
129                 // section.setLayoutData(CmsUiUtils.coverAll());
130                 build(section, uiProvider, context);
131                 if (sections.size() == 0)
132                         sections.add(section);
133                 refreshTabHeaders();
134                 index = tabIndex(context);
135                 showTab(index);
136                 layout(true, true);
137         }
138
139         public void open(CmsUiProvider uiProvider, Node context) {
140                 if (singleTab)
141                         throw new UnsupportedOperationException("Open is not supported in single tab mode.");
142
143                 if (previousNode != null && Jcr.getIdentifier(previousNode).equals(Jcr.getIdentifier(context))) {
144                         // does nothing
145                         return;
146                 }
147                 if (sections.size() == 0)
148                         CmsUiUtils.clear(body);
149                 Section currentSection = getCurrentSection();
150                 int currentIndex = sections.indexOf(currentSection);
151                 Section previousSection = new Section(body, SWT.NONE, context);
152                 build(previousSection, previousUiProvider, previousNode);
153                 // previousSection.setLayoutData(CmsUiUtils.coverAll());
154                 int index = currentIndex + 1;
155                 sections.add(index, previousSection);
156                 showTab(index);
157                 refreshTabHeaders();
158                 layout(true, true);
159         }
160
161         public void showTab(int index) {
162                 Section sectionToShow = sections.get(index);
163                 // sectionToShow.moveAbove(null);
164                 stackLayout.topControl = sectionToShow;
165                 refreshTabHeaders();
166                 layout(true, true);
167         }
168
169         protected void build(Section section, CmsUiProvider uiProvider, Node context) {
170                 for (Control child : section.getChildren())
171                         child.dispose();
172                 CmsUiUtils.style(section, bodyStyle);
173                 section.setNode(context);
174                 uiProvider.createUiPart(section, context);
175
176         }
177
178         private int tabIndex(Node node) {
179                 for (int i = 0; i < sections.size(); i++) {
180                         Section section = sections.get(i);
181                         if (Jcr.getIdentifier(section.getNode()).equals(Jcr.getIdentifier(node)))
182                                 return i;
183                 }
184                 return -1;
185         }
186
187         public void closeTab(Section section) {
188                 int currentIndex = sections.indexOf(section);
189                 int nextIndex = currentIndex == 0 ? 0 : currentIndex - 1;
190                 sections.remove(section);
191                 section.dispose();
192                 if (sections.size() == 0) {
193                         emptyState();
194                         refreshTabHeaders();
195                         layout(true, true);
196                         return;
197                 }
198                 refreshTabHeaders();
199                 showTab(nextIndex);
200         }
201
202         protected void emptyState() {
203                 new Section(body, SWT.NONE, null);
204                 refreshTabHeaders();
205         }
206
207         public Composite getCurrent() {
208                 return getCurrentSection();
209         }
210
211         protected Section getCurrentSection() {
212                 return (Section) stackLayout.topControl;
213         }
214
215         public void setTabStyle(String tabStyle) {
216                 this.tabStyle = tabStyle;
217         }
218
219         public void setTabSelectedStyle(String tabSelectedStyle) {
220                 this.tabSelectedStyle = tabSelectedStyle;
221         }
222
223         public void setBodyStyle(String bodyStyle) {
224                 this.bodyStyle = bodyStyle;
225         }
226
227         public void setCloseIcon(Image closeIcon) {
228                 this.closeIcon = closeIcon;
229         }
230
231         public void setSingleTab(boolean singleTab) {
232                 this.singleTab = singleTab;
233         }
234
235 }