/*!
* 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() );
}
}
}