Java tutorial
/* * Copyright 2017 NEOautus Ltd. (http://neoautus.com) * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.lucidj.ui.gauss; import org.lucidj.api.core.MenuEntry; import org.lucidj.api.core.MenuInstance; import org.lucidj.api.core.MenuManager; import org.lucidj.api.core.ServiceContext; import org.lucidj.api.core.ServiceObject; import org.lucidj.api.vui.ApplicationInterface; import org.lucidj.api.vui.DesktopInterface; import org.lucidj.api.vui.NavigatorManager; import org.lucidj.api.vui.ObjectRenderer; import org.lucidj.api.vui.RendererFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.vaadin.event.ItemClickEvent; import com.vaadin.event.LayoutEvents; import com.vaadin.navigator.Navigator; import com.vaadin.navigator.View; import com.vaadin.navigator.ViewChangeListener; import com.vaadin.navigator.ViewDisplay; import com.vaadin.server.FontAwesome; import com.vaadin.server.Page; import com.vaadin.server.Sizeable; import com.vaadin.server.Sizeable.Unit; import com.vaadin.shared.ui.label.ContentMode; import com.vaadin.ui.AbstractComponent; 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.HorizontalSplitPanel; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; import com.vaadin.ui.Notification; import com.vaadin.ui.Panel; import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.themes.ValoTheme; import java.io.PrintWriter; import java.io.StringWriter; import java.net.URI; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; public class GaussUI implements DesktopInterface, MenuInstance.EventListener { private final static Logger log = LoggerFactory.getLogger(GaussUI.class); // Layout structure: // +----------------------------------------------------------+ // | vAppLayout | // | +------------------+-----------------------------------+ | // | | menuArea | hToolbarArea | | // | | +--------------+ +--------------------+--------------+ | // | | | menuHeader | | vContentArea | vSidebarArea | | // | | | | | | | | // | | | | | | | | // | | | +----------+ | | | | | // | | | |navMenu | | | | | | // | | | | | | | | | | // | | | | | | | | | | // | | | | | | | | | | // | | | | | | | | | | // | | | +----------+ | | | | | // | | +--------------+ | | | | // | +------------------+--------------------+--------------+ | // +----------------------------------------------------------+ private final static int MIN_DEF_COLUMN_WIDTH_PX = 240; private final static int MIN_LEFT_PANEL_WIDTH_PX = 120; private final static int MIN_RIGHT_PANEL_WIDTH_PX = 120; private int default_left_panel_width_px; private int default_right_panel_width_px; private VerticalLayout vAppLayout = new VerticalLayout(); private HorizontalSplitPanel hsMenuContents = new HorizontalSplitPanel(); private HorizontalSplitPanel hsContentsSidebar = new HorizontalSplitPanel(); private HorizontalLayout hToolbarArea = new HorizontalLayout(); private CssLayout hToolbarPlaceholder = new CssLayout(); private CssLayout emptyContents = new CssLayout(); private CssLayout emptySidebar = new CssLayout(); private HorizontalLayout hSecurityArea = new HorizontalLayout(); private Button toggle_sidebar; private VerticalLayout acMenu; private String DAMN = "damage.report"; private ErrorView damage_report_view = new ErrorView(); private Navigator navigator; private MenuManager menu_manager; private NavigatorManager nav_manager; private MenuInstance main_menu; private RendererFactory rendererFactory; private ObjectRenderer main_menu_renderer; private ServiceContext serviceContext; public GaussUI(ServiceContext serviceContext, BundleContext bundleContext) { this.serviceContext = serviceContext; menu_manager = serviceContext.getService(bundleContext, MenuManager.class); nav_manager = serviceContext.getService(bundleContext, NavigatorManager.class); rendererFactory = serviceContext.getService(bundleContext, RendererFactory.class); } //========================================================================================= // DEFAULTS //========================================================================================= private int get_def_column_width_px() { Page page = UI.getCurrent().getPage(); int page_width = page.getBrowserWindowWidth(); int column_width = page_width / 6; if (column_width < MIN_DEF_COLUMN_WIDTH_PX) { return (MIN_DEF_COLUMN_WIDTH_PX); } return (column_width); } private int get_default_left_panel_width() { if (default_left_panel_width_px == 0) { default_left_panel_width_px = get_def_column_width_px(); } return (default_left_panel_width_px); } private int get_default_right_panel_width() { if (default_right_panel_width_px == 0) { default_right_panel_width_px = get_def_column_width_px(); } return (default_right_panel_width_px); } //========================================================================================= // RIGHT SIDEBAR //========================================================================================= private boolean sidebar_visible() { return (!hsContentsSidebar.isLocked()); } private void show_sidebar(boolean visible) { if (visible == sidebar_visible()) { // Nothing changed return; } if (visible) { hsContentsSidebar.setLocked(false); hsContentsSidebar.setMinSplitPosition(MIN_RIGHT_PANEL_WIDTH_PX, Unit.PIXELS); hsContentsSidebar.setSplitPosition(get_default_right_panel_width(), Unit.PIXELS, true); toggle_sidebar.setIcon(FontAwesome.CHEVRON_DOWN); } else { if (default_right_panel_width_px != 0) // Record size only after proper init { default_right_panel_width_px = (int) hsContentsSidebar.getSplitPosition(); } hsContentsSidebar.setMinSplitPosition(0, Unit.PIXELS); hsContentsSidebar.setSplitPosition(0, Unit.PIXELS, true); hsContentsSidebar.setLocked(true); toggle_sidebar.setIcon(FontAwesome.CHEVRON_LEFT); } } private void set_contents(Component contents) { hsContentsSidebar.setFirstComponent(contents); } private void set_sidebar(Component sidebar) { if (sidebar != null) { // Sidebar visible and toggle button enabled hsContentsSidebar.setSecondComponent(sidebar); toggle_sidebar.setEnabled(true); show_sidebar(true); } else { // No contents, sidebar hidden and toggle button disabled show_sidebar(false); toggle_sidebar.setIcon(FontAwesome.CHEVRON_DOWN); // Down+disable = no sidebar hsContentsSidebar.setSecondComponent(emptySidebar); toggle_sidebar.setEnabled(false); } } //========================================================================================= // LAYOUTS //========================================================================================= private void add_smart_tab(VerticalLayout container, String caption, Component contents) { String style_expanded = "ui-panel-caption-expanded"; // Every panel is a glorified button disguised as accordion tab... final Button caption_button = new Button(caption); caption_button.setWidth(100, Unit.PERCENTAGE); container.addComponent(caption_button); caption_button.addStyleName("ui-panel-caption"); caption_button.addStyleName(style_expanded); // ... with a panel for the contents and selective hide/show final Panel content_panel = new Panel(); content_panel.setWidth(100, Unit.PERCENTAGE); content_panel.setContent(contents); content_panel.addStyleName("ui-panel-contents"); content_panel.addStyleName(ValoTheme.PANEL_BORDERLESS); container.addComponent(content_panel); caption_button.addClickListener(new Button.ClickListener() { @Override public void buttonClick(Button.ClickEvent clickEvent) { if (content_panel.isVisible()) { content_panel.setVisible(false); caption_button.removeStyleName(style_expanded); } else { content_panel.setVisible(true); caption_button.addStyleName(style_expanded); } } }); } private VerticalLayout create_multipanel() { VerticalLayout layout = new VerticalLayout(); add_smart_tab(layout, "Navigation", main_menu_renderer); serviceContext.addServiceTracker("(@section=Navigation)", new ServiceContext.TrackerListener() { @Override public void bind(Object service, ServiceReference ref) { log.info("///// bind: service={} ref={}", service, ref); ObjectRenderer r = rendererFactory.newRenderer(ref); r.setWidthUndefined(); r.setHeightUndefined(); r.addListener(new Component.Listener() { @Override public void componentEvent(Component.Event event) { if (event instanceof ItemClickEvent) { ItemClickEvent itemClickEvent = (ItemClickEvent) event; URI uri = (URI) itemClickEvent.getItem().getItemProperty(URI.class.getName()) .getValue(); if (uri != null && uri.getScheme().equals("navigator")) { log.info("Navigator URI: {}", uri); navigator.navigateTo(uri.getHost() + uri.getPath()); } } } }); add_smart_tab(layout, (String) ref.getProperty("@caption"), r); } @Override public void unbind(Object service, ServiceReference ref) { log.info("///// unbind: service={} ref={}", service, ref); } @Override public void modified(Object service, ServiceReference ref) { log.info("///// modified: service={} ref={}", service, ref); } }); return (layout); } private void initAppLayout() { vAppLayout.setSizeFull(); vAppLayout.setWidth("100%"); { initToolbarArea(); vAppLayout.addComponent(hToolbarArea); } { hsMenuContents.setSizeFull(); hsMenuContents.addStyleName("ui-main-splitpanel"); vAppLayout.addComponent(hsMenuContents); vAppLayout.setExpandRatio(hsMenuContents, 1.0f); } // Accordion menu { // Create the logical menu main_menu = menu_manager.newMenuInstance(null); main_menu.setEventListener(this); // Create the menu renderer main_menu_renderer = rendererFactory.newRenderer(main_menu); main_menu_renderer.setWidth(100, Unit.PERCENTAGE); main_menu_renderer.setHeightUndefined(); // Add the rendered component into navigation panel acMenu = create_multipanel(); acMenu.addStyleName("ui-navigation-panel"); acMenu.setWidth(100, Unit.PERCENTAGE); } emptyContents = new CssLayout(); emptyContents.addStyleName("fancy-grid-background"); set_contents(emptyContents); emptySidebar.addStyleName("fancy-grid-background"); hsContentsSidebar.setSecondComponent(emptySidebar); show_sidebar(false); hsMenuContents.setFirstComponent(acMenu); hsMenuContents.setSecondComponent(hsContentsSidebar); hsMenuContents.setMinSplitPosition(MIN_LEFT_PANEL_WIDTH_PX, Unit.PIXELS); hsMenuContents.setSplitPosition(get_default_left_panel_width(), Sizeable.Unit.PIXELS); } @Override // MenuInstance.EventListener public void entrySelectedEvent(MenuEntry entry) { navigator.navigateTo(entry.getNavId()); } private void initToolbarArea() { hToolbarArea.setStyleName("ui-toolbar-area"); hToolbarArea.setSizeUndefined(); hToolbarArea.setWidth("100%"); CssLayout home_buttons = new CssLayout(); home_buttons.setStyleName("ui-toolbar-area-home"); home_buttons.setWidth(get_default_left_panel_width(), Sizeable.Unit.PIXELS); home_buttons.setId("_home_buttons"); final Button toggle_menu = new Button(); toggle_menu.setWidth(3, Unit.EM); toggle_menu.setIcon(FontAwesome.CHEVRON_DOWN); toggle_menu.addStyleName("tiny"); toggle_menu.addStyleName("link"); toggle_menu.addStyleName("ui-toolbar-spacer"); toggle_menu.addStyleName("ui-toggle-button"); toggle_menu.setId("_toggle_menu"); home_buttons.addComponent(toggle_menu); toggle_menu.addClickListener(new Button.ClickListener() { @Override public void buttonClick(Button.ClickEvent clickEvent) { if (!hsMenuContents.isLocked()) { default_left_panel_width_px = (int) hsMenuContents.getSplitPosition(); acMenu.setVisible(false); hsMenuContents.setMinSplitPosition(0, Unit.PIXELS); hsMenuContents.setSplitPosition(0, Sizeable.Unit.PIXELS); toggle_menu.setIcon(FontAwesome.CHEVRON_RIGHT); hsMenuContents.setLocked(true); } else { hsMenuContents.setLocked(false); acMenu.setVisible(true); hsMenuContents.setMinSplitPosition(MIN_LEFT_PANEL_WIDTH_PX, Unit.PIXELS); hsMenuContents.setSplitPosition(get_default_left_panel_width(), Unit.PIXELS); toggle_menu.setIcon(FontAwesome.CHEVRON_DOWN); } } }); final Button home = new Button("Home"); home.setIcon(FontAwesome.HOME); home.addStyleName("tiny"); home.addStyleName("ui-toolbar-spacer"); home.addStyleName("ui-toggle-button"); home.setId("_home"); home_buttons.addComponent(home); home.addClickListener(new Button.ClickListener() { @Override public void buttonClick(Button.ClickEvent clickEvent) { navigator.navigateTo("home"); } }); final Button new_button = new Button("New"); new_button.setIcon(FontAwesome.EDIT); new_button.addStyleName("tiny"); new_button.addStyleName("primary"); new_button.addStyleName("ui-toggle-button"); new_button.setId("_new"); home_buttons.addComponent(new_button); new_button.addClickListener(new Button.ClickListener() { @Override public void buttonClick(Button.ClickEvent clickEvent) { navigator.navigateTo("new"); } }); hToolbarArea.addComponent(home_buttons); hToolbarPlaceholder = new CssLayout(); hToolbarPlaceholder.setSizeFull(); hToolbarArea.addComponent(hToolbarPlaceholder); hToolbarArea.setExpandRatio(hToolbarPlaceholder, 1.0f); final Button eject_view = new Button(); eject_view.setIcon(FontAwesome.EXTERNAL_LINK); eject_view.addStyleName("tiny"); eject_view.addStyleName("link"); eject_view.addStyleName("ui-toggle-button"); eject_view.setId("_eject_view"); hToolbarArea.addComponent(eject_view); eject_view.addClickListener(new Button.ClickListener() { @Override public void buttonClick(Button.ClickEvent clickEvent) { Notification.show("Not implemented", Notification.Type.HUMANIZED_MESSAGE); } }); toggle_sidebar = new Button(); toggle_sidebar.setWidth(3, Unit.EM); toggle_sidebar.addStyleName("tiny"); toggle_sidebar.addStyleName("link"); toggle_sidebar.addStyleName("ui-toolbar-spacer"); toggle_sidebar.addStyleName("ui-toggle-button"); toggle_sidebar.setId("_toggle_sidebar"); hToolbarArea.addComponent(toggle_sidebar); toggle_sidebar.addClickListener(new Button.ClickListener() { @Override public void buttonClick(Button.ClickEvent clickEvent) { show_sidebar(!sidebar_visible()); } }); } private void initSecurityArea() { HorizontalLayout click_catcher = new HorizontalLayout(); { click_catcher.setDefaultComponentAlignment(Alignment.MIDDLE_LEFT); String fancy_css = "background-color: white; vertical-align:middle; width: 32px; height: 32px; border-radius: 50%;"; String userinfo_html = "<span style='vertical-align:middle;'>LucidJ Admin</span>" + " " + "<img style='" + fancy_css + "' src='/VAADIN/~/vaadinui_libraries/user-frank-128x128.png'>"; Label userinfo = new Label(userinfo_html, ContentMode.HTML); click_catcher.addComponent(userinfo); click_catcher.addLayoutClickListener(new LayoutEvents.LayoutClickListener() { @Override public void layoutClick(LayoutEvents.LayoutClickEvent layoutClickEvent) { navigator.navigateTo("accounts"); } }); } hSecurityArea.addComponent(click_catcher); } protected void initAllLayouts() { initAppLayout(); } //========================================================================================= // VAADIN NAVIGATOR SYSTEM //========================================================================================= protected void initNavigator(UI ui) { navigator = new SafeNavigator(ui, new ViewDisplay() { @Override public void showView(View view) { if (view instanceof com.vaadin.ui.Component) { set_contents((com.vaadin.ui.Component) view); } else { String msg = "Invalid component:\n" + view.getClass().getCanonicalName(); set_contents(emptyContents); } } }); // navigator.setErrorView (FancyEmptyView.class); ---> make it better navigator.addView(DAMN, damage_report_view); nav_manager.configureNavigator(navigator, null); navigator.addViewChangeListener(new ViewChangeListener() { @Override public boolean beforeViewChange(final ViewChangeEvent event) { if (false /* go somewhere else */) { navigator.navigateTo("neverland"); return (false); } // Go ahead return (true); } @Override public void afterViewChange(final ViewChangeEvent event) { String navid = event.getViewName(); // TODO: BUBBLE EVENT INTO PROPER MenuInstance // highlight_menu_item(navid); View new_view = event.getNewView(); AbstractComponent sidebar = null; AbstractComponent toolbar = null; // TODO: CHANGE TO Aggregates if (new_view instanceof ApplicationInterface) { ApplicationInterface app_view = (ApplicationInterface) new_view; sidebar = app_view.getSidebar(); toolbar = app_view.getToolbar(); } log.debug("Sidebar navid:{} = {}", navid, sidebar); log.debug("Toolbar navid:{} = {}", navid, toolbar); //--------------- // Place sidebar //--------------- set_sidebar(sidebar); //--------------- // Place toolbar //--------------- hToolbarPlaceholder.removeAllComponents(); if (toolbar != null) { // Attach a new toolbar hToolbarPlaceholder.addComponent(toolbar); } // TODO: FIGURE OUT THE DESTINY OF THIS // This exists to autohide responsive sandwich menu. //menu.removeStyleName ("valo-menu-visible"); } }); // Start on default Home navigator.navigateTo("home"); } @Override // DesktopInterface public void init(UI ui) { initAllLayouts(); initSecurityArea(); initNavigator(ui); } @Override // DesktopInterface public Layout getMainLayout() { return (vAppLayout); } @Override public Layout getSecurityLayout() { return (hSecurityArea); } @Override // DesktopInterface public void attach() { // Nothing } @Override // DesktopInterface public void detach() { // TODO: COMPONENT CLEANUP! log.info("detach() " + this); } @ServiceObject.Invalidate public void invalidate() { if (navigator != null && navigator.getUI().isAttached()) { // TODO: INVALIDATE THE DESTKTOP, _NOT_ THE WHOLE SESSION AND UI UI attached_ui = navigator.getUI(); attached_ui.getSession().getSession().invalidate(); // Actually this gets the ui reload pretty fast attached_ui.getPage().reload(); } } class SafeNavigator extends Navigator { public SafeNavigator(UI ui, ViewDisplay viewDisplay) { super(ui, viewDisplay); } @Override public void navigateTo(String navigationState) { try { super.navigateTo(navigationState); } catch (Exception e) { String html_message = "<h2>An unknown form of exception was found navigating to:<br>" + "<b>" + navigationState + "</b>" + "</h2>"; damage_report(html_message, e); } } } class ErrorView extends VerticalLayout implements View { private String err_message; private String err_details; public ErrorView() { addStyleName("damage-report"); setMargin(true); } public void setMessage(String html_message, String text_details) { err_message = html_message; err_details = text_details; } public void setMessage(String html_message, Exception e) { StringWriter errors = new StringWriter(); e.printStackTrace(new PrintWriter(errors)); setMessage(html_message, errors.toString()); } @Override public void enter(ViewChangeListener.ViewChangeEvent viewChangeEvent) { removeAllComponents(); addComponent(new Label("<h1>Damage Report<h1>" + err_message, ContentMode.HTML)); addComponent(new Label(err_details, ContentMode.PREFORMATTED)); } } private void damage_report(String html_message, String text_details) { damage_report_view.setMessage(html_message, text_details); navigator.navigateTo(DAMN); } private void damage_report(String html_message, Exception e) { damage_report_view.setMessage(html_message, e); navigator.navigateTo(DAMN); } } // EOF