/*! * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program 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. * * Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved. */ package org.pentaho.mantle.client.ui.xul; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JsArray; import com.google.gwt.core.client.JsonUtils; import com.google.gwt.http.client.Request; import com.google.gwt.http.client.RequestBuilder; import com.google.gwt.http.client.RequestCallback; import com.google.gwt.http.client.RequestException; import com.google.gwt.http.client.Response; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.DeckPanel; import com.google.gwt.user.client.ui.Panel; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.Tree; import com.google.gwt.user.client.ui.TreeItem; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.xml.client.Document; import com.google.gwt.xml.client.XMLParser; import org.pentaho.gwt.widgets.client.utils.i18n.IResourceBundleLoadCallback; import org.pentaho.gwt.widgets.client.utils.i18n.ResourceBundle; import org.pentaho.mantle.client.commands.AbstractCommand; import org.pentaho.mantle.client.events.EventBusUtil; import org.pentaho.mantle.client.events.SolutionBrowserCloseEvent; import org.pentaho.mantle.client.events.SolutionBrowserCloseEventHandler; import org.pentaho.mantle.client.events.SolutionBrowserDeselectEvent; import org.pentaho.mantle.client.events.SolutionBrowserDeselectEventHandler; import org.pentaho.mantle.client.events.SolutionBrowserOpenEvent; import org.pentaho.mantle.client.events.SolutionBrowserOpenEventHandler; import org.pentaho.mantle.client.events.SolutionBrowserSelectEvent; import org.pentaho.mantle.client.events.SolutionBrowserSelectEventHandler; import org.pentaho.mantle.client.messages.Messages; import org.pentaho.mantle.client.objects.MantleXulOverlay; import org.pentaho.mantle.client.solutionbrowser.tabs.IFrameTabPanel; import org.pentaho.ui.xul.XulException; import org.pentaho.ui.xul.XulOverlay; import org.pentaho.ui.xul.gwt.GwtXulDomContainer; import org.pentaho.ui.xul.gwt.GwtXulRunner; import org.pentaho.ui.xul.gwt.tags.GwtTree; import org.pentaho.ui.xul.gwt.util.AsyncXulLoader; import org.pentaho.ui.xul.gwt.util.IXulLoaderCallback; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; public class MantleXul implements IXulLoaderCallback, SolutionBrowserOpenEventHandler, SolutionBrowserCloseEventHandler, SolutionBrowserSelectEventHandler, SolutionBrowserDeselectEventHandler { public static final String PROPERTIES_EXTENSION = ".properties"; //$NON-NLS-1$ public static final String SEPARATOR = "/"; //$NON-NLS-1$ private GwtXulDomContainer container; private static MantleXul instance; private SimplePanel toolbar = new SimplePanel(); private SimplePanel menubar = new SimplePanel(); private SimplePanel adminPerspective = new SimplePanel(); private DeckPanel adminContentDeck = new DeckPanel(); private MantleController controller; private ArrayList<XulOverlay> overlays = new ArrayList<XulOverlay>(); private HashSet<String> loadedOverlays = new HashSet<String>(); private MantleXul() { AsyncXulLoader.loadXulFromUrl( GWT.getModuleBaseURL() + "xul/mantle.xul", GWT.getModuleBaseURL() + "messages/mantleMessages", this ); EventBusUtil.EVENT_BUS.addHandler( SolutionBrowserOpenEvent.TYPE, this ); EventBusUtil.EVENT_BUS.addHandler( SolutionBrowserCloseEvent.TYPE, this ); EventBusUtil.EVENT_BUS.addHandler( SolutionBrowserSelectEvent.TYPE, this ); EventBusUtil.EVENT_BUS.addHandler( SolutionBrowserDeselectEvent.TYPE, this ); } public static MantleXul getInstance() { if ( instance == null ) { instance = new MantleXul(); } return instance; } /** * Callback method for the MantleXulLoader. This is called when the Xul file has been processed. * * @param runner * GwtXulRunner instance ready for event handlers and initializing. */ public void xulLoaded( GwtXulRunner runner ) { // handlers need to be wrapped generically in GWT, create one and pass it our reference. // instantiate our Model and Controller controller = new MantleController( new MantleModel( this ) ); // Add handler to container container = (GwtXulDomContainer) runner.getXulDomContainers().get( 0 ); container.addEventHandler( controller ); try { runner.initialize(); } catch ( XulException e ) { Window.alert( "Error initializing XUL runner: " + e.getMessage() ); //$NON-NLS-1$ e.printStackTrace(); return; } // Get the toolbar from the XUL doc Widget bar = (Widget) container.getDocumentRoot().getElementById( "mainToolbarWrapper" ).getManagedObject(); //$NON-NLS-1$ Widget xultoolbar = (Widget) container.getDocumentRoot().getElementById( "mainToolbar" ).getManagedObject(); //$NON-NLS-1$ xultoolbar.getElement().removeClassName( "toolbar" ); toolbar.setStylePrimaryName( "mainToolbar-Wrapper" ); toolbar.setWidget( bar ); // Get the menubar from the XUL doc Widget menu = (Widget) container.getDocumentRoot().getElementById( "mainMenubar" ).getManagedObject(); //$NON-NLS-1$ menubar.setWidget( menu ); // check based on user permissions final String moduleBaseURL = GWT.getModuleBaseURL(); final String moduleName = GWT.getModuleName(); final String contextURL = moduleBaseURL.substring( 0, moduleBaseURL.lastIndexOf( moduleName ) ); final String url = contextURL + "api/repo/files/canCreate"; //$NON-NLS-1$ RequestBuilder executableTypesRequestBuilder = new RequestBuilder( RequestBuilder.GET, url ); executableTypesRequestBuilder.setHeader( "accept", "text/plain" ); executableTypesRequestBuilder.setHeader( "If-Modified-Since", "01 Jan 1970 00:00:00 GMT" ); try { executableTypesRequestBuilder.sendRequest( null, new RequestCallback() { public void onError( Request request, Throwable exception ) { // showError(exception); } public void onResponseReceived( Request request, Response response ) { if ( response.getStatusCode() == Response.SC_OK ) { Boolean visible = new Boolean( response.getText() ); controller.setMenuBarEnabled( "newmenu", visible ); controller.setToolBarButtonEnabled( "newButton", visible ); } } } ); } catch ( RequestException e ) { // showError(e); } // get the admin perspective from the XUL doc Widget admin = (Widget) container.getDocumentRoot().getElementById( "adminPerspective" ).getManagedObject(); //$NON-NLS-1$ admin.setStyleName( "admin-perspective" ); admin.getElement().getStyle().clearHeight(); admin.getElement().getStyle().clearWidth(); adminPerspective.setWidget( admin ); Panel adminContentPanel = (Panel) container.getDocumentRoot().getElementById( "adminContentPanel" ).getManagedObject(); adminContentPanel.add( adminContentDeck ); adminContentDeck.setHeight( "100%" ); adminContentDeck.getElement().getStyle().setProperty( "height", "100%" ); fetchPluginOverlays(); } public void customizeAdminStyle() { Timer t = new Timer() { public void run() { if ( container != null ) { cancel(); // call this method when Elements are added to DOM GwtTree adminCatTree = (GwtTree) container.getDocumentRoot().getElementById( "adminCatTree" ); adminCatTree.getTree().removeStyleName( "gwt-Tree" ); Panel adminContentPanel = (Panel) container.getDocumentRoot().getElementById( "adminContentPanel" ).getManagedObject(); adminContentPanel.setWidth( "100%" ); for ( int i = 0; i < adminCatTree.getTree().getItemCount(); i++ ) { TreeItem treeItem = adminCatTree.getTree().getItem( i ); Element e = treeItem.getElement(); e.getStyle().clearPadding(); e.addClassName( "adminCatTreeItem" ); if ( i == adminCatTree.getTree().getItemCount() - 1 ) { e.addClassName( "adminCatTreeItemLast" ); } } MantleXul.this.selectAdminCatTreeTreeItem( Messages.getString( "manageUsersAndRoles" ).replaceAll( "&", "&" ) ); } } }; t.scheduleRepeating( 250 ); } public void configureAdminCatTree() { String serviceUrl = GWT.getHostPageBaseURL() + "api/ldap/config/getAttributeValues"; RequestBuilder executableTypesRequestBuilder = new RequestBuilder( RequestBuilder.GET, serviceUrl ); executableTypesRequestBuilder.setHeader( "If-Modified-Since", "01 Jan 1970 00:00:00 GMT" ); try { executableTypesRequestBuilder.sendRequest( null, new RequestCallback() { public void onError( Request request, Throwable exception ) { } public void onResponseReceived( Request request, Response response ) { String securityProvider = response.getText(); enableUsersRolesTreeItem( securityProvider.contains( "DB_BASED_AUTHENTICATION" ) ); } } ); } catch ( RequestException e ) { //ignored } } public void enableUsersRolesTreeItem( final boolean enabled ) { Timer t = new Timer() { public void run() { if ( container != null ) { cancel(); String usersRolesLabel = Messages.getString( "users" ) + "/" + Messages.getString( "roles" ); GwtTree adminCatTree = (GwtTree) container.getDocumentRoot().getElementById( "adminCatTree" ); TreeItem usersRolesTreeItem = null; Tree adminTree = adminCatTree.getTree(); Iterator<TreeItem> adminTreeItr = adminTree.treeItemIterator(); while ( adminTreeItr.hasNext() ) { usersRolesTreeItem = adminTreeItr.next(); if ( usersRolesTreeItem.getText().equals( usersRolesLabel ) ) { usersRolesTreeItem.setVisible( enabled ); break; } } } } }; t.scheduleRepeating( 250 ); } public void selectAdminCatTreeTreeItem( final String treeLabel ) { GwtTree adminCatTree = (GwtTree) container.getDocumentRoot().getElementById( "adminCatTree" ); Tree adminTree = adminCatTree.getTree(); adminTree.setSelectedItem( null, true ); Iterator<TreeItem> adminTreeItr = adminTree.treeItemIterator(); while ( adminTreeItr.hasNext() ) { TreeItem treeItem = adminTreeItr.next(); if ( treeItem.getText().equals( treeLabel ) ) { adminTree.setSelectedItem( treeItem, true ); break; } } } public DeckPanel getAdminContentDeck() { return adminContentDeck; } public Widget getToolbar() { return toolbar; } public Widget getMenubar() { return menubar; } public Widget getAdminPerspective() { return adminPerspective; } private void fetchPluginOverlays() { AbstractCommand cmd = new AbstractCommand() { protected void performOperation( boolean feedback ) { performOperation(); } protected void performOperation() { final String url = GWT.getHostPageBaseURL() + "api/plugin-manager/overlays"; //$NON-NLS-1$ RequestBuilder builder = new RequestBuilder( RequestBuilder.GET, url ); builder.setHeader( "If-Modified-Since", "01 Jan 1970 00:00:00 GMT" ); builder.setHeader( "accept", "application/json" ); try { builder.sendRequest( null, new RequestCallback() { public void onError( Request request, Throwable exception ) { Window.alert( exception.getMessage() ); } public void onResponseReceived( Request request, Response response ) { JsArray<JsXulOverlay> jsoverlays = JsXulOverlay.parseJson( JsonUtils.escapeJsonForEval( response.getText() ) ); ArrayList<XulOverlay> overlays = new ArrayList<XulOverlay>(); for ( int i = 0; i < jsoverlays.length(); i++ ) { JsXulOverlay o = jsoverlays.get( i ); MantleXulOverlay overlay; overlay = new MantleXulOverlay( o.getId(), o.getOverlayUri(), o.getSource(), o.getResourceBundleUri(), Integer.parseInt( o.getPriority() ) ); overlays.add( overlay ); } MantleXul.this.addOverlays( overlays ); final String url = GWT.getHostPageBaseURL() + "plugin/data-access/api/permissions/hasDataAccess"; //$NON-NLS-1$ RequestBuilder builder = new RequestBuilder( RequestBuilder.GET, url ); builder.setHeader( "If-Modified-Since", "01 Jan 1970 00:00:00 GMT" ); builder.setHeader( "accept", "application/json" ); try { builder.sendRequest( null, new RequestCallback() { public void onError( Request request, Throwable exception ) { Window.alert( exception.getMessage() ); } public void onResponseReceived( Request request, Response response ) { if ( response.getText().equals( "true" ) ) { controller.loadOverlay( "dataaccess" ); } } } ); } catch ( RequestException e ) { // showError(e); } } } ); } catch ( RequestException e ) { // showError(e); } } }; cmd.execute(); } public void overlayLoaded() { } /** * Class to compare Overlays using their priority attribute */ private class OverlayPriority implements Comparator<XulOverlay> { @Override public int compare( XulOverlay o1, XulOverlay o2 ) { int value = 0; if ( o1 != null && o2 != null ) { if ( o1.getPriority() > o2.getPriority() ) { value = 1; } else if ( o1.getPriority() < o2.getPriority() ) { value = -1; } } else if ( o1 == null && o2 != null ) { value = -1; } else if ( o2 == null && o1 != null ) { value = 1; } return value; } } /** * Class to compare Overlays using their priority attribute */ private class OverlayLoader { private final List<XulOverlay> overlays; public OverlayLoader( List<XulOverlay> overlays ) { this.overlays = new ArrayList<XulOverlay>( overlays ); } public void loadOverlays() { loadOverlays( 0 ); } private void loadOverlays( final int index ) { if ( index < overlays.size() ) { final XulOverlay overlayToLoad = overlays.get( index ); final String id = overlayToLoad.getId(); if ( loadedOverlays.contains( id ) ) { // already loaded - skip this one and load the next OverlayLoader.this.loadOverlays( index + 1 ); } else { loadedOverlays.add( id ); final boolean applyOnStart = id.startsWith( "startup" ) || id.startsWith( "sticky" ); final Document doc = XMLParser.parse( overlayToLoad.getSource() ); final String bundleUri = overlayToLoad.getResourceBundleUri(); String folder = ""; //$NON-NLS-1$ String baseName = bundleUri; // we have to separate the folder from the base name if ( bundleUri.indexOf( SEPARATOR ) > -1 ) { folder = bundleUri.substring( 0, bundleUri.lastIndexOf( SEPARATOR ) + 1 ); baseName = bundleUri.substring( bundleUri.lastIndexOf( SEPARATOR ) + 1 ); } // some may put the .properties on incorrectly if ( baseName.contains( PROPERTIES_EXTENSION ) ) { baseName = baseName.substring( 0, baseName.indexOf( PROPERTIES_EXTENSION ) ); } // some may put the .properties on incorrectly if ( baseName.contains( ".properties" ) ) { baseName = baseName.substring( 0, baseName.indexOf( ".properties" ) ); } try { final ResourceBundle bundle = new ResourceBundle(); bundle.loadBundle( folder, baseName, true, new IResourceBundleLoadCallback() { public void bundleLoaded( String arg0 ) { try { container.loadOverlay( doc, bundle, applyOnStart ); } catch ( XulException e ) { //ignored } finally { OverlayLoader.this.loadOverlays( index + 1 ); } } } ); } catch ( Exception e ) { Window.alert( "Error loading message bundle: " + e.getMessage() ); //$NON-NLS-1$ e.printStackTrace(); } } } } } public void addOverlays( ArrayList<XulOverlay> overlays ) { this.overlays.addAll( overlays ); Collections.sort( this.overlays, new OverlayPriority() ); if ( this.overlays.size() > 0 ) { // wait for container to be loaded/ready Timer loadOverlayTimer = new Timer() { public void run() { if ( container != null ) { cancel(); new OverlayLoader( MantleXul.this.overlays ).loadOverlays(); } } }; loadOverlayTimer.scheduleRepeating( 250 ); } } public void applyOverlays( Set<String> overlayIds ) { if ( overlayIds != null && !overlayIds.isEmpty() ) { for ( String overlayId : overlayIds ) { applyOverlay( overlayId ); } } } public void applyOverlay( final String id ) { if ( container != null ) { try { container.loadOverlay( id ); } catch ( XulException e ) { //ignored } } else { Timer t = new Timer() { public void run() { try { if ( container != null ) { cancel(); container.loadOverlay( id ); } } catch ( XulException e ) { //ignored } } }; t.scheduleRepeating( 250 ); } } public void removeOverlays( Set<String> overlayIds ) { if ( overlayIds != null && !overlayIds.isEmpty() ) { for ( String overlayId : overlayIds ) { removeOverlay( overlayId ); } } } public void removeOverlay( final String id ) { if ( container != null ) { try { container.removeOverlay( id ); } catch ( XulException e ) { //ignored } } else { Timer t = new Timer() { public void run() { try { if ( container != null ) { cancel(); container.removeOverlay( id ); } } catch ( XulException e ) { //ignored } } }; t.scheduleRepeating( 250 ); } } public void overlayRemoved() { } public ArrayList<XulOverlay> getOverlays() { return overlays; } public void onTabOpened( SolutionBrowserOpenEvent event ) { if ( event.getWidget() != null ) { applyOverlays( ( (IFrameTabPanel) event.getWidget() ).getOverlayIds() ); } } public void onTabSelected( SolutionBrowserSelectEvent event ) { if ( event.getWidget() != null ) { applyOverlays( ( (IFrameTabPanel) event.getWidget() ).getOverlayIds() ); } } public void onTabClosed( SolutionBrowserCloseEvent event ) { if ( event.getWidget() != null ) { removeOverlays( ( (IFrameTabPanel) event.getWidget() ).getOverlayIds() ); } } public void onTabDeselected( SolutionBrowserDeselectEvent event ) { if ( event.getWidget() != null ) { removeOverlays( ( (IFrameTabPanel) event.getWidget() ).getOverlayIds() ); } } }