From: Mathieu Baudier Date: Sun, 7 Feb 2021 12:12:31 +0000 (+0100) Subject: Merge remote-tracking branch 'origin/master' into v2.x X-Git-Tag: argeo-suite-2.1.19~4 X-Git-Url: https://git.argeo.org/?p=gpl%2Fargeo-suite.git;a=commitdiff_plain;h=bf2b76df49da4a94e37d539ef15d676a9fa58359;hp=54163670f28cbd809c691c52f545e3669ae7888c Merge remote-tracking branch 'origin/master' into v2.x --- diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultEditionLayer.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultEditionLayer.java index 7b8bb3e..9c2ad47 100644 --- a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultEditionLayer.java +++ b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultEditionLayer.java @@ -7,16 +7,19 @@ import java.util.Map; import javax.jcr.Node; import javax.jcr.RepositoryException; +import org.argeo.cms.Localized; import org.argeo.cms.ui.CmsTheme; import org.argeo.cms.ui.CmsUiProvider; import org.argeo.cms.ui.util.CmsUiUtils; -import org.argeo.cms.ui.widgets.TabbedArea; +import org.argeo.suite.ui.widgets.TabbedArea; import org.argeo.util.LangUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; +import org.osgi.framework.BundleContext; +import org.osgi.framework.wiring.BundleWiring; /** An app layer based on an entry area and an editor area. */ public class DefaultEditionLayer implements SuiteLayer { @@ -24,6 +27,7 @@ public class DefaultEditionLayer implements SuiteLayer { private CmsUiProvider workArea; private List weights = new ArrayList<>(); private boolean startMaximized = false; + private Localized title = null; @Override public Control createUi(Composite parent, Node context) throws RepositoryException { @@ -64,12 +68,43 @@ public class DefaultEditionLayer implements SuiteLayer { tabbedArea.open(uiProvider, context); } - public void init(Map properties) { + @Override + public Localized getTitle() { + return title; + } + + public void init(BundleContext bundleContext, Map properties) { weights = LangUtils.toStringList(properties.get(Property.weights.name())); startMaximized = properties.containsKey(Property.startMaximized.name()) && "true".equals(properties.get(Property.startMaximized.name())); + + String titleStr = (String) properties.get(SuiteLayer.Property.title.name()); + if (titleStr != null) { + if (titleStr.startsWith("%")) { + title = new Localized() { + + @Override + public String name() { + return titleStr; + } + + @Override + public ClassLoader getL10nClassLoader() { + return bundleContext != null + ? bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader() + : getClass().getClassLoader(); + } + }; + } else { + title = new Localized.Untranslated(titleStr); + } + } } + public void destroy() { + + } + public void setEntryArea(CmsUiProvider entryArea) { this.entryArea = entryArea; } diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultHeader.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultHeader.java index 692a23b..080bac2 100644 --- a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultHeader.java +++ b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultHeader.java @@ -7,7 +7,7 @@ import java.util.TreeMap; import javax.jcr.Node; import javax.jcr.RepositoryException; -import org.argeo.cms.LocaleUtils; +import org.argeo.cms.Localized; import org.argeo.cms.auth.CurrentUser; import org.argeo.cms.ui.CmsTheme; import org.argeo.cms.ui.CmsUiProvider; @@ -23,14 +23,18 @@ import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; +import org.osgi.framework.BundleContext; +import org.osgi.framework.wiring.BundleWiring; import org.osgi.service.cm.ConfigurationException; import org.osgi.service.cm.ManagedService; -/** HEader of a standard Argeo Suite applicaiton. */ +/** HEader of a standard Argeo Suite application. */ public class DefaultHeader implements CmsUiProvider, ManagedService { public final static String TITLE_PROPERTY = "argeo.suite.ui.header.title"; private Map properties; + private Localized title = null; + @Override public Control createUi(Composite parent, Node context) throws RepositoryException { CmsView cmsView = CmsView.getCmsView(parent); @@ -44,9 +48,11 @@ public class DefaultHeader implements CmsUiProvider, ManagedService { lead.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, false)); lead.setLayout(new GridLayout()); Label lbl = new Label(lead, SWT.NONE); - String title = properties.get(TITLE_PROPERTY); - lbl.setText(LocaleUtils.isLocaleKey(title) ? LocaleUtils.local(title, getClass().getClassLoader()).toString() - : title); +// String title = properties.get(TITLE_PROPERTY); +// // TODO expose the localized +// lbl.setText(LocaleUtils.isLocaleKey(title) ? LocaleUtils.local(title, getClass().getClassLoader()).toString() +// : title); + lbl.setText(title.lead()); CmsUiUtils.style(lbl, SuiteStyle.headerTitle); lbl.setLayoutData(CmsUiUtils.fillWidth()); @@ -85,8 +91,33 @@ public class DefaultHeader implements CmsUiProvider, ManagedService { return lbl; } - public void init(Map properties) { + public void init(BundleContext bundleContext, Map properties) { this.properties = new TreeMap<>(properties); + String titleStr = (String) properties.get(TITLE_PROPERTY); + if (titleStr != null) { + if (titleStr.startsWith("%")) { + title = new Localized() { + + @Override + public String name() { + return titleStr; + } + + @Override + public ClassLoader getL10nClassLoader() { + return bundleContext != null + ? bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader() + : getClass().getClassLoader(); + } + }; + } else { + title = new Localized.Untranslated(titleStr); + } + } + } + + public void destroy() { + } @Override @@ -95,4 +126,8 @@ public class DefaultHeader implements CmsUiProvider, ManagedService { this.properties.putAll(LangUtils.dictToStringMap(properties)); } + public Localized getTitle() { + return title; + } + } diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLeadPane.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLeadPane.java index 9a5248e..10d386c 100644 --- a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLeadPane.java +++ b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/DefaultLeadPane.java @@ -87,15 +87,16 @@ public class DefaultLeadPane implements CmsUiProvider { } RankedObject layerObj = layers.get(layerId); - // TODO deal with i10n - String titleStr = (String) layerObj.getProperties().get(SuiteLayer.Property.title.name()); Localized title = null; - if (titleStr != null) { - if (titleStr.startsWith("%")) { - // LocaleUtils.local(titleStr, getClass().getClassLoader()); - title = () -> titleStr; - } else { - title = new Localized.Untranslated(titleStr); + if (!adminLayers.contains(layerId)) { + String titleStr = (String) layerObj.getProperties().get(SuiteLayer.Property.title.name()); + if (titleStr != null) { + if (titleStr.startsWith("%")) { + // LocaleUtils.local(titleStr, getClass().getClassLoader()); + title = () -> titleStr; + } else { + title = new Localized.Untranslated(titleStr); + } } } @@ -114,41 +115,9 @@ public class DefaultLeadPane implements CmsUiProvider { first = b; } } - -// if (isAdmin && adminLayers != null) -// for (String layerId : adminLayers) { -// if (layers.containsKey(layerId)) { -// RankedObject layerObj = layers.get(layerId); -// -// String titleStr = (String) layerObj.getProperties().get(SuiteLayer.Property.title.name()); -// Localized title = null; -// if (titleStr != null) -// title = new Localized.Untranslated(titleStr); -// -// String iconName = (String) layerObj.getProperties().get(SuiteLayer.Property.icon.name()); -// SuiteIcon icon = null; -// if (iconName != null) -// icon = SuiteIcon.valueOf(iconName); -// -// Button b = SuiteUiUtils.createLayerButton(parent, layerId, title, icon); -// if (first == null) -// first = b; -// } -// } - -// Button dashboardB = createButton(parent, SuiteMsg.dashboard.name(), SuiteMsg.dashboard, SuiteIcon.dashboard); - if (!cmsView.isAnonymous()) { -// createButton(parent, SuiteMsg.documents.name(), SuiteMsg.documents, SuiteIcon.documents); -// createButton(parent, SuiteMsg.people.name(), SuiteMsg.people, SuiteIcon.people); -// createButton(parent, SuiteMsg.locations.name(), SuiteMsg.locations, SuiteIcon.location); - } return first; } - protected void processLayer(String layerDef) { - - } - public void init(Map properties) { String[] defaultLayers = (String[]) properties.get(Property.defaultLayers.toString()); if (defaultLayers == null) @@ -193,7 +162,7 @@ public class DefaultLeadPane implements CmsUiProvider { if (msg != null) { Label lbl = new Label(parent, SWT.CENTER); CmsUiUtils.style(lbl, SuiteStyle.leadPane); - //CmsUiUtils.markup(lbl); + // CmsUiUtils.markup(lbl); ClassLoader l10nClassLoader = getClass().getClassLoader(); String txt = LocaleUtils.lead(msg, l10nClassLoader); // String txt = msg.lead(); diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteApp.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteApp.java index dc8060b..e8bfa5f 100644 --- a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteApp.java +++ b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteApp.java @@ -24,13 +24,13 @@ import org.apache.commons.logging.LogFactory; import org.argeo.api.NodeUtils; import org.argeo.cms.CmsUserManager; import org.argeo.cms.LocaleUtils; +import org.argeo.cms.Localized; import org.argeo.cms.auth.CmsSession; import org.argeo.cms.ui.AbstractCmsApp; import org.argeo.cms.ui.CmsTheme; import org.argeo.cms.ui.CmsUiProvider; import org.argeo.cms.ui.CmsView; import org.argeo.cms.ui.dialogs.CmsFeedback; -import org.argeo.cms.ui.util.CmsEvent; import org.argeo.cms.ui.util.CmsUiUtils; import org.argeo.eclipse.ui.specific.UiContext; import org.argeo.entity.EntityConstants; @@ -54,6 +54,7 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler { public final static String PUBLIC_BASE_PATH_PROPERTY = "publicBasePath"; public final static String DEFAULT_UI_NAME_PROPERTY = "defaultUiName"; public final static String DEFAULT_THEME_ID_PROPERTY = "defaultThemeId"; + private final static String LOGIN = "login"; private String publicBasePath = null; @@ -61,8 +62,8 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler { private String headerPid; private String leadPanePid; private String loginScreenPid; -// private String DASHBOARD_PID = pidPrefix + "dashboard"; -// private String RECENT_ITEMS_PID = pidPrefix + "recentItems"; + + private String defaultLayerPid = "argeo.suite.ui.dashboardLayer"; private String defaultUiName = "app"; private String defaultThemeId = "org.argeo.suite.theme.default"; @@ -77,8 +78,6 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler { // TODO make more optimal or via CmsSession/CmsView private Map managedUis = new HashMap<>(); -// private CmsUiProvider headerPart = null; - public void init(Map properties) { if (log.isDebugEnabled()) log.info("Argeo Suite App started"); @@ -151,12 +150,20 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler { Node context = null; SuiteUi ui = (SuiteUi) parent; CmsView cmsView = CmsView.getCmsView(parent); + CmsUiProvider headerUiProvider = findUiProvider(headerPid); + Localized appTitle = null; + if (headerUiProvider instanceof DefaultHeader) { + appTitle = ((DefaultHeader) headerUiProvider).getTitle(); + } + ui.setTitle(appTitle); + if (cmsView.isAnonymous() && publicBasePath == null) {// internal app, must login ui.logout(); - refreshPart(findUiProvider(headerPid), ui.getHeader(), context); + refreshPart(headerUiProvider, ui.getHeader(), context); ui.refreshBelowHeader(false); refreshPart(findUiProvider(loginScreenPid), ui.getBelowHeader(), context); ui.layout(true, true); + setState(ui, LOGIN); } else { CmsSession cmsSession = cmsView.getCmsSession(); if (ui.getUserDir() == null) { @@ -179,7 +186,7 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler { if (context == null) context = ui.getUserDir(); - refreshPart(findUiProvider(headerPid), ui.getHeader(), context); + refreshPart(headerUiProvider, ui.getHeader(), context); ui.refreshBelowHeader(true); for (String key : layersByPid.keySet()) { SuiteLayer layer = layersByPid.get(key).get(); @@ -187,7 +194,7 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler { } refreshPart(findUiProvider(leadPanePid), ui.getLeadPane(), context); ui.layout(true, true); - setState(parent, state); + setState(parent, state != null ? state : defaultLayerPid); } } catch (Exception e) { CmsFeedback.show("Unexpected exception", e); @@ -214,6 +221,12 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler { return uiProvidersByPid.get(pid).get(); } + private SuiteLayer findLayer(String pid) { + if (!layersByPid.containsKey(pid)) + throw new IllegalArgumentException("No UI provider registered as " + pid); + return layersByPid.get(pid).get(); + } + private T findByType(Map> byType, Node context) { if (context == null) throw new IllegalArgumentException("A node should be provided"); @@ -269,11 +282,18 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler { @Override public void setState(Composite parent, String state) { - if (state == null || state.equals("~")) + if (state == null) return; - if (!state.startsWith("/") && !state.equals("~")) { + if (!state.startsWith("/")) { if (parent instanceof SuiteUi) { SuiteUi ui = (SuiteUi) parent; + if (LOGIN.equals(state) || state.equals("~")) { + String appTitle = ""; + if (ui.getTitle() != null) + appTitle = ui.getTitle().lead(); + ui.getCmsView().stateChanged(state, appTitle); + return; + } String currentLayerId = ui.getCurrentLayerId(); if (state.equals(currentLayerId)) return; // does nothing @@ -343,9 +363,13 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler { if (ui == null) return; try { + String appTitle = ""; + if (ui.getTitle() != null) + appTitle = ui.getTitle().lead() + " - "; + // String currentLayerId = ui.getCurrentLayerId(); // SuiteLayer currentLayer = currentLayerId != null ? layersByPid.get(currentLayerId).get() : null; - if (isTopic(event, SuiteEvent.refreshPart)) { + if (SuiteUiUtils.isTopic(event, SuiteEvent.refreshPart)) { Node node = getNode(ui, event); if (node == null) return; @@ -353,8 +377,8 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler { SuiteLayer layer = findByType(layersByType, node); ui.switchToLayer(layer, node); ui.getCmsView().runAs(() -> layer.view(uiProvider, ui.getCurrentWorkArea(), node)); - ui.getCmsView().stateChanged(nodeToState(node), Jcr.getTitle(node)); - } else if (isTopic(event, SuiteEvent.openNewPart)) { + ui.getCmsView().stateChanged(nodeToState(node), appTitle + Jcr.getTitle(node)); + } else if (SuiteUiUtils.isTopic(event, SuiteEvent.openNewPart)) { Node node = getNode(ui, event); if (node == null) return; @@ -362,13 +386,18 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler { SuiteLayer layer = findByType(layersByType, node); ui.switchToLayer(layer, node); ui.getCmsView().runAs(() -> layer.open(uiProvider, ui.getCurrentWorkArea(), node)); - ui.getCmsView().stateChanged(nodeToState(node), Jcr.getTitle(node)); - } else if (isTopic(event, SuiteEvent.switchLayer)) { + ui.getCmsView().stateChanged(nodeToState(node), appTitle + Jcr.getTitle(node)); + } else if (SuiteUiUtils.isTopic(event, SuiteEvent.switchLayer)) { String layerId = get(event, SuiteEvent.LAYER); if (layerId != null) { // ui.switchToLayer(layerId, ui.getUserDir()); + SuiteLayer suiteLayer = findLayer(layerId); + Localized layerTitle = suiteLayer.getTitle(); ui.getCmsView().runAs(() -> ui.switchToLayer(layerId, ui.getUserDir())); - ui.getCmsView().navigateTo(layerId); + String title = null; + if (layerTitle != null) + title = layerTitle.lead(); + ui.getCmsView().stateChanged(layerId, appTitle + title); } else { Node node = getNode(ui, event); if (node != null) { @@ -426,11 +455,7 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler { return managedUis.get(get(event, CMS_VIEW_UID_PROPERTY)); } - private static boolean isTopic(Event event, CmsEvent cmsEvent) { - return event.getTopic().equals(cmsEvent.topic()); - } - - private static String get(Event event, String key) { + public static String get(Event event, String key) { Object value = event.getProperty(key); if (value == null) return null; diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteLayer.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteLayer.java index 8af7611..994ea84 100644 --- a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteLayer.java +++ b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteLayer.java @@ -2,6 +2,7 @@ package org.argeo.suite.ui; import javax.jcr.Node; +import org.argeo.cms.Localized; import org.argeo.cms.ui.CmsUiProvider; import org.eclipse.swt.widgets.Composite; @@ -16,4 +17,8 @@ public interface SuiteLayer extends CmsUiProvider { default void open(CmsUiProvider uiProvider, Composite workArea, Node context) { view(uiProvider, workArea, context); } + + default Localized getTitle() { + return null; + } } diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUi.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUi.java index b245762..3c4474f 100644 --- a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUi.java +++ b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUi.java @@ -11,6 +11,7 @@ import javax.jcr.Session; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.api.NodeConstants; +import org.argeo.cms.Localized; import org.argeo.cms.ui.CmsView; import org.argeo.cms.ui.util.CmsUiUtils; import org.argeo.jcr.Jcr; @@ -22,6 +23,8 @@ import org.eclipse.swt.widgets.Composite; class SuiteUi extends Composite { private static final long serialVersionUID = 6207018859086689108L; private final static Log log = LogFactory.getLog(SuiteUi.class); + + private Localized title; private Composite header; private Composite belowHeader; private Composite leadPane; @@ -223,4 +226,12 @@ class SuiteUi extends Composite { return cmsView; } + public Localized getTitle() { + return title; + } + + public void setTitle(Localized title) { + this.title = title; + } + } diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUiUtils.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUiUtils.java index 3c47b96..79edb64 100644 --- a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUiUtils.java +++ b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteUiUtils.java @@ -12,6 +12,7 @@ import org.argeo.cms.auth.CurrentUser; import org.argeo.cms.ui.CmsEditable; import org.argeo.cms.ui.CmsView; import org.argeo.cms.ui.dialogs.LightweightDialog; +import org.argeo.cms.ui.util.CmsEvent; import org.argeo.cms.ui.util.CmsUiUtils; import org.argeo.eclipse.ui.EclipseUiUtils; import org.argeo.entity.EntityNames; @@ -32,6 +33,7 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; +import org.osgi.service.event.Event; /** UI utilities related to the APAF project. */ public class SuiteUiUtils { @@ -318,6 +320,10 @@ public class SuiteUiUtils { return coworker; } + public static boolean isTopic(Event event, CmsEvent cmsEvent) { + return event.getTopic().equals(cmsEvent.topic()); + } + // public static String createAndConfigureEntity(Shell shell, Session referenceSession, String mainMixin, // String... additionnalProps) { // diff --git a/core/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/TabbedArea.java b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/TabbedArea.java new file mode 100644 index 0000000..5192f84 --- /dev/null +++ b/core/org.argeo.suite.ui/src/org/argeo/suite/ui/widgets/TabbedArea.java @@ -0,0 +1,244 @@ +package org.argeo.suite.ui.widgets; + +import java.util.ArrayList; +import java.util.List; + +import javax.jcr.Node; + +import org.argeo.cms.ui.CmsUiProvider; +import org.argeo.cms.ui.util.CmsUiUtils; +import org.argeo.cms.ui.viewers.Section; +import org.argeo.eclipse.ui.Selected; +import org.argeo.jcr.Jcr; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.FormLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; + +/** Manages {@link Section} in a tab-like structure. */ +public class TabbedArea extends Composite { + private static final long serialVersionUID = 8659669229482033444L; + + private Composite headers; + private Composite body; + + private List
sections = new ArrayList<>(); + + private Node previousNode; + private CmsUiProvider previousUiProvider; + private CmsUiProvider currentUiProvider; + + private String tabStyle; + private String tabSelectedStyle; + private String bodyStyle; + private Image closeIcon; + + public TabbedArea(Composite parent, int style) { + super(parent, style); + CmsUiUtils.style(parent, bodyStyle); + + setLayout(CmsUiUtils.noSpaceGridLayout()); + + // TODO manage tabs at bottom or sides + headers = new Composite(this, SWT.NONE); + headers.setLayoutData(CmsUiUtils.fillWidth()); + // CmsUiUtils.style(headers, bodyStyle); + body = new Composite(this, SWT.NONE); + body.setLayoutData(CmsUiUtils.fillAll()); + body.setLayout(new FormLayout()); + emptyState(); + } + + protected void refreshTabHeaders() { + // TODO deal with initialisation better +// CmsUiUtils.style(body, bodyStyle); + +// int tabCount = sections.size() > 0 ?(sections.size()>1?sections.size()+1:1) : 1; + int tabCount = sections.size() > 0 ? sections.size() : 1; + for (Control tab : headers.getChildren()) + tab.dispose(); + +// GridLayout headersGridLayout = new GridLayout(tabCount, true); +// headersGridLayout.marginHeight=0; +// headers.setLayout(headersGridLayout); + headers.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(tabCount, true))); + + if (sections.size() == 0) { + Composite emptyHeader = new Composite(headers, SWT.NONE); + emptyHeader.setLayoutData(CmsUiUtils.fillAll()); + emptyHeader.setLayout(new GridLayout()); + Label lbl = new Label(emptyHeader, SWT.NONE); + lbl.setText(""); + lbl.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false)); + + } + + Section currentSection = getCurrentSection(); + for (Section section : sections) { + boolean selected = section == currentSection; + Composite sectionHeader = section.createHeader(headers); + CmsUiUtils.style(sectionHeader, selected ? tabSelectedStyle : tabStyle); + int headerColumns = 2; + sectionHeader.setLayout(new GridLayout(headerColumns, false)); + sectionHeader.setLayout(CmsUiUtils.noSpaceGridLayout(headerColumns)); + Button title = new Button(sectionHeader, SWT.FLAT); + CmsUiUtils.style(title, selected ? tabSelectedStyle : tabStyle); + title.setLayoutData(CmsUiUtils.fillWidth()); + title.addSelectionListener((Selected) (e) -> showTab(tabIndex(section.getNode()))); + Node node = section.getNode(); + title.setText(Jcr.getTitle(node)); + ToolBar toolBar = new ToolBar(sectionHeader, SWT.NONE); +// CmsUiUtils.style(toolBar, selected ? tabSelectedStyle : tabStyle); + ToolItem closeItem = new ToolItem(toolBar, SWT.FLAT); + if (closeIcon != null) + closeItem.setImage(closeIcon); + else + closeItem.setText("X"); + CmsUiUtils.style(closeItem, selected ? tabSelectedStyle : tabStyle); + closeItem.addSelectionListener((Selected) (e) -> closeTab(section)); + } + +// if(sections.size()>1) +// { +// ToolBar toolBar = new ToolBar(headers, SWT.NONE); +// CmsUiUtils.style(toolBar, tabStyle); +// ToolItem closeAllItem = new ToolItem(toolBar, SWT.FLAT); +// closeAllItem.setText("X"); +// } + } + + public void view(CmsUiProvider uiProvider, Node context) { + if (body.isDisposed()) + return; + int index = tabIndex(context); + if (index >= 0) { + showTab(index); + previousNode = context; + previousUiProvider = uiProvider; + return; + } + Section section = (Section) body.getChildren()[0]; + previousNode = section.getNode(); + if (previousNode == null) {// empty state + previousNode = context; + previousUiProvider = uiProvider; + } else { + previousUiProvider = currentUiProvider; + } + currentUiProvider = uiProvider; + section.setNode(context); + section.setLayoutData(CmsUiUtils.coverAll()); + build(section, uiProvider, context); + if (sections.size() == 0) + sections.add(section); + refreshTabHeaders(); + layout(true, true); + } + + public void open(CmsUiProvider uiProvider, Node context) { +// try { +// if (openingTimer > 0) +// Thread.sleep(openingTimer); +// } catch (InterruptedException e) { +// // silent +// } + + // int index = tabIndex(context); + if (previousNode != null && Jcr.getIdentifier(previousNode).equals(Jcr.getIdentifier(context))) { + // does nothing + return; + } + if (sections.size() == 0) + CmsUiUtils.clear(body); + Section currentSection = getCurrentSection(); + int currentIndex = sections.indexOf(currentSection); + Section previousSection = new Section(body, SWT.NONE, context); + build(previousSection, previousUiProvider, previousNode); + previousSection.setLayoutData(CmsUiUtils.coverAll()); +// sections.remove(currentSection); + sections.add(currentIndex + 1, previousSection); +// sections.add(currentSection); +// nextCurrentSection.moveAbove(null); +// if (previousNode != null) { +// view(previousUiProvider, previousNode); +// } + refreshTabHeaders(); + layout(true, true); + } + + public void showTab(int index) { + Section sectionToShow = sections.get(index); + sectionToShow.moveAbove(null); + refreshTabHeaders(); + layout(true, true); + } + + protected void build(Section section, CmsUiProvider uiProvider, Node context) { + for (Control child : section.getChildren()) + child.dispose(); + CmsUiUtils.style(section, bodyStyle); + section.setNode(context); + uiProvider.createUiPart(section, context); + + } + + private int tabIndex(Node node) { + for (int i = 0; i < sections.size(); i++) { + Section section = sections.get(i); + if (Jcr.getIdentifier(section.getNode()).equals(Jcr.getIdentifier(node))) + return i; + } + return -1; + } + + public void closeTab(Section section) { + int currentIndex = sections.indexOf(section); + int nextIndex = currentIndex == 0 ? 0 : currentIndex - 1; + sections.remove(section); + section.dispose(); + if (sections.size() == 0) { + emptyState(); + refreshTabHeaders(); + layout(true, true); + return; + } + refreshTabHeaders(); + showTab(nextIndex); + } + + protected void emptyState() { + new Section(body, SWT.NONE, null); + refreshTabHeaders(); + } + + public Composite getCurrent() { + return getCurrentSection(); + } + + protected Section getCurrentSection() { + return (Section) body.getChildren()[0]; + } + + public void setTabStyle(String tabStyle) { + this.tabStyle = tabStyle; + } + + public void setTabSelectedStyle(String tabSelectedStyle) { + this.tabSelectedStyle = tabSelectedStyle; + } + + public void setBodyStyle(String bodyStyle) { + this.bodyStyle = bodyStyle; + } + + public void setCloseIcon(Image closeIcon) { + this.closeIcon = closeIcon; + } +}