/*
* 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 2008 Pentaho Corporation. All rights reserved.
*
* Created Mar 25, 2008
* @author Michael D'Amour
*/
package org.pentaho.mantle.client.solutionbrowser.tabs;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import org.pentaho.gwt.widgets.client.utils.string.StringUtils;
import org.pentaho.mantle.client.messages.Messages;
import org.pentaho.mantle.client.objects.SolutionFileInfo;
import org.pentaho.mantle.client.solutionbrowser.SolutionBrowserListener;
import org.pentaho.mantle.client.solutionbrowser.SolutionBrowserPerspective;
import org.pentaho.mantle.client.solutionbrowser.filelist.FileItem;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.event.logical.shared.BeforeSelectionEvent;
import com.google.gwt.event.logical.shared.BeforeSelectionHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.Window.ClosingEvent;
import com.google.gwt.user.client.Window.ClosingHandler;
import com.google.gwt.user.client.ui.Frame;
import com.google.gwt.user.client.ui.NamedFrame;
import com.google.gwt.user.client.ui.TabPanel;
import com.google.gwt.user.client.ui.Widget;
public class MantleTabPanel extends TabPanel {
public static final int CURRENT_SELECTED_TAB = -1;
private static final String FRAME_ID_PRE = "frame_"; //$NON-NLS-1$
private static int frameIdCount = 0;
private HashMap<Widget, TabWidget> contentTabMap = new HashMap<Widget, TabWidget>();
private int previousIndex;
public MantleTabPanel() {
setupNativeHooks(this);
// add window close listener
Window.addWindowClosingHandler(new ClosingHandler() {
public void onWindowClosing(ClosingEvent event) {
// close only if we have stuff open
if (getTabBar().getTabCount() > 0) {
event.setMessage(Messages.getString("windowCloseWarning")); //$NON-NLS-1$
}
}
});
addBeforeSelectionHandler(new BeforeSelectionHandler<Integer>() {
public void onBeforeSelection(BeforeSelectionEvent<Integer> event) {
previousIndex = getTabBar().getSelectedTab();
}
});
addSelectionHandler(new SelectionHandler<Integer>() {
public void onSelection(SelectionEvent<Integer> event) {
int tabIndex = event.getSelectedItem();
SolutionBrowserPerspective.getInstance().fireSolutionBrowserListenerEvent(SolutionBrowserListener.EventType.DESELECT, previousIndex);
SolutionBrowserPerspective.getInstance().fireSolutionBrowserListenerEvent(SolutionBrowserListener.EventType.SELECT, tabIndex);
if (previousIndex != tabIndex) {
Widget tabPanel = getWidget(tabIndex);
Window.setTitle(Messages.getString("productName") + " - " + getCurrentTab().getText()); //$NON-NLS-1$ //$NON-NLS-2$
if (tabPanel instanceof IFrameTabPanel) {
NamedFrame frame = ((IFrameTabPanel) tabPanel).getFrame();
frame.setVisible(true);
refreshIfPDF();
}
}
for (int i = 0; i < tabIndex; i++) {
hideFrame(i);
}
for (int i = tabIndex + 1; i < getTabBar().getTabCount(); i++) {
hideFrame(i);
}
}
});
setHeight("100%"); //$NON-NLS-1$
setWidth("100%"); //$NON-NLS-1$
}
public void add(Widget w, TabWidget tabWidget) {
super.add(w, tabWidget);
contentTabMap.put(w, tabWidget);
}
/*
* This should only ever get invoked via JSNI now
*/
@SuppressWarnings("unused")
private void showNewURLTab(String tabName, String tabTooltip, final String url) {
showNewURLTab(tabName, tabTooltip, url, false);
}
public void showNewURLTab(String tabName, String tabTooltip, final String url, boolean setFileInfoInFrame) {
final int elementId = getWidgetCount();
String frameName = getUniqueFrameName();
// check for other tabs with this name
if (existingTabMatchesName(tabName)) {
int counter = 2;
while (true) {
// Loop until a unique tab name is not found
// i.e. get the last counter number and then add 1 to it for the new tab name
if (existingTabMatchesName(tabName + " (" + counter + ")")) { // unique //$NON-NLS-1$ //$NON-NLS-2$
counter++;
continue;
} else {
tabName = tabName + " (" + counter + ")"; //$NON-NLS-1$ //$NON-NLS-2$
tabTooltip = tabTooltip + " (" + counter + ")"; //$NON-NLS-1$ //$NON-NLS-2$
break;
}
}
}
IFrameTabPanel panel = new IFrameTabPanel(frameName, url);
add(panel, new TabWidget(tabName, tabTooltip, SolutionBrowserPerspective.getInstance(), this, panel));
selectTab(elementId);
final ArrayList<com.google.gwt.dom.client.Element> parentList = new ArrayList<com.google.gwt.dom.client.Element>();
com.google.gwt.dom.client.Element parent = panel.getFrame().getElement();
while (parent != getElement()) {
parentList.add(parent);
parent = parent.getParentElement();
}
Collections.reverse(parentList);
for (int i = 1; i < parentList.size(); i++) {
parentList.get(i).getStyle().setProperty("height", "100%"); //$NON-NLS-1$ //$NON-NLS-2$
}
SolutionBrowserPerspective.getInstance().showContent();
SolutionBrowserPerspective.getInstance().fireSolutionBrowserListenerEvent(SolutionBrowserListener.EventType.OPEN, getTabBar().getSelectedTab());
if (setFileInfoInFrame) {
setFileInfoInFrame(SolutionBrowserPerspective.getInstance().getFilesListPanel().getSelectedFileItem());
}
}
private native void setupNativeHooks(MantleTabPanel tabPanel)
/*-{
$wnd.enableContentEdit = function(enable) {
tabPanel.@org.pentaho.mantle.client.solutionbrowser.tabs.MantleTabPanel::enableContentEdit(Z)(enable);
}
$wnd.setContentEditSelected = function(enable) {
tabPanel.@org.pentaho.mantle.client.solutionbrowser.tabs.MantleTabPanel::setContentEditSelected(Z)(enable);
}
$wnd.registerContentOverlay = function(id) {
tabPanel.@org.pentaho.mantle.client.solutionbrowser.tabs.MantleTabPanel::registerContentOverlay(Ljava/lang/String;)(id);
}
$wnd.registerContentCallback = function(callback) {
tabPanel.@org.pentaho.mantle.client.solutionbrowser.tabs.MantleTabPanel::setCurrentTabJSCallback(Lcom/google/gwt/core/client/JavaScriptObject;)(callback);
}
$wnd.enableAdhocSave = function(enable) {
tabPanel.@org.pentaho.mantle.client.solutionbrowser.tabs.MantleTabPanel::setCurrentTabSaveEnabled(Z)(enable);
}
$wnd.closeTab = function(url) {
tabPanel.@org.pentaho.mantle.client.solutionbrowser.tabs.MantleTabPanel::closeTab(Ljava/lang/String;)(url);
}
$wnd.mantle_openTab = function(name, title, url) {
tabPanel.@org.pentaho.mantle.client.solutionbrowser.tabs.MantleTabPanel::showNewURLTab(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)(name, title, url);
}
$wnd.openURL = function(name, tooltip, url){
tabPanel.@org.pentaho.mantle.client.solutionbrowser.tabs.MantleTabPanel::showNewURLTab(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)(name, tooltip, url);
}
}-*/;
public Widget getCurrentTab(int tabIndex) {
Widget tabPanel = null;
if (tabIndex >= 0 && getWidgetCount() > tabIndex) {
tabPanel = getWidget(tabIndex);
} else {
int selectedTabIndex = getTabBar().getSelectedTab();
if (selectedTabIndex >= 0) {
tabPanel = getWidget(selectedTabIndex);
}
}
return tabPanel;
}
public TabWidget getCurrentTab() {
return contentTabMap.get(getWidget(getTabBar().getSelectedTab()));
}
public TabWidget getTabForWidget(Widget tabWidget) {
return contentTabMap.get(getWidget(getWidgetIndex(tabWidget)));
}
/**
* This method returns the current frame element id.
*
* @return
*/
public String getCurrentFrameElementId() {
int curpos = getTabBar().getSelectedTab();
final IFrameTabPanel curPanel = (IFrameTabPanel) getWidget(curpos);
return curPanel.getFrame().getElement().getAttribute("id"); //$NON-NLS-1$
}
public IFrameTabPanel getCurrentFrame() {
int curpos = getTabBar().getSelectedTab();
if (curpos == -1) {
return null;
}
final IFrameTabPanel curPanel = (IFrameTabPanel) getWidget(curpos);
return curPanel;
}
public void setCurrentTabSaveEnabled(boolean enabled) {
IFrameTabPanel panel = getCurrentFrame();
if (panel != null) {
panel.setSaveEnabled(enabled);
}
SolutionBrowserPerspective.getInstance().fireSolutionBrowserListenerEvent(SolutionBrowserListener.EventType.SELECT, getTabBar().getSelectedTab());
}
/*
* registerContentOverlay - register the overlay with the panel. Once the registration is done it fires a soultion browser event passing the current tab index
* and the type of event
*/
public void registerContentOverlay(String id) {
IFrameTabPanel panel = getCurrentFrame();
panel.addOverlay(id);
SolutionBrowserPerspective.getInstance().fireSolutionBrowserListenerEvent(SolutionBrowserListener.EventType.OPEN, getTabBar().getSelectedTab());
}
public void enableContentEdit(boolean enable) {
IFrameTabPanel panel = getCurrentFrame();
panel.setEditEnabled(enable);
SolutionBrowserPerspective.getInstance().fireSolutionBrowserListenerEvent(SolutionBrowserListener.EventType.UNDEFINED, getTabBar().getSelectedTab());
}
public void setContentEditSelected(boolean selected) {
IFrameTabPanel panel = getCurrentFrame();
panel.setEditSelected(selected);
SolutionBrowserPerspective.getInstance().fireSolutionBrowserListenerEvent(SolutionBrowserListener.EventType.UNDEFINED, getTabBar().getSelectedTab());
}
// Content frames can register a Javascript object to receive various PUC notifications. We broker that out
// to the appropriate IFrameTabPanel here.
public void setCurrentTabJSCallback(JavaScriptObject obj) {
IFrameTabPanel panel = getCurrentFrame();
panel.setContentCallback(obj);
}
public void hideFrame(int tabIndex) {
Frame frame = ((IFrameTabPanel) getWidget(tabIndex)).getFrame();
frame.setVisible(false);
}
public boolean existingTabMatchesName(String name) {
String key = "title=\"" + name + "\""; //$NON-NLS-1$ //$NON-NLS-2$
NodeList<com.google.gwt.dom.client.Element> divs = getTabBar().getElement().getElementsByTagName("div"); //$NON-NLS-1$
for (int i = 0; i < divs.getLength(); i++) {
String tabHtml = divs.getItem(i).getInnerHTML();
// TODO: remove once a more elegant tab solution is in place
if (tabHtml.indexOf(key) > -1) {
return true;
}
}
return false;
}
public String getUniqueFrameName() {
return FRAME_ID_PRE + frameIdCount++;
}
/**
* Called by JSNI call from parameterized xaction prompt pages to "cancel". The only 'key' to pass up is the URL. To handle the possibility of multiple tabs
* with the same url, this method first checks the assumption that the current active tab initiates the call. Otherwise it checks from tail up for the first
* tab with a matching url and closes that one. *
*
* @param url
*/
@SuppressWarnings("unused")
private void closeTab(String url) {
int curpos = getTabBar().getSelectedTab();
if (StringUtils.isEmpty(url)) {
// if the url was not provided, simply remove the currently selected tab and then remove
if (curpos >= 0 && getWidgetCount() > 0) {
remove(curpos);
}
if (getWidgetCount() == 0) {
allTabsClosed();
}
return;
}
IFrameTabPanel curPanel = (IFrameTabPanel) getWidget(curpos);
if (url.contains(curPanel.getUrl())) {
remove(curpos);
if (getWidgetCount() == 0) {
allTabsClosed();
}
return;
}
for (int i = getWidgetCount() - 1; i >= 0; i--) {
curPanel = (IFrameTabPanel) getWidget(i);
if (url.contains(curPanel.getUrl())) {
remove(i);
if (getWidgetCount() == 0) {
allTabsClosed();
}
return;
}
}
}
private native boolean isPDF(com.google.gwt.dom.client.Element frame)
/*-{
return (frame.contentDocument != null && frame.contentDocument.getElementsByTagName('embed').length > 0);
}-*/;
public void refreshIfPDF() {
// There's a bug when re-showing a tab containing a PDF. Under Firefox it doesn't render, so we force a reload
int selectedTab = getTabBar().getSelectedTab();
if (selectedTab > -1) {
final Widget tabContent = getWidget(selectedTab);
if (tabContent instanceof IFrameTabPanel) {
Timer t = new Timer() {
public void run() {
IFrameTabPanel frame = ((IFrameTabPanel) tabContent);
if (isPDF(frame.getFrame().getElement())) {
frame.reload();
}
}
};
t.schedule(250);
}
}
}
/**
* This method will check if the given frame(by id) is jpivot.
*
* @param elementId
*/
public static native boolean isPivot(String elementId)
/*-{
var frame = $doc.getElementById(elementId);
if (!frame) {
return false;
}
frame = frame.contentWindow;
return true == frame.pivot_initialized;
}-*/;
/**
* Store representation of file in the frame for reference later when save is called
*
* @param selectedFileItem
*/
public void setFileInfoInFrame(FileItem selectedFileItem) {
IFrameTabPanel tp = getCurrentFrame();
if (tp != null && selectedFileItem != null) {
SolutionFileInfo fileInfo = new SolutionFileInfo();
fileInfo.setName(selectedFileItem.getName());
fileInfo.setSolution(selectedFileItem.getSolution());
fileInfo.setPath(selectedFileItem.getPath());
tp.setFileInfo(fileInfo);
}
}
public void allTabsClosed() {
// show the "launch" panel
SolutionBrowserPerspective.getInstance().showContent();
SolutionBrowserPerspective.getInstance().fireSolutionBrowserListenerEvent(SolutionBrowserListener.EventType.CLOSE, CURRENT_SELECTED_TAB);
}
}