/*! * 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; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JsArray; import com.google.gwt.core.client.JsArrayString; import com.google.gwt.core.client.JsonUtils; import com.google.gwt.core.client.RunAsyncCallback; import com.google.gwt.core.client.Scheduler.ScheduledCommand; 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.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.DeckPanel; import com.google.gwt.user.client.ui.Frame; import com.google.gwt.user.client.ui.HasText; import com.google.gwt.user.client.ui.MenuBar; import com.google.gwt.user.client.ui.MenuItem; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.Widget; import org.pentaho.gwt.widgets.client.menuitem.PentahoMenuItem; import org.pentaho.gwt.widgets.client.utils.i18n.IResourceBundleLoadCallback; import org.pentaho.gwt.widgets.client.utils.i18n.ResourceBundle; import org.pentaho.mantle.client.MantleApplication; import org.pentaho.mantle.client.admin.ISysAdminPanel; import org.pentaho.mantle.client.events.EventBusUtil; import org.pentaho.mantle.client.events.PerspectivesLoadedEvent; import org.pentaho.mantle.client.objects.MantleXulOverlay; import org.pentaho.mantle.client.solutionbrowser.SolutionBrowserPanel; import org.pentaho.mantle.client.ui.CustomDropDown.MODE; import org.pentaho.mantle.client.ui.xul.JsPerspective; import org.pentaho.mantle.client.ui.xul.JsXulOverlay; import org.pentaho.mantle.client.ui.xul.MantleXul; import org.pentaho.mantle.client.workspace.SchedulesPerspectivePanel; import org.pentaho.platform.api.engine.perspective.pojo.IPluginPerspective; import org.pentaho.platform.plugin.services.pluginmgr.perspective.pojo.DefaultPluginPerspective; import org.pentaho.ui.xul.XulOverlay; import org.pentaho.ui.xul.gwt.util.ResourceBundleTranslator; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; public class PerspectiveManager extends SimplePanel { private static final String ALLOW_TRANSPARENCY_ATTRIBUTE = "allowTransparency"; private static final String REMOVE_IFRAME_BORDERS = "frameBorder"; public static final String ADMIN_PERSPECTIVE = "admin.perspective"; public static final String SCHEDULES_PERSPECTIVE = "schedules.perspective"; public static final String OPENED_PERSPECTIVE = "opened.perspective"; public static final String HOME_PERSPECTIVE = "home.perspective"; public static final String BROWSER_PERSPECTIVE = "browser.perspective"; public static final String PROPERTIES_EXTENSION = ".properties"; //$NON-NLS-1$ public static final String SEPARATOR = "/"; //$NON-NLS-1$ private static PerspectiveManager instance = new PerspectiveManager(); private CustomDropDown perspectiveDropDown; private HashMap<String, MenuItem> perspectiveMenuItemMap = new HashMap<String, MenuItem>(); private PentahoMenuItem browserMenuItem; private PentahoMenuItem schedulesMenuItem; // create an overlay list to later register with the main toolbar/menubar private ArrayList<XulOverlay> overlays = new ArrayList<XulOverlay>(); private ArrayList<IPluginPerspective> perspectives; private IPluginPerspective activePerspective; private boolean loaded = false; public static PerspectiveManager getInstance() { return instance; } private PerspectiveManager() { getElement().setId( "mantle-perspective-switcher" ); setStyleName( "mantle-perspective-switcher" ); final String url = GWT.getHostPageBaseURL() + "api/plugin-manager/perspectives?ts=" + System.currentTimeMillis(); //$NON-NLS-1$ RequestBuilder builder = new RequestBuilder( RequestBuilder.GET, url ); builder.setHeader( "Content-Type", "application/json" ); //$NON-NLS-1$//$NON-NLS-2$ builder.setHeader( "If-Modified-Since", "01 Jan 1970 00:00:00 GMT" ); try { builder.sendRequest( null, new RequestCallback() { public void onError( Request request, Throwable exception ) { Window.alert( "getPluginPerpectives fail: " + exception.getMessage() ); } public void onResponseReceived( Request request, Response response ) { JsArray<JsPerspective> jsperspectives = JsPerspective.parseJson( JsonUtils.escapeJsonForEval( response.getText() ) ); ArrayList<IPluginPerspective> perspectives = new ArrayList<IPluginPerspective>(); for ( int i = 0; i < jsperspectives.length(); i++ ) { JsPerspective jsperspective = jsperspectives.get( i ); DefaultPluginPerspective perspective = new DefaultPluginPerspective(); perspective.setContentUrl( jsperspective.getContentUrl() ); perspective.setId( jsperspective.getId() ); perspective.setLayoutPriority( Integer.parseInt( jsperspective.getLayoutPriority() ) ); ArrayList<String> requiredSecurityActions = new ArrayList<String>(); if ( jsperspective.getRequiredSecurityActions() != null ) { for ( int j = 0; j < jsperspective.getRequiredSecurityActions().length(); j++ ) { requiredSecurityActions.add( jsperspective.getRequiredSecurityActions().get( j ) ); } } // will need to iterate over jsoverlays and convert to MantleXulOverlay ArrayList<XulOverlay> overlays = new ArrayList<XulOverlay>(); if ( jsperspective.getOverlays() != null ) { for ( int j = 0; j < jsperspective.getOverlays().length(); j++ ) { JsXulOverlay o = jsperspective.getOverlays().get( j ); MantleXulOverlay overlay = new MantleXulOverlay( o.getId(), o.getOverlayUri(), o.getSource(), o.getResourceBundleUri() ); overlays.add( overlay ); } } perspective.setOverlays( overlays ); perspective.setRequiredSecurityActions( requiredSecurityActions ); perspective.setResourceBundleUri( jsperspective.getResourceBundleUri() ); perspective.setTitle( jsperspective.getTitle() ); perspectives.add( perspective ); } setPluginPerspectives( perspectives ); } } ); } catch ( RequestException e ) { // showError(e); } registerFunctions( this ); } protected void setPluginPerspectives( final ArrayList<IPluginPerspective> perspectives ) { this.perspectives = perspectives; clear(); // sort perspectives Collections.sort( perspectives, new Comparator<IPluginPerspective>() { public int compare( IPluginPerspective o1, IPluginPerspective o2 ) { Integer p1 = new Integer( o1.getLayoutPriority() ); Integer p2 = new Integer( o2.getLayoutPriority() ); return p1.compareTo( p2 ); } } ); MenuBar perspectiveMenuBar = new MenuBar( true ); perspectiveDropDown = new CustomDropDown( "", perspectiveMenuBar, MODE.MAJOR ); setWidget( perspectiveDropDown ); loadResourceBundle( perspectiveDropDown, perspectives.get( 0 ) ); ScheduledCommand noopCmd = new ScheduledCommand() { public void execute() { } }; for ( final IPluginPerspective perspective : perspectives ) { // if we have overlays add it to the list if ( perspective.getOverlays() != null ) { overlays.addAll( perspective.getOverlays() ); } final MenuItem menuItem = new MenuItem( "", noopCmd ); perspectiveMenuItemMap.put( perspective.getId(), menuItem ); ScheduledCommand cmd = new ScheduledCommand() { public void execute() { showPerspective( perspective ); perspectiveDropDown.setText( menuItem.getText() ); perspectiveDropDown.hidePopup(); } }; menuItem.setScheduledCommand( cmd ); perspectiveMenuBar.addItem( menuItem ); loadResourceBundle( menuItem, perspective ); } // register overlays with XulMainToolbar MantleXul.getInstance().addOverlays( overlays ); setPerspective( perspectives.get( 0 ).getId() ); loaded = true; EventBusUtil.EVENT_BUS.fireEvent( new PerspectivesLoadedEvent() ); } private void loadResourceBundle( final HasText textWidget, final IPluginPerspective perspective ) { try { String bundle = perspective.getResourceBundleUri(); if ( bundle == null ) { return; } String folder = ""; //$NON-NLS-1$ String baseName = bundle; // we have to separate the folder from the base name if ( bundle.indexOf( SEPARATOR ) > -1 ) { folder = bundle.substring( 0, bundle.lastIndexOf( SEPARATOR ) + 1 ); baseName = bundle.substring( bundle.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" ) ); } final ResourceBundle messageBundle = new ResourceBundle(); messageBundle.loadBundle( folder, baseName, true, new IResourceBundleLoadCallback() { public void bundleLoaded( String arg0 ) { String title = ResourceBundleTranslator.translate( perspective.getTitle(), messageBundle ); perspective.setTitle( title ); textWidget.setText( title ); } } ); } catch ( Throwable t ) { Window.alert( "Error loading message bundle: " + t.getMessage() ); //$NON-NLS-1$ t.printStackTrace(); } } public void enablePerspective( final String perspectiveId, boolean enabled ) { if ( perspectives == null ) { return; } // return value to indicate if perspective now disabled for ( int i = 0; i < perspectives.size(); i++ ) { if ( perspectives.get( i ).getId().equalsIgnoreCase( perspectiveId ) ) { perspectiveMenuItemMap.get( perspectiveId ).setEnabled( enabled ); return; } } return; } public boolean setPerspective( final String perspectiveId ) { if ( perspectives == null ) { return false; } // return value to indicate if perspective now shown for ( int i = 0; i < perspectives.size(); i++ ) { if ( perspectives.get( i ).getId().equalsIgnoreCase( perspectiveId ) ) { showPerspective( perspectives.get( i ) ); return true; } } return false; } /** * Show the perspective defined as with the highest priority */ public void showPerspectiveWithHighestPriority() { // perspectives list is sorted by priority, so show the first one setPerspective( perspectives.get( 0 ).getId() ); } private void showPerspective( final IPluginPerspective perspective ) { if ( activePerspective == perspective ) { return; } if ( activePerspective != null && ADMIN_PERSPECTIVE.equals( activePerspective.getId() ) ) { final Widget activeAdminPanel = MantleXul.getInstance().getAdminContentDeck().getWidget( MantleXul.getInstance() .getAdminContentDeck().getVisibleWidget() ); if ( activeAdminPanel != null ) { if ( activeAdminPanel instanceof ISysAdminPanel ) { ( (ISysAdminPanel) activeAdminPanel ).passivate( new AsyncCallback<Boolean>() { @Override public void onFailure( Throwable caught ) { } @Override public void onSuccess( Boolean result ) { showPerspectiveContinue( perspective ); } } ); } else { showPerspectiveContinue( perspective ); } } } else { showPerspectiveContinue( perspective ); } } private void showPerspectiveContinue( IPluginPerspective perspective ) { if ( !perspective.getTitle().startsWith( "${" ) ) { perspectiveDropDown.setText( perspective.getTitle() ); } for ( MenuItem m : perspectiveMenuItemMap.values() ) { m.getElement().removeClassName( "custom-dropdown-selected" ); } perspectiveMenuItemMap.get( perspective.getId() ).getElement().addClassName( "custom-dropdown-selected" ); // before we show.. de-activate current perspective (based on shown widget) Widget w = MantleApplication.getInstance().getContentDeck().getWidget( MantleApplication.getInstance().getContentDeck().getVisibleWidget() ); if ( w instanceof Frame && !perspective.getId().equals( w.getElement().getId() ) ) { // invoke deactivation method Frame frame = (Frame) w; perspectiveDeactivated( frame.getElement() ); } // remove current perspective overlays if ( activePerspective != null ) { for ( XulOverlay o : activePerspective.getOverlays() ) { if ( !o.getId().startsWith( "startup" ) && !o.getId().startsWith( "sticky" ) ) { MantleXul.getInstance().removeOverlay( o.getId() ); } } for ( XulOverlay overlay : MantleXul.getInstance().getOverlays() ) { if ( overlay.getId().startsWith( activePerspective.getId() + ".overlay." ) ) { MantleXul.getInstance().removeOverlay( overlay.getId() ); } } } // now it's safe to set active this.activePerspective = perspective; if ( perspective.getOverlays() != null ) { // handle PERSPECTIVE overlays for ( XulOverlay overlay : perspective.getOverlays() ) { if ( !overlay.getId().startsWith( "startup" ) && !overlay.getId().startsWith( "sticky" ) ) { MantleXul.getInstance().applyOverlay( overlay.getId() ); } } // handle PLUGIN overlays for ( XulOverlay overlay : MantleXul.getInstance().getOverlays() ) { if ( overlay.getId().startsWith( perspective.getId() + ".overlay." ) ) { MantleXul.getInstance().applyOverlay( overlay.getId() ); } } } if ( !perspective.getId().equals( OPENED_PERSPECTIVE ) && !perspective.getId().equals( SCHEDULES_PERSPECTIVE ) && !perspective.getId().equals( ADMIN_PERSPECTIVE ) ) { hijackContentArea( perspective ); } // if the selected perspective is "opened.perspective" if ( perspective.getId().equals( OPENED_PERSPECTIVE ) ) { showOpenedPerspective( true, false ); } else if ( perspective.getId().equals( SCHEDULES_PERSPECTIVE ) ) { showSchedulesPerspective(); } else if ( perspective.getId().equals( ADMIN_PERSPECTIVE ) ) { showAdminPerspective( false, false ); } } private void showOpenedPerspective( boolean browserChecked, boolean schedulesChecked ) { DeckPanel contentDeck = MantleApplication.getInstance().getContentDeck(); if ( MantleApplication.getInstance().getContentDeck().getWidgetIndex( SolutionBrowserPanel.getInstance() ) == -1 ) { contentDeck.add( SolutionBrowserPanel.getInstance() ); } // show stuff we've created/configured contentDeck.showWidget( contentDeck.getWidgetIndex( SolutionBrowserPanel.getInstance() ) ); SolutionBrowserPanel.getInstance().setNavigatorShowing( SolutionBrowserPanel.getInstance().isNavigatorShowing() ); setCheckMMenuItem( browserChecked, schedulesChecked ); } private void showSchedulesPerspective() { GWT.runAsync( new RunAsyncCallback() { public void onSuccess() { DeckPanel contentDeck = MantleApplication.getInstance().getContentDeck(); if ( MantleApplication.getInstance().getContentDeck().getWidgetIndex( SchedulesPerspectivePanel.getInstance() ) == -1 ) { contentDeck.add( SchedulesPerspectivePanel.getInstance() ); } else { SchedulesPerspectivePanel.getInstance().refresh(); } contentDeck.showWidget( contentDeck.getWidgetIndex( SchedulesPerspectivePanel.getInstance() ) ); } public void onFailure( Throwable reason ) { } } ); setCheckMMenuItem( false, true ); } private void showAdminPerspective( boolean browserChecked, boolean schedulesChecked ) { DeckPanel contentDeck = MantleApplication.getInstance().getContentDeck(); if ( MantleApplication.getInstance().getContentDeck() .getWidgetIndex( MantleXul.getInstance().getAdminPerspective() ) == -1 ) { contentDeck.add( MantleXul.getInstance().getAdminPerspective() ); } contentDeck.showWidget( contentDeck.getWidgetIndex( MantleXul.getInstance().getAdminPerspective() ) ); MantleXul.getInstance().customizeAdminStyle(); MantleXul.getInstance().configureAdminCatTree(); // disable Browser and schedules menuItem setCheckMMenuItem( browserChecked, schedulesChecked ); } private void hijackContentArea( IPluginPerspective perspective ) { // hijack content area (or simply find and select existing content) Frame frame = null; for ( int i = 0; i < MantleApplication.getInstance().getContentDeck().getWidgetCount(); i++ ) { Widget w = MantleApplication.getInstance().getContentDeck().getWidget( i ); if ( w instanceof Frame && perspective.getId().equals( w.getElement().getId() ) ) { frame = (Frame) w; } } if ( frame == null ) { frame = new Frame( perspective.getContentUrl() ); Element frameElement = frame.getElement(); frameElement.setAttribute( ALLOW_TRANSPARENCY_ATTRIBUTE, "true" ); // BISERVER-7661 Mantle sections have a border on IE9 (not on chrome, firefox) frameElement.setAttribute( REMOVE_IFRAME_BORDERS, "0" ); frame.getElement().setId( perspective.getId() ); MantleApplication.getInstance().getContentDeck().add( frame ); } MantleApplication.getInstance().getContentDeck().showWidget( MantleApplication.getInstance().getContentDeck().getWidgetIndex( frame ) ); final Element frameElement = frame.getElement(); perspectiveActivated( frameElement ); } private native void perspectiveActivated( Element frameElement ) /*-{ try { frameElement.contentWindow.perspectiveActivated(); } catch (e) { } }-*/; private native void perspectiveDeactivated( Element frameElement ) /*-{ try { frameElement.contentWindow.perspectiveDeactivated(); } catch (e) { } }-*/; private native void registerFunctions( PerspectiveManager manager ) /*-{ $wnd.mantle_getPerspectives = function() { return manager.@org.pentaho.mantle.client.ui.PerspectiveManager::getPerspectives()(); } $wnd.mantle_setPerspective = function(perspectiveId) { manager.@org.pentaho.mantle.client.ui.PerspectiveManager::setPerspective(Ljava/lang/String;)(perspectiveId); } }-*/; private JsArrayString getPerspectives() { JsArrayString stringArray = getJsArrayString(); for ( IPluginPerspective perspective : perspectives ) { stringArray.push( perspective.getId() ); } return stringArray; } private native JsArrayString getJsArrayString() /*-{ return []; }-*/; public IPluginPerspective getActivePerspective() { return activePerspective; } public void setActivePerspective( IPluginPerspective activePerspective ) { this.activePerspective = activePerspective; setPerspective( activePerspective.getId() ); } public void setBrowserMenuItem( PentahoMenuItem menuItem ) { this.browserMenuItem = menuItem; } public void setSchedulesMenuItem( PentahoMenuItem menuItem ) { this.schedulesMenuItem = menuItem; } private void setCheckMMenuItem( boolean browserChecked, boolean schedulesChecked ) { if ( this.browserMenuItem != null && this.schedulesMenuItem != null ) { this.browserMenuItem.setChecked( browserChecked ); this.schedulesMenuItem.setChecked( schedulesChecked ); } } public boolean isLoaded() { return loaded; } public void setLoaded( boolean loaded ) { this.loaded = loaded; } }