Java tutorial
/* * This library is part of OpenCms - * the Open Source Content Management System * * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * For further information about Alkacon Software, please see the * company website: http://www.alkacon.com * * For further information about OpenCms, please see the * project website: http://www.opencms.org * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.opencms.ui.components; import org.opencms.file.CmsObject; import org.opencms.file.CmsResource; import org.opencms.file.CmsResourceFilter; import org.opencms.main.CmsException; import org.opencms.main.CmsLog; import org.opencms.main.OpenCms; import org.opencms.site.CmsSite; import org.opencms.ui.A_CmsDialogContext; import org.opencms.ui.A_CmsUI; import org.opencms.ui.CmsVaadinUtils; import org.opencms.ui.FontOpenCms; import org.opencms.ui.I_CmsDialogContext; import org.opencms.ui.apps.CmsAppWorkplaceUi; import org.opencms.ui.apps.CmsDefaultAppButtonProvider; import org.opencms.ui.apps.I_CmsWorkplaceAppConfiguration; import org.opencms.ui.apps.Messages; import org.opencms.ui.components.CmsUploadButton.I_UploadListener; import org.opencms.ui.contextmenu.CmsContextMenuTreeBuilder; import org.opencms.ui.contextmenu.I_CmsContextMenuItem; import org.opencms.util.CmsStringUtil; import org.opencms.util.CmsTreeNode; import org.opencms.util.CmsUUID; import org.opencms.workplace.CmsWorkplace; import java.util.Collections; import java.util.List; import java.util.Locale; import org.apache.commons.logging.Log; import com.google.common.collect.Lists; import com.vaadin.server.ExternalResource; import com.vaadin.server.FontIcon; import com.vaadin.server.Page; import com.vaadin.server.Page.BrowserWindowResizeEvent; import com.vaadin.server.Page.BrowserWindowResizeListener; import com.vaadin.server.Resource; import com.vaadin.ui.AbstractOrderedLayout; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Component; import com.vaadin.ui.CssLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.MenuBar; import com.vaadin.ui.MenuBar.Command; import com.vaadin.ui.MenuBar.MenuItem; import com.vaadin.ui.PopupView; import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.declarative.Design; import com.vaadin.ui.themes.ValoTheme; /** * The workplace toolbar.<p> */ public class CmsToolBar extends CssLayout implements BrowserWindowResizeListener { /** Toolbar dialog context. */ protected class ToolbarContext extends A_CmsDialogContext { /** * Constructor.<p> * * @param appId the app id */ protected ToolbarContext(String appId) { super(appId, ContextType.appToolbar, Collections.<CmsResource>emptyList()); } /** * @see org.opencms.ui.I_CmsDialogContext#focus(org.opencms.util.CmsUUID) */ public void focus(CmsUUID structureId) { // nothing to do } /** * @see org.opencms.ui.I_CmsDialogContext#getAllStructureIdsInView() */ public List<CmsUUID> getAllStructureIdsInView() { return Lists.newArrayList(); } /** * @see org.opencms.ui.I_CmsDialogContext#updateUserInfo() */ public void updateUserInfo() { refreshUserInfoDropDown(); } } /** Logger instance for this class. */ private static final Log LOG = CmsLog.getLog(CmsToolBar.class); /** The serial version id. */ private static final long serialVersionUID = -4551194983054069395L; /** The app indicator. */ private Label m_appIndicator; /** Flag indicating the toolbar buttons are folded into a sub menu. */ private boolean m_buttonsFolded; /** The context menu component. */ private MenuBar m_contextMenu; /** The dialog context. */ private I_CmsDialogContext m_dialogContext; /** The sub menu displaying the folded buttons. */ private PopupView m_foldedButtonsMenu; /** The browser window width that is required to display all toolbar buttons. */ private int m_foldingThreshhold; /** Toolbar items left. */ private HorizontalLayout m_itemsLeft; /** Toolbar items right. */ private HorizontalLayout m_itemsRight; /** The contains the buttons from the left side, displayed in the folded buttons sub menu. */ private VerticalLayout m_leftButtons; /** The quick launch drop down. */ private Component m_quickLaunchDropDown; /** The contains the buttons from the right side, displayed in the folded buttons sub menu. */ private VerticalLayout m_rightButtons; /** The user drop down. */ private Component m_userDropDown; /** * Constructor.<p> */ public CmsToolBar() { m_quickLaunchDropDown = createQuickLaunchDropDown(); m_userDropDown = createUserInfoDropDown(); m_leftButtons = new VerticalLayout(); m_rightButtons = new VerticalLayout(); VerticalLayout layout = new VerticalLayout(); layout.addComponent(m_leftButtons); layout.addComponent(m_rightButtons); m_foldedButtonsMenu = new PopupView(getDropDownButtonHtml(FontOpenCms.CONTEXT_MENU_DOTS), layout); m_foldedButtonsMenu.addStyleName(OpenCmsTheme.NAVIGATOR_DROPDOWN); m_foldedButtonsMenu.setHideOnMouseOut(false); Design.read("CmsToolBar.html", this); } /** * Creates a properly styled toolbar button.<p> * * @param icon the button icon * @param title the button title, will be used for the tooltip * * @return the button */ public static Button createButton(Resource icon, String title) { return createButton(icon, title, false); } /** * Creates a properly styled toolbar button.<p> * * @param icon the button icon * @param title the button title, will be used for the tooltip * @param alwaysShow <code>true</code> to prevent the button to be folded into a sub menu for small screens * * @return the button */ public static Button createButton(Resource icon, String title, boolean alwaysShow) { Button button = new Button(icon); button.setDescription(title); button.addStyleName(ValoTheme.BUTTON_BORDERLESS); button.addStyleName(OpenCmsTheme.TOOLBAR_BUTTON); if (alwaysShow) { button.addStyleName(OpenCmsTheme.REQUIRED_BUTTON); } return button; } /** * Creates a drop down menu.<p> * * @param icon the button icon * @param content the drop down content * @param title the button title * * @return the component */ public static Component createDropDown(ExternalResource icon, Component content, String title) { return createDropDown(getDropDownButtonHtml(icon), content, title); } /** * Creates a drop down menu.<p> * * @param icon the button icon * @param content the drop down content * @param title the drop down title * * @return the component */ public static Component createDropDown(FontIcon icon, Component content, String title) { return createDropDown(getDropDownButtonHtml(icon), content, title); } /** * Creates a drop down menu.<p> * * @param buttonHtml the button HTML * @param content the drop down content * @param title the button title * * @return the component */ public static Component createDropDown(String buttonHtml, Component content, String title) { PopupView pv = new PopupView(buttonHtml, content); pv.setDescription(title); pv.addStyleName(OpenCmsTheme.NAVIGATOR_DROPDOWN); pv.setHideOnMouseOut(false); return pv; } /** * Creates the button HTML for the given icon resource.<p> * * @param icon the icon * * @return the HTML */ static String getDropDownButtonHtml(ExternalResource icon) { return "<div tabindex=\"0\" role=\"button\" class=\"v-button v-widget borderless v-button-borderless " + OpenCmsTheme.TOOLBAR_BUTTON + " v-button-" + OpenCmsTheme.TOOLBAR_BUTTON + "\"><span class=\"v-button-wrap\"><img class=\"v-icon\" src=\"" + icon.getURL() + "\" /></span></div>"; } /** * Creates the button HTML for the given icon resource.<p> * * @param icon the icon * * @return the HTML */ static String getDropDownButtonHtml(FontIcon icon) { return "<div tabindex=\"0\" role=\"button\" class=\"v-button v-widget borderless v-button-borderless " + OpenCmsTheme.TOOLBAR_BUTTON + " v-button-" + OpenCmsTheme.TOOLBAR_BUTTON + "\"><span class=\"v-button-wrap\">" + icon.getHtml() + "</span></div>"; } /** * Adds a button to left toolbar side.<p> * * @param button the button */ public void addButtonLeft(Component button) { if (m_buttonsFolded && !isAlwaysShow(button)) { m_leftButtons.addComponent(button); } else { m_itemsLeft.addComponent(button); } updateFoldingThreshhold(); } /** * Adds a button to right toolbar side.<p> * * @param button the button */ public void addButtonRight(Component button) { if (m_buttonsFolded && !isAlwaysShow(button)) { m_rightButtons.addComponent(button); } else { int dropDownIndex = m_itemsRight.getComponentIndex(m_userDropDown); if (dropDownIndex >= 0) { m_itemsRight.addComponent(button, dropDownIndex); } else { m_itemsRight.addComponent(button); } } updateFoldingThreshhold(); } /** * @see com.vaadin.server.Page.BrowserWindowResizeListener#browserWindowResized(com.vaadin.server.Page.BrowserWindowResizeEvent) */ public void browserWindowResized(BrowserWindowResizeEvent event) { updateButtonVisibility(event.getWidth()); } /** * Clears the left toolbar buttons.<p> */ public void clearButtonsLeft() { m_itemsLeft.removeAllComponents(); m_leftButtons.removeAllComponents(); // in case the app title is set, make sure to keep the label in the button bar if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_appIndicator.getValue())) { m_itemsLeft.addComponent(m_appIndicator); } updateFoldingThreshhold(); } /** * Clears the right toolbar buttons.<p> */ public void clearButtonsRight() { m_itemsRight.removeAllComponents(); m_rightButtons.removeAllComponents(); updateFoldingThreshhold(); } /** * Closes all visible popup views.<p> */ public void closePopupViews() { closePopupViews(m_itemsLeft); closePopupViews(m_itemsRight); } /** * Enables or removes the default toolbar buttons.<p> * These are the context menu and the quick launch drop down.<p> * The default is <code>enabled = true</code>.<p> * * @param enabled <code>true</code> to enable the buttons */ public void enableDefaultButtons(boolean enabled) { if (enabled) { m_itemsRight.addComponent(m_contextMenu, 0); m_itemsRight.addComponent(m_quickLaunchDropDown, 1); } else { m_itemsRight.removeComponent(m_contextMenu); m_itemsRight.removeComponent(m_quickLaunchDropDown); } updateFoldingThreshhold(); } /** * Refreshes the user drop down.<p> */ public void refreshUserInfoDropDown() { Component oldVersion = m_userDropDown; m_userDropDown = createUserInfoDropDown(); m_itemsRight.replaceComponent(oldVersion, m_userDropDown); } /** * Removes the given button from the toolbar.<p> * * @param button the button to remove */ public void removeButton(Component button) { m_itemsLeft.removeComponent(button); m_itemsRight.removeComponent(button); m_leftButtons.removeComponent(button); m_rightButtons.removeComponent(button); updateFoldingThreshhold(); } /** * Sets the app title.<p> * * @param appTitle the app title */ public void setAppTitle(String appTitle) { if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(appTitle)) { m_appIndicator.setValue(appTitle); updateAppIndicator(); m_appIndicator.setVisible(true); } else { m_appIndicator.setVisible(false); } } /** * Updates the app indicator site and project info.<p> */ public void updateAppIndicator() { if (CmsAppWorkplaceUi.isOnlineProject()) { m_appIndicator.addStyleName(OpenCmsTheme.TOOLABER_APP_INDICATOR_ONLINE); } else { m_appIndicator.removeStyleName(OpenCmsTheme.TOOLABER_APP_INDICATOR_ONLINE); } CmsObject cms = A_CmsUI.getCmsObject(); String siteRoot = cms.getRequestContext().getSiteRoot(); CmsSite site = OpenCms.getSiteManager().getSiteForSiteRoot(siteRoot); String siteName = null; if (site != null) { siteName = site.getTitle(); } else { try { CmsResource folder = cms.readResource("/", CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); siteName = OpenCms.getSiteManager().getSiteTitle(cms, folder); } catch (CmsException e) { LOG.warn("Error reading site title.", e); } } if (CmsStringUtil.isEmptyOrWhitespaceOnly(siteName)) { siteName = siteRoot; } else { siteName = CmsWorkplace.substituteSiteTitleStatic(siteName, UI.getCurrent().getLocale()); } m_appIndicator.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_TOOLBAR_PROJECT_SITE_INFO_2, A_CmsUI.getCmsObject().getRequestContext().getCurrentProject().getName(), siteName)); } /** * Initializes the toolbar.<p> * * @param appId the app id */ protected void init(String appId) { m_dialogContext = new ToolbarContext(appId); initContextMenu(); m_itemsRight.addComponent(m_quickLaunchDropDown); m_itemsRight.addComponent(m_userDropDown); } /** * Sets the dialog context.<p> * * @param context the dialog context */ protected void setDialogContext(I_CmsDialogContext context) { m_dialogContext = context; // reinit context menu initContextMenu(); } /** * Updates the button visibility according o the given widow width.<p> * * @param width the window width */ protected void updateButtonVisibility(int width) { if (!m_buttonsFolded && (m_foldingThreshhold > width)) { foldButtons(); } else if (m_buttonsFolded && (width > m_foldingThreshhold)) { unfoldButtons(); } } /** * Recalculates the space required by the toolbar buttons */ protected void updateFoldingThreshhold() { int left = estimateRequiredWidth(m_itemsLeft) + estimateRequiredWidth(m_leftButtons); int right = estimateRequiredWidth(m_itemsRight) + estimateRequiredWidth(m_rightButtons); int requiredWidth = left > right ? left : right; if (requiredWidth < 350) { // folding not required at any width m_foldingThreshhold = 0; } else if (requiredWidth < 400) { m_foldingThreshhold = 984; } else if (requiredWidth <= 520) { m_foldingThreshhold = 1240; } else { // always fold m_foldingThreshhold = 10000; } updateButtonVisibility(Page.getCurrent().getBrowserWindowWidth()); } /** * Returns the dialog context.<p> * * @return the dialog context */ I_CmsDialogContext getDialogContext() { return m_dialogContext; } /** * Handles the user image file upload.<p> * * @param uploadedFiles the uploaded file names */ void handleUpload(List<String> uploadedFiles) { CmsObject cms = A_CmsUI.getCmsObject(); boolean success = OpenCms.getWorkplaceAppManager().getUserIconHelper().handleImageUpload(cms, uploadedFiles); if (success) { refreshUserInfoDropDown(); } } /** * Closes the visible popup view children of the given layout.<p> * * @param layout the layout */ private void closePopupViews(AbstractOrderedLayout layout) { for (Component item : layout) { if (item instanceof PopupView) { ((PopupView) item).setPopupVisible(false); } } } /** * Creates the context menu entry and it's children.<p> * * @param parent the entry parent * @param node the item tree node * @param treeBuilder the tree builder */ private void createMenuEntry(MenuItem parent, final CmsTreeNode<I_CmsContextMenuItem> node, CmsContextMenuTreeBuilder treeBuilder) { Command entryCommand = null; if (node.getChildren().size() == 0) { entryCommand = new Command() { private static final long serialVersionUID = 1L; public void menuSelected(MenuItem selectedItem) { node.getData().executeAction(getDialogContext()); } }; } MenuItem entry = parent.addItem((node.getData().getTitle(A_CmsUI.get().getLocale())), entryCommand); for (CmsTreeNode<I_CmsContextMenuItem> child : node.getChildren()) { createMenuEntry(entry, child, treeBuilder); } if (treeBuilder.getVisibility(node.getData()).isInActive()) { entry.setEnabled(false); } } /** * Creates the app select drop down.<p> * * @return the drop down component */ private Component createQuickLaunchDropDown() { PopupView pv = new PopupView(new PopupView.Content() { private static final long serialVersionUID = 1L; public String getMinimizedValueAsHTML() { return getDropDownButtonHtml(FontOpenCms.APPS); } public Component getPopupComponent() { CmsObject cms = A_CmsUI.getCmsObject(); Locale locale = UI.getCurrent().getLocale(); HorizontalLayout layout = new HorizontalLayout(); layout.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); layout.addStyleName(OpenCmsTheme.QUICK_LAUNCH); // layout.setSpacing(true); layout.setMargin(true); for (I_CmsWorkplaceAppConfiguration config : OpenCms.getWorkplaceAppManager() .getQuickLaunchConfigurations(cms)) { layout.addComponent(CmsDefaultAppButtonProvider.createAppButton(cms, config, locale)); } return layout; } }); pv.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_QUICK_LAUNCH_TITLE_0)); pv.addStyleName(OpenCmsTheme.NAVIGATOR_DROPDOWN); pv.setHideOnMouseOut(false); return pv; } /** * Creates the user info drop down.<p> * * @return the drop down component */ private Component createUserInfoDropDown() { PopupView pv = new PopupView(new PopupView.Content() { private static final long serialVersionUID = 1L; public String getMinimizedValueAsHTML() { CmsObject cms = A_CmsUI.getCmsObject(); return getDropDownButtonHtml(new ExternalResource(OpenCms.getWorkplaceAppManager() .getUserIconHelper().getSmallIconPath(cms, cms.getRequestContext().getCurrentUser()))); } public Component getPopupComponent() { return new CmsUserInfo(new I_UploadListener() { public void onUploadFinished(List<String> uploadedFiles) { handleUpload(uploadedFiles); } }, getDialogContext()); } }); pv.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_USER_INFO_TITLE_0)); pv.addStyleName(OpenCmsTheme.NAVIGATOR_DROPDOWN); pv.setHideOnMouseOut(false); pv.addStyleName(OpenCmsTheme.USER_INFO); return pv; } /** * Calculates the width required by the layout components * * @param items the layout * * @return the width */ private int estimateRequiredWidth(AbstractOrderedLayout items) { int result = 0; if (items != null) { for (Component comp : items) { if (comp == m_foldedButtonsMenu) { continue; } else if ((comp instanceof Button) || (comp instanceof PopupView) || (comp instanceof MenuBar)) { // assume all buttons have a with of 50px result += 50; } else if (comp == m_appIndicator) { // assume app indicator requires 150px result += 50; } else { float compWidth = comp.getWidth(); if ((compWidth > 0) && (comp.getWidthUnits() == Unit.PIXELS)) { // also add 10px margin result += compWidth + 10; } else { result += 200; } } } } return result; } /** * Folds the toolbar buttons into a sub menu.<p> */ private void foldButtons() { VerticalLayout mainPV = (VerticalLayout) m_foldedButtonsMenu.getContent().getPopupComponent(); for (int i = m_itemsLeft.getComponentCount() - 1; i > -1; i--) { Component comp = m_itemsLeft.getComponent(i); if (!isAlwaysShow(comp)) { m_itemsLeft.removeComponent(comp); m_leftButtons.addComponent(comp, 0); m_leftButtons.setComponentAlignment(comp, Alignment.MIDDLE_CENTER); } } if (m_leftButtons.getComponentCount() == 0) { mainPV.removeComponent(m_leftButtons); } else { mainPV.addComponent(m_leftButtons, 0); } for (int i = m_itemsRight.getComponentCount() - 1; i > -1; i--) { Component comp = m_itemsRight.getComponent(i); if (!isAlwaysShow(comp)) { m_itemsRight.removeComponent(comp); m_rightButtons.addComponent(comp, 0); m_rightButtons.setComponentAlignment(comp, Alignment.MIDDLE_CENTER); } } if (m_rightButtons.getComponentCount() == 0) { mainPV.removeComponent(m_rightButtons); } else { mainPV.addComponent(m_rightButtons); } m_itemsRight.addComponent(m_foldedButtonsMenu, 0); m_buttonsFolded = true; markAsDirtyRecursive(); } /** * Initializes the context menu entries.<p> */ private void initContextMenu() { m_contextMenu.removeItems(); MenuItem main = m_contextMenu.addItem("", null); main.setIcon(FontOpenCms.CONTEXT_MENU); main.setDescription(CmsVaadinUtils.getMessageText(Messages.GUI_MENU_TITLE_0)); CmsContextMenuTreeBuilder treeBuilder = new CmsContextMenuTreeBuilder(getDialogContext()); CmsTreeNode<I_CmsContextMenuItem> tree = treeBuilder .buildAll(OpenCms.getWorkplaceAppManager().getMenuItemProvider().getMenuItems()); for (CmsTreeNode<I_CmsContextMenuItem> node : tree.getChildren()) { createMenuEntry(main, node, treeBuilder); } } /** * Checks whether the given component may be placed into the buttons sub menu.<p> * * @param comp the component to check * * @return <code>true</code> in case the component should always be displayed in the toolbar */ private boolean isAlwaysShow(Component comp) { return ((comp == m_appIndicator) || (comp == m_contextMenu) || (comp == m_userDropDown) || (comp == m_quickLaunchDropDown) || comp.getStyleName().contains(OpenCmsTheme.REQUIRED_BUTTON)); } /** * Places the buttons formerly moved to the sub menu back into the toolbar.<p> */ private void unfoldButtons() { m_itemsRight.removeComponent(m_foldedButtonsMenu); while (m_leftButtons.getComponentCount() > 0) { Component comp = m_leftButtons.getComponent(0); if (!isAlwaysShow(comp)) { m_leftButtons.removeComponent(comp); m_itemsLeft.addComponent(comp); } } int index = 0; while (m_rightButtons.getComponentCount() > 0) { Component comp = m_rightButtons.getComponent(0); m_rightButtons.removeComponent(comp); m_itemsRight.addComponent(comp, index); index++; } m_buttonsFolded = false; markAsDirtyRecursive(); } }