/*!
* 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.reporting.designer.core;
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.KeyboardFocusManager;
import java.awt.Toolkit;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragSource;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetAdapter;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.IndexedPropertyChangeEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.TabbedPaneUI;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeModel;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.designer.core.actions.elements.InsertElementAction;
import org.pentaho.reporting.designer.core.actions.elements.MorphAction;
import org.pentaho.reporting.designer.core.actions.elements.barcode.BarcodeTypeAction;
import org.pentaho.reporting.designer.core.actions.global.AboutAction;
import org.pentaho.reporting.designer.core.actions.global.OpenReportAction;
import org.pentaho.reporting.designer.core.actions.global.OpenSampleReportAction;
import org.pentaho.reporting.designer.core.actions.global.QuitAction;
import org.pentaho.reporting.designer.core.actions.global.SelectTabAction;
import org.pentaho.reporting.designer.core.actions.global.SettingsAction;
import org.pentaho.reporting.designer.core.actions.report.CloseAllReportsAction;
import org.pentaho.reporting.designer.core.actions.report.CloseChildReportsAction;
import org.pentaho.reporting.designer.core.actions.report.CloseOtherReportsAction;
import org.pentaho.reporting.designer.core.actions.report.CloseReportAction;
import org.pentaho.reporting.designer.core.actions.report.CloseUnmodifiedReportsAction;
import org.pentaho.reporting.designer.core.editor.ContextMenuUtility;
import org.pentaho.reporting.designer.core.editor.ElementPropertiesPanel;
import org.pentaho.reporting.designer.core.editor.ReportDocumentContext;
import org.pentaho.reporting.designer.core.editor.ReportRenderContext;
import org.pentaho.reporting.designer.core.editor.ReportRendererComponent;
import org.pentaho.reporting.designer.core.editor.fieldselector.FieldSelectorPaletteDialog;
import org.pentaho.reporting.designer.core.editor.palette.PaletteButton;
import org.pentaho.reporting.designer.core.frame.RecentFilesUpdateHandler;
import org.pentaho.reporting.designer.core.inspections.InspectionSidePanePanel;
import org.pentaho.reporting.designer.core.settings.WorkspaceSettings;
import org.pentaho.reporting.designer.core.status.StatusBar;
import org.pentaho.reporting.designer.core.util.IconLoader;
import org.pentaho.reporting.designer.core.util.docking.Category;
import org.pentaho.reporting.designer.core.util.docking.GlobalPane;
import org.pentaho.reporting.designer.core.util.docking.InternalWindow;
import org.pentaho.reporting.designer.core.util.exceptions.UncaughtExceptionsModel;
import org.pentaho.reporting.designer.core.welcome.SamplesTreeBuilder;
import org.pentaho.reporting.designer.core.welcome.WelcomePane;
import org.pentaho.reporting.designer.core.widgets.FancyTabbedPane;
import org.pentaho.reporting.designer.core.widgets.TabRenderer;
import org.pentaho.reporting.designer.core.xul.ActionSwingMenuitem;
import org.pentaho.reporting.designer.core.xul.XulDesignerFrame;
import org.pentaho.reporting.engine.classic.core.metadata.ElementMetaData;
import org.pentaho.reporting.engine.classic.core.metadata.ElementTypeRegistry;
import org.pentaho.reporting.engine.classic.core.metadata.GroupedMetaDataComparator;
import org.pentaho.reporting.engine.classic.extensions.modules.sbarcodes.BarcodeTypePropertyEditor;
import org.pentaho.reporting.libraries.base.util.DebugLog;
import org.pentaho.reporting.libraries.base.util.ObjectUtilities;
import org.pentaho.reporting.libraries.base.util.StringUtils;
import org.pentaho.reporting.libraries.designtime.swing.MacOSXIntegration;
import org.pentaho.ui.xul.XulComponent;
import org.pentaho.ui.xul.XulException;
import org.pentaho.ui.xul.components.XulMenuitem;
import org.pentaho.ui.xul.containers.XulMenupopup;
import org.pentaho.ui.xul.swing.tags.SwingMenuseparator;
public class ReportDesignerFrame extends JFrame
{
/**
* Class for handling cursor changes during drags
* See PRD-1674
*/
public class DefaultDropTargetListener extends DropTargetAdapter
{
public void dragEnter(final DropTargetDragEvent dtde)
{
final DropTarget dropTarget = (DropTarget) dtde.getSource();
dropTarget.getComponent().setCursor(DragSource.DefaultCopyNoDrop);
}
public void dragExit(final DropTargetEvent dte)
{
final DropTarget dropTarget = (DropTarget) dte.getSource();
dropTarget.getComponent().setCursor(Cursor.getDefaultCursor());
}
public void drop(final DropTargetDropEvent dtde)
{
final DropTarget dropTarget = (DropTarget) dtde.getSource();
dropTarget.getComponent().setCursor(Cursor.getDefaultCursor());
dtde.rejectDrop();
}
}
private static class ScrollbarSyncHandler extends ComponentAdapter
{
private final JScrollBar theVerticalScrollBar;
private final JToolBar toolBar;
public ScrollbarSyncHandler(final JScrollBar theVerticalScrollBar, final JToolBar toolBar)
{
this.theVerticalScrollBar = theVerticalScrollBar;
this.toolBar = toolBar;
}
public void componentResized(final ComponentEvent e)
{
if (theVerticalScrollBar.isShowing())
{
toolBar.setBorder(BorderFactory.createEmptyBorder(25, 0, 0, 19));
}
else
{
toolBar.setBorder(BorderFactory.createEmptyBorder(25, 0, 0, 4));
}
}
}
private class WindowCloseHandler extends WindowAdapter
{
private WindowCloseHandler()
{
}
/**
* Invoked when a window is in the process of being closed. The close operation can be overridden at this point.
*/
public void windowClosing(final WindowEvent e)
{
final QuitAction quitAction = new QuitAction();
quitAction.setReportDesignerContext(context);
quitAction.actionPerformed(new ActionEvent(this, 0, "quit", 0)); // NON-NLS
}
}
private class ReportTabActivationHandler implements ChangeListener, PropertyChangeListener
{
private ReportTabActivationHandler()
{
}
public void propertyChange(final PropertyChangeEvent evt)
{
final ReportDesignerDocumentContext activeContext = getContext().getActiveDocument();
final JTabbedPane editorPanes = getReportEditorPane();
final int i = findTabForContext(activeContext);
if (i != -1 && editorPanes.getSelectedIndex() != i)
{
editorPanes.setSelectedIndex(i);
}
updateFrameTitle();
}
private int findTabForContext(final ReportDesignerDocumentContext activeContext)
{
final JTabbedPane editorPanes = getReportEditorPane();
final int count = editorPanes.getTabCount();
for (int i = 0; i < count; i++)
{
final Component c = editorPanes.getComponentAt(i);
if (c instanceof ReportRendererComponent)
{
final ReportRendererComponent rrc = (ReportRendererComponent) c;
if (rrc.getRenderContext() == activeContext)
{
return i;
}
}
}
return -1;
}
/**
* Invoked when the target of the listener has changed its state.
*
* @param e a ChangeEvent object
*/
public void stateChanged(final ChangeEvent e)
{
final JTabbedPane editorPanes = getReportEditorPane();
final DefaultReportDesignerContext context = getContext();
if (editorPanes.getTabCount() == 0)
{
context.setActiveDocument(null);
return;
}
final int index = editorPanes.getSelectedIndex();
if (index == -1 || editorPanes.getComponentAt(index) instanceof ReportRendererComponent == false)
{
context.setActiveDocument(null);
}
else
{
// try to sync the context.
final ReportRendererComponent rendererComponent = (ReportRendererComponent) editorPanes.getComponentAt(index);
final ReportDocumentContext rendererContext = rendererComponent.getRenderContext();
for (int i = 0; i < context.getReportRenderContextCount(); i++)
{
final ReportRenderContext context1 = context.getReportRenderContext(i);
if (context1 == rendererContext)
{
context.setActiveDocument(rendererContext);
rendererContext.onDocumentActivated();
return;
}
}
if (context.getReportRenderContextCount() > 0)
{
// we couldn't find a context, but we do at least have a context
// instead of blowing away the context, let's grab one and
// attempt to use it
// this works around PRD-1609
context.setActiveDocument(context.getReportRenderContext(context.getReportRenderContextCount() - 1));
}
else
{
// not found, so we are probably in a remove at the moment.
context.setActiveDocument(null);
}
}
}
}
private class StatusTextHandler implements PropertyChangeListener
{
private StatusTextHandler()
{
}
/**
* This method gets called when a bound property is changed.
*
* @param evt A PropertyChangeEvent object describing the event source and the property that has changed.
*/
public void propertyChange(final PropertyChangeEvent evt)
{
getStatusBar().setGeneralInfoText(getContext().getStatusText());
}
}
private class ReportEditorContextHandler implements PropertyChangeListener
{
private ReportEditorContextHandler()
{
}
/**
* This method gets called when a bound property is changed.
*
* @param evt A PropertyChangeEvent object describing the event source and the property that has changed.
*/
public void propertyChange(final PropertyChangeEvent evt)
{
if (ReportDesignerContext.REPORT_RENDER_CONTEXT_PROPERTY.equals(evt.getPropertyName()) == false)
{
return;
}
if (!(evt instanceof IndexedPropertyChangeEvent))
{
throw new UnsupportedOperationException();
}
final JTabbedPane editorPanes = getReportEditorPane();
final IndexedPropertyChangeEvent ievt = (IndexedPropertyChangeEvent) evt;
if (ievt.getNewValue() != null)
{
// added
final ReportRenderContext renderContext = (ReportRenderContext) ievt.getNewValue();
DefaultReportDesignerContext reportDesignerContext = getContext();
final ReportRendererComponent rendererComponent = new ReportRendererComponent(reportDesignerContext, renderContext);
final String title = renderContext.getTabName();
final Icon icon = renderContext.getIcon();
final TabRenderer tabRenderer = new TabRenderer(icon, title, reportDesignerContext, editorPanes);
editorPanes.addTab(title, null, rendererComponent);
editorPanes.setTabComponentAt(editorPanes.getTabCount() - 1, tabRenderer);
editorPanes.setSelectedComponent(rendererComponent);
renderContext.addPropertyChangeListener("tabName",
new DocumentNameChangeHandler(renderContext, tabRenderer, editorPanes.getTabCount() - 1));
}
else if (ievt.getOldValue() != null)
{
if (editorPanes.getTabCount() <= 0)
{
return;
}
// removed
int index = ievt.getIndex();
final ReportRenderContext reportRenderContext = (ReportRenderContext) ievt.getOldValue();
boolean removedTab = false;
for (int i = 0; i < editorPanes.getTabCount(); i++)
{
final Component tabContent = editorPanes.getComponentAt(i);
if (tabContent instanceof ReportRendererComponent)
{
final ReportRendererComponent myReportRenderer = (ReportRendererComponent) tabContent;
if (myReportRenderer.getRenderContext() == reportRenderContext)
{
index = i;
editorPanes.removeTabAt(index);
removedTab = true;
myReportRenderer.dispose();
break;
}
}
}
// if we didn't remove a tab, the tab was probably not a report, so remove it by index
if (!removedTab)
{
editorPanes.removeTabAt(index);
}
// unregister the listeners ...
if (editorPanes.getTabCount() > 0)
{
if (index < editorPanes.getTabCount())
{
editorPanes.setSelectedIndex(index);
}
else
{
editorPanes.setSelectedIndex(editorPanes.getTabCount() - 1);
}
}
}
recomputeAllTabTitles();
rebuildReportMenu();
}
}
private class ReportTabPanePopupHandler extends MouseAdapter
{
private ReportTabPanePopupHandler()
{
}
private void handlePopup(final MouseEvent e)
{
final JTabbedPane reportEditorPane = getReportEditorPane();
final TabbedPaneUI ui = reportEditorPane.getUI();
final int tabIndex = ui.tabForCoordinate(reportEditorPane, e.getX(), e.getY());
final JPopupMenu popupMenu = new JPopupMenu();
final CloseReportAction closeThisAction = new CloseReportAction(tabIndex);
closeThisAction.setReportDesignerContext(getContext());
final CloseChildReportsAction closeChildsAction = new CloseChildReportsAction(tabIndex);
closeChildsAction.setReportDesignerContext(getContext());
final CloseOtherReportsAction closeOthersAction = new CloseOtherReportsAction(tabIndex);
closeOthersAction.setReportDesignerContext(getContext());
final CloseAllReportsAction closeAllAction = new CloseAllReportsAction();
closeAllAction.setReportDesignerContext(getContext());
final CloseUnmodifiedReportsAction closeUnmodifiedReportsAction = new CloseUnmodifiedReportsAction();
closeUnmodifiedReportsAction.setReportDesignerContext(getContext());
popupMenu.add(new JMenuItem(closeThisAction));
popupMenu.addSeparator();
popupMenu.add(new JMenuItem(closeChildsAction));
popupMenu.add(new JMenuItem(closeUnmodifiedReportsAction));
popupMenu.add(new JMenuItem(closeOthersAction));
popupMenu.add(new JMenuItem(closeAllAction));
popupMenu.show(reportEditorPane, e.getX(), e.getY());
}
public void mouseClicked(final MouseEvent e)
{
if (e.isPopupTrigger())
{
handlePopup(e);
}
}
public void mousePressed(final MouseEvent e)
{
if (e.isPopupTrigger())
{
handlePopup(e);
}
}
public void mouseReleased(final MouseEvent e)
{
if (e.isPopupTrigger())
{
handlePopup(e);
}
}
}
private class FrameViewController implements ReportDesignerView
{
private PropertyChangeSupport propertyChangeSupport;
private XulDesignerFrame xulDesignerFrame;
private Component parent;
private FrameViewController(final Component parent)
{
this.propertyChangeSupport = new PropertyChangeSupport(this);
this.parent = parent;
}
private void initializeXulDesignerFrame(final ReportDesignerContext context) throws XulException
{
this.xulDesignerFrame = new XulDesignerFrame();
this.xulDesignerFrame.setReportDesignerContext(context);
}
public void addPropertyChangeListener(final PropertyChangeListener listener)
{
propertyChangeSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(final PropertyChangeListener listener)
{
propertyChangeSupport.removePropertyChangeListener(listener);
}
public void addPropertyChangeListener(final String propertyName, final PropertyChangeListener listener)
{
propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
}
public void removePropertyChangeListener(final String propertyName, final PropertyChangeListener listener)
{
propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
}
public boolean isStructureVisible()
{
final Category reportTreeToolWindow = getReportTreeToolWindow();
return reportTreeToolWindow != null && reportTreeToolWindow.isMinimized() == false;
}
public void setStructureVisible(final boolean visible)
{
final Category reportTreeToolWindow = getReportTreeToolWindow();
final boolean oldValue = reportTreeToolWindow.isMinimized() == false;
reportTreeToolWindow.setMinimized(visible == false);
propertyChangeSupport.firePropertyChange(STRUCTURE_VISIBLE_PROPERTY, oldValue, visible);
}
public boolean isPropertiesEditorVisible()
{
final Category attributeToolWindow = getAttributeToolWindow();
if (attributeToolWindow == null)
{
return false;
}
return attributeToolWindow.isMinimized() == false;
}
public void setPropertiesEditorVisible(final boolean visible)
{
final Category attributeToolWindow = getAttributeToolWindow();
final boolean oldValue = attributeToolWindow.isMinimized() == false;
attributeToolWindow.setMinimized(visible == false);
propertyChangeSupport.firePropertyChange(PROPERTIES_EDITOR_VISIBLE_PROPERTY, oldValue, visible);
}
public boolean isMessagesVisible()
{
final Category inspectionsToolWindow = getInspectionsToolWindow();
return inspectionsToolWindow != null && !inspectionsToolWindow.isMinimized();
}
public void setMessagesVisible(final boolean visible)
{
final Category inspectionsToolWindow = getInspectionsToolWindow();
final boolean oldValue = inspectionsToolWindow.isMinimized() == false;
inspectionsToolWindow.setMinimized(visible == false);
propertyChangeSupport.firePropertyChange(MESSAGES_VISIBLE_PROPERTY, oldValue, visible);
}
public boolean isPreviewVisible()
{
final JTabbedPane reportEditorPane = getReportEditorPane();
if (reportEditorPane == null || reportEditorPane.getTabCount() == 0)
{
return false;
}
if (reportEditorPane.getSelectedComponent() instanceof ReportRendererComponent)
{
final ReportRendererComponent rendererComponent = (ReportRendererComponent) reportEditorPane.getSelectedComponent();
return !rendererComponent.isDesignVisible();
}
return false;
}
public void setPreviewVisible(final boolean visible)
{
final boolean oldValue = isPreviewVisible();
final JTabbedPane reportEditorPane = getReportEditorPane();
if (reportEditorPane != null && reportEditorPane.getTabCount() > 0)
{
if (reportEditorPane.getSelectedComponent() instanceof ReportRendererComponent)
{
final ReportRendererComponent rendererComponent = (ReportRendererComponent) reportEditorPane.getSelectedComponent();
if (visible)
{
rendererComponent.showPreview();
}
else
{
rendererComponent.showDesign();
}
}
}
propertyChangeSupport.firePropertyChange(PREVIEW_VISIBLE_PROPERTY, oldValue, visible);
}
public boolean isWelcomeVisible()
{
if (welcomePane == null)
{
return false;
}
return welcomePane.isVisible();
}
public void setWelcomeVisible(final boolean visible)
{
if (welcomePane == null)
{
return;
}
welcomePane.setVisible(visible);
welcomePane.toFront();
}
public boolean isFieldSelectorVisible()
{
if (fieldSelectorPaletteDialog == null)
{
return false;
}
return fieldSelectorPaletteDialog.isVisible();
}
public void setFieldSelectorVisible(final boolean visible)
{
if (fieldSelectorPaletteDialog == null)
{
return;
}
fieldSelectorPaletteDialog.setVisible(visible);
fieldSelectorPaletteDialog.toFront();
}
public void redrawAll()
{
getReportEditorPane().invalidate();
getReportEditorPane().revalidate();
getReportEditorPane().repaint();
}
public void showDataTree()
{
treePanel.refreshTabPanel(getAttributeEditorPanel());
treePanel.showDataTab();
}
public JPopupMenu getPopupMenu(final String id)
{
return xulDesignerFrame.getComponent(id, JPopupMenu.class);
}
public JComponent getToolBar(final String id)
{
JComponent toolBar = xulDesignerFrame.getComponent(id, JComponent.class);
if (toolBar instanceof JToolBar)
{
final JToolBar realToolBar = (JToolBar) toolBar;
realToolBar.setFloatable(false);
}
return toolBar;
}
public Component getParent()
{
return parent;
}
public <T extends JComponent> T getComponent(final String id, final Class<T> type)
{
T xulComponentById = xulDesignerFrame.getComponent(id, type);
if (type.isInstance(xulComponentById))
{
return (T) xulComponentById;
}
return null;
}
public <T extends XulComponent> T getXulComponent(final String id, final Class<T> type)
{
T xulComponentById = xulDesignerFrame.getXulComponent(id, type);
if (type.isInstance(xulComponentById))
{
return (T) xulComponentById;
}
return null;
}
public ActionSwingMenuitem createMenuItem(final Action action)
{
return xulDesignerFrame.createMenu(action);
}
public XulMenupopup createPopupMenu(final String label, final XulComponent parent) throws XulException
{
return xulDesignerFrame.createPopupMenu(label, parent);
}
}
private class ShowWelcomeScreenTask implements Runnable
{
public void run()
{
viewController.setWelcomeVisible(WorkspaceSettings.getInstance().isShowLauncher());
}
}
private class DragSelectionToggleHandler implements AWTEventListener
{
private DragSelectionToggleHandler()
{
}
/**
* Invoked when an event is dispatched in the AWT.
*/
public void eventDispatched(final AWTEvent event)
{
if (event instanceof KeyEvent == false)
{
return;
}
final KeyEvent keyevent = (KeyEvent) event;
if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow() ==
ReportDesignerFrame.this)
{
context.setSelectionWaiting(keyevent.isShiftDown());
}
}
}
private class PageTextHandler implements PropertyChangeListener
{
/**
* This method gets called when a bound property is changed.
*
* @param evt A PropertyChangeEvent object describing the event source
* and the property that has changed.
*/
public void propertyChange(final PropertyChangeEvent evt)
{
statusBar.setPages(context.getPage(), context.getPageTotal());
}
}
private class DocumentNameChangeHandler implements PropertyChangeListener
{
private ReportDesignerDocumentContext documentContext;
private TabRenderer tabRenderer;
private int tabIndex;
private DocumentNameChangeHandler(final ReportDesignerDocumentContext documentContext,
final TabRenderer tabRenderer,
final int tabIndex)
{
this.documentContext = documentContext;
this.tabRenderer = tabRenderer;
this.tabIndex = tabIndex;
}
public void propertyChange(final PropertyChangeEvent evt)
{
String tabName = documentContext.getTabName();
tabRenderer.setRawTabName(tabName);
getReportEditorPane().setTitleAt(tabIndex, tabName);
recomputeAllTabTitles();
rebuildReportMenu();
}
}
private static final Log logger = LogFactory.getLog(ReportDesignerFrame.class);
private JTabbedPane reportEditorPane;
private GlobalPane dockingPane;
private StatusBar statusBar;
private DefaultReportDesignerContext context;
private Category attributeToolWindow;
private Category reportTreeToolWindow;
private Category inspectionsToolWindow;
private FrameViewController viewController;
private ElementPropertiesPanel attributeEditorPanel;
private WelcomePane welcomePane;
private FieldSelectorPaletteDialog fieldSelectorPaletteDialog;
private TreeSidePanel treePanel;
public ReportDesignerFrame() throws XulException
{
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
final ImageIcon icon = IconLoader.getInstance().getProductIcon();
if (icon != null)
{
setIconImage(icon.getImage());
}
setTitle(Messages.getString("ReportDesignerFrame.Title"));
addWindowListener(new WindowCloseHandler());
viewController = new FrameViewController(this);
context = new DefaultReportDesignerContext(viewController);
viewController.initializeXulDesignerFrame(context);
welcomePane = new WelcomePane(ReportDesignerFrame.this, getContext());
fieldSelectorPaletteDialog = new FieldSelectorPaletteDialog(ReportDesignerFrame.this, getContext());
statusBar = new StatusBar(context);
reportEditorPane = new FancyTabbedPane();
reportEditorPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
reportEditorPane.getModel().addChangeListener(new ReportTabActivationHandler());
reportEditorPane.addMouseListener(new ReportTabPanePopupHandler());
dockingPane = new GlobalPane(false);
dockingPane.setMainComponent(reportEditorPane);
attributeEditorPanel = new ElementPropertiesPanel();
attributeEditorPanel.setAllowAttributeCard(true);
attributeEditorPanel.setReportDesignerContext(context);
treePanel = new TreeSidePanel(context, attributeEditorPanel);
initializeToolWindows();
final JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout());
contentPane.add(context.getToolBar("main-toolbar"), BorderLayout.NORTH); // NON-NLS
contentPane.add(dockingPane, BorderLayout.CENTER);
contentPane.add(statusBar, BorderLayout.SOUTH);
contentPane.add(createPaletteToolBar(), BorderLayout.WEST);
setContentPane(contentPane);
setJMenuBar(createMenuBar());
setDropTarget(new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, new DefaultDropTargetListener()));
context.addPropertyChangeListener(ReportDesignerContext.ACTIVE_CONTEXT_PROPERTY, new ReportTabActivationHandler());
context.addPropertyChangeListener(ReportDesignerContext.STATUS_TEXT_PROPERTY, new StatusTextHandler());
context.addPropertyChangeListener(ReportDesignerContext.PAGE_PROPERTY, new PageTextHandler());
context.addPropertyChangeListener(ReportDesignerContext.REPORT_RENDER_CONTEXT_PROPERTY, new ReportEditorContextHandler());
Toolkit.getDefaultToolkit().addAWTEventListener(new DragSelectionToggleHandler(), AWTEvent.KEY_EVENT_MASK);
if (MacOSXIntegration.MAC_OS_X)
{
try
{
final AboutAction aboutAction = new AboutAction();
aboutAction.setReportDesignerContext(context);
final SettingsAction settingsAction = new SettingsAction();
settingsAction.setReportDesignerContext(context);
final QuitAction quitAction = new QuitAction();
quitAction.setReportDesignerContext(context);
final OpenReportAction openReportAction = new OpenReportAction();
openReportAction.setReportDesignerContext(context);
MacOSXIntegration.setOpenFileAction(openReportAction);
MacOSXIntegration.setAboutAction(aboutAction);
MacOSXIntegration.setPreferencesAction(settingsAction);
MacOSXIntegration.setQuitAction(quitAction);
}
catch (Throwable e)
{
DebugLog.log("Failed to activate MacOS-X integration", e); // NON-NLS
}
}
}
public void initWindowLocations(final File[] filesToOpen)
{
fieldSelectorPaletteDialog.initWindowLocation();
viewController.setFieldSelectorVisible(WorkspaceSettings.getInstance().isFieldSelectorVisible());
welcomePane.setLocationRelativeTo(ReportDesignerFrame.this);
if (filesToOpen == null || filesToOpen.length == 0)
{
if (WorkspaceSettings.getInstance().isReopenLastReport())
{
final File[] recentFiles = context.getRecentFilesModel().getRecentFiles();
if (recentFiles.length > 0)
{
SwingUtilities.invokeLater(new OpenReportAction.OpenReportTask(recentFiles[0], context));
return;
}
}
/*
* PRD-1676: Since the report designer frame will steal the focus from the Welcome dialog
* we must let the report designer frame finish it's initialization before we try to display
* the welcome panel.
*/
SwingUtilities.invokeLater(new ShowWelcomeScreenTask());
}
else
{
for (int i = 0; i < filesToOpen.length; i++)
{
final File file = filesToOpen[i];
SwingUtilities.invokeLater(new OpenReportAction.OpenReportTask(file, context));
}
}
}
protected Category getAttributeToolWindow()
{
return attributeToolWindow;
}
protected Category getReportTreeToolWindow()
{
return reportTreeToolWindow;
}
protected Category getInspectionsToolWindow()
{
return inspectionsToolWindow;
}
protected ElementPropertiesPanel getAttributeEditorPanel()
{
return attributeEditorPanel;
}
protected JTabbedPane getReportEditorPane()
{
return reportEditorPane;
}
protected DefaultReportDesignerContext getContext()
{
return context;
}
protected StatusBar getStatusBar()
{
return statusBar;
}
private JMenuBar createMenuBar()
{
createRecentFilesMenu();
createZoomMenu();
createMorphMenu();
createInsertElementsMenu();
createInsertDataSourcesMenu();
createSamplesMenu();
return context.getView().getComponent("main-menubar", JMenuBar.class);
}
private void createInsertDataSourcesMenu()
{
final JMenu insertDataSourcesMenu = context.getView().getComponent("insert-datasources-menu", JMenu.class);// NON-NLS
if (insertDataSourcesMenu != null)
{
ContextMenuUtility.createDataSourceMenu(context, insertDataSourcesMenu);
}
}
private void createInsertElementsMenu()
{
final XulMenupopup insertElementsMenu = context.getView().getXulComponent("insert-elements-popup", XulMenupopup.class);// NON-NLS
if (insertElementsMenu != null)
{
final ElementMetaData[] datas = ElementTypeRegistry.getInstance().getAllElementTypes();
Arrays.sort(datas, new GroupedMetaDataComparator());
Object grouping = null;
boolean firstElement = true;
for (int i = 0; i < datas.length; i++)
{
final ElementMetaData data = datas[i];
if (data.isHidden())
{
continue;
}
final String currentGrouping = data.getGrouping(Locale.getDefault());
if (firstElement == false)
{
if (ObjectUtilities.equal(currentGrouping, grouping) == false)
{
grouping = currentGrouping;
SwingMenuseparator separator = new SwingMenuseparator(null, null, null, "menuseparator");
insertElementsMenu.addChild(separator);
}
}
else
{
grouping = currentGrouping;
firstElement = false;
}
final InsertElementAction action = new InsertElementAction(data);
action.setReportDesignerContext(context);
ActionSwingMenuitem menuItem = new ActionSwingMenuitem(ActionSwingMenuitem.MENUITEM);
menuItem.setAction(action);
insertElementsMenu.addChild(menuItem);
}
}
}
private void createRecentFilesMenu()
{
final XulMenupopup reopenMenu = context.getView().getXulComponent("file-reopen-popup", XulMenupopup.class); // NON-NLS
final XulMenuitem clearMenuitem = context.getView().getXulComponent("file-clear-recent", XulMenuitem.class);// NON-NLS
if (reopenMenu != null && clearMenuitem != null)
{
final RecentFilesUpdateHandler updateHandler = new RecentFilesUpdateHandler(context, reopenMenu, clearMenuitem);
updateHandler.settingsChanged();
context.getRecentFilesModel().addSettingsListener(updateHandler);
}
}
private void createZoomMenu()
{
final XulComponent zoomMenu = context.getView().getXulComponent("view-zoom-selection-popup", XulMenupopup.class);// NON-NLS
if (zoomMenu == null)
{
return;
}
final InternalZoomAction zoom50action = new InternalZoomAction(50);
final InternalZoomAction zoom100action = new InternalZoomAction(100);
final InternalZoomAction zoom200action = new InternalZoomAction(200);
final InternalZoomAction zoom400action = new InternalZoomAction(400);
zoom50action.setReportDesignerContext(context);
zoom100action.setReportDesignerContext(context);
zoom200action.setReportDesignerContext(context);
zoom400action.setReportDesignerContext(context);
zoomMenu.addChild(context.getView().createMenuItem(zoom50action));
zoomMenu.addChild(context.getView().createMenuItem(zoom100action));
zoomMenu.addChild(context.getView().createMenuItem(zoom200action));
zoomMenu.addChild(context.getView().createMenuItem(zoom400action));
}
private void createSamplesMenu()
{
final XulComponent samplesopup = context.getView().getXulComponent("help-samples-popup", XulMenupopup.class);// NON-NLS
if (samplesopup == null)
{
return;
}
final XulMenupopup xulMenupopup = (XulMenupopup) samplesopup;
final TreeModel treeModel = SamplesTreeBuilder.getSampleTreeModel();
final Object root = treeModel.getRoot();
try
{
insertReports(treeModel, root, xulMenupopup);
}
catch (XulException e)
{
logger.warn("Failed to initialize sample menu", e);
}
}
private void insertReports(final TreeModel model,
final Object currentLevel,
final XulMenupopup popup) throws XulException
{
final int childCount = model.getChildCount(currentLevel);
for (int i = 0; i < childCount; i += 1)
{
final ReportDesignerView frame = context.getView();
final Object child = model.getChild(currentLevel, i);
if (model.isLeaf(child))
{
final DefaultMutableTreeNode node = (DefaultMutableTreeNode) child;
final File file = new File(String.valueOf(node.getUserObject()));
final OpenSampleReportAction action = new OpenSampleReportAction(file, node.toString());
action.setReportDesignerContext(context);
popup.addChild(frame.createMenuItem(action));
}
else
{
final XulMenupopup childPopup = frame.createPopupMenu(String.valueOf(child), popup);
insertReports(model, child, childPopup);
}
}
}
private void createMorphMenu()
{
final JMenu morphMenu = context.getView().getComponent("format-morph-menu", JMenu.class);// NON-NLS PRD-4452
if (morphMenu == null)
{
return;
}
final ElementMetaData[] datas = ElementTypeRegistry.getInstance().getAllElementTypes();
Arrays.sort(datas, new GroupedMetaDataComparator());
Object grouping = null;
boolean firstElement = true;
for (int i = 0; i < datas.length; i++)
{
final ElementMetaData data = datas[i];
if (data.isHidden())
{
continue;
}
final String currentGrouping = data.getGrouping(Locale.getDefault());
if (firstElement == false)
{
if (ObjectUtilities.equal(currentGrouping, grouping) == false)
{
grouping = currentGrouping;
morphMenu.addSeparator();
}
}
else
{
grouping = currentGrouping;
firstElement = false;
}
try
{
final MorphAction action = new MorphAction(data.create());
action.setReportDesignerContext(context);
morphMenu.add(new JMenuItem(action));
}
catch (InstantiationException e)
{
UncaughtExceptionsModel.getInstance().addException(e);
}
}
}
private void initializeToolWindows()
{
this.reportTreeToolWindow = createStructureTreeToolWindow();
this.attributeToolWindow = createAttributesToolWindow();
this.inspectionsToolWindow = createInspectionsToolWindow();
dockingPane.add(GlobalPane.Alignment.RIGHT, reportTreeToolWindow);
dockingPane.add(GlobalPane.Alignment.RIGHT, attributeToolWindow);
dockingPane.add(GlobalPane.Alignment.BOTTOM, inspectionsToolWindow);
dockingPane.setPreferredContentSize(GlobalPane.Alignment.BOTTOM, 100);
dockingPane.setPreferredContentSize(GlobalPane.Alignment.RIGHT, 300);
// initialize add elements
initAddElements("popup-Band.add-element-menu");// NON-NLS
initAddElements("popup-RootLevelBand.add-element-menu");// NON-NLS
initSetBarcodeTypeElements("popup-Barcode.type");// NON-NLS
}
private Category createAttributesToolWindow()
{
final ImageIcon propertyTableIcon = IconLoader.getInstance().getPropertyTableIcon();
return new Category(propertyTableIcon, Messages.getString("Attribute.Title"), attributeEditorPanel);// NON-NLS
}
private Category createInspectionsToolWindow()
{
// this is the bottom 'messages' panel
final InspectionSidePanePanel inspectionsMessagePanel = new InspectionSidePanePanel();
inspectionsMessagePanel.setReportDesignerContext(context);
final InternalWindow inspectionGadgetInternalWindow = new InternalWindow(Messages.getString("InspectionGadget.Title"));// NON-NLS
inspectionGadgetInternalWindow.add(inspectionsMessagePanel, BorderLayout.CENTER);
final Category category = new Category
(IconLoader.getInstance().getMessagesIcon(),
Messages.getString("Messages.Title"),// NON-NLS
inspectionGadgetInternalWindow);
category.setMinimized(true);
return category;
}
private Category createStructureTreeToolWindow()
{
return new Category(IconLoader.getInstance().getReportTreeIcon(),
Messages.getString("StructureView.Title"),// NON-NLS
treePanel);
}
private void initSetBarcodeTypeElements(final String id)
{
final JMenu menu = context.getView().getComponent(id, JMenu.class);
if (menu == null)
{
return;
}
final BarcodeTypePropertyEditor editor = new BarcodeTypePropertyEditor();
final String[] tags = editor.getTags();
for (int i = 0; i < tags.length; i++)
{
final String tag = tags[i];
final BarcodeTypeAction action = new BarcodeTypeAction(tag);
action.setReportDesignerContext(context);
menu.add(new JRadioButtonMenuItem(action));
}
}
private void initAddElements(final String id)
{
final JMenu menu = context.getView().getComponent(id, JMenu.class);
if (menu == null)
{
return;
}
final ElementMetaData[] datas = ElementTypeRegistry.getInstance().getAllElementTypes();
Arrays.sort(datas, new GroupedMetaDataComparator());
Object grouping = null;
boolean firstElement = true;
for (int i = 0; i < datas.length; i++)
{
final ElementMetaData data = datas[i];
if (data.isHidden())
{
continue;
}
if (WorkspaceSettings.getInstance().isShowExpertItems() == false && data.isExpert())
{
continue;
}
if (WorkspaceSettings.getInstance().isShowDeprecatedItems() == false && data.isDeprecated())
{
continue;
}
final String currentGrouping = data.getGrouping(Locale.getDefault());
if (firstElement == false)
{
if (ObjectUtilities.equal(currentGrouping, grouping) == false)
{
grouping = currentGrouping;
menu.addSeparator();
}
}
else
{
grouping = currentGrouping;
firstElement = false;
}
final InsertElementAction action = new InsertElementAction(data);
action.setReportDesignerContext(context);
menu.add(new JMenuItem(action));
}
}
private JComponent createPaletteToolBar()
{
final JToolBar toolBar = new JToolBar();
toolBar.setFloatable(false);
toolBar.setOrientation(JToolBar.VERTICAL);
final ElementMetaData[] datas = ElementTypeRegistry.getInstance().getAllElementTypes();
Arrays.sort(datas, new GroupedMetaDataComparator());
Object grouping = null;
boolean firstElement = true;
for (int i = 0; i < datas.length; i++)
{
final ElementMetaData data = datas[i];
if (data.isHidden())
{
continue;
}
if (WorkspaceSettings.getInstance().isShowExpertItems() == false && data.isExpert())
{
continue;
}
if (WorkspaceSettings.getInstance().isShowDeprecatedItems() == false && data.isDeprecated())
{
continue;
}
if (WorkspaceSettings.getInstance().isExperimentalFeaturesVisible() == false && data.isExperimental())
{
continue;
}
final String currentGrouping = data.getGrouping(Locale.getDefault());
if (firstElement == false)
{
if (ObjectUtilities.equal(currentGrouping, grouping) == false)
{
grouping = currentGrouping;
toolBar.addSeparator();
}
}
else
{
grouping = currentGrouping;
firstElement = false;
}
final InsertElementAction action = new InsertElementAction(data);
action.setReportDesignerContext(context);
toolBar.add(new PaletteButton(data, context));
}
final JScrollPane paletteScrollpane = new JScrollPane(toolBar);
paletteScrollpane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
paletteScrollpane.addComponentListener(new ScrollbarSyncHandler(paletteScrollpane.getVerticalScrollBar(), toolBar));
return paletteScrollpane;
}
private void rebuildReportMenu()
{
final XulComponent reopenMenu = context.getView().getXulComponent("window.reports-area", XulComponent.class);
if (reopenMenu == null)
{
return;
}
final List<XulComponent> xulComponents = reopenMenu.getChildNodes();
final XulComponent[] objects = xulComponents.toArray(new XulComponent[xulComponents.size()]);
for (int i = 0; i < objects.length; i++)
{
final XulComponent object = objects[i];
reopenMenu.removeChild(object);
}
final JTabbedPane tabbedPane = getReportEditorPane();
final int count = tabbedPane.getTabCount();
if (count > 0)
{
reopenMenu.addChild(new SwingMenuseparator(null, null, null, "menu-separator")); // NON-NLS
for (int i = 0; i < count; i++)
{
final Component at = tabbedPane.getTabComponentAt(i);
final String tabName;
if (at instanceof TabRenderer)
{
final TabRenderer renderer = (TabRenderer) at;
tabName = renderer.getTitle();
}
else
{
tabName = tabbedPane.getTitleAt(i);
}
final SelectTabAction action = new SelectTabAction(i, tabName);
final ActionSwingMenuitem actionSwingMenuitem = context.getView().createMenuItem(action);
actionSwingMenuitem.setReportDesignerContext(context);
reopenMenu.addChild(actionSwingMenuitem);
}
}
}
protected void updateFrameTitle()
{
final int i = getReportEditorPane().getSelectedIndex();
final String report;
final String reportName;
if (getContext() != null && getContext().getActiveContext() != null)
{
if (i == -1)
{
reportName = null;
}
else
{
final Component at = getReportEditorPane().getTabComponentAt(i);
if (at instanceof TabRenderer)
{
final TabRenderer renderer = (TabRenderer) at;
reportName = renderer.getTitle();
}
else
{
reportName = getReportEditorPane().getTitleAt(i);
}
}
report = getContext().getActiveContext().getDocumentFile();
}
else
{
report = null;
reportName = null;
}
setTitle(computeFrameTitle(reportName, report));
}
private String computeFrameTitle(final String tabName, final String path)
{
if (tabName == null || path == null)
{
return Messages.getString("ReportDesignerFrame.Title");// NON-NLS
}
if (StringUtils.isEmpty(path))
{
return Messages.getString("ReportDesignerFrame.TitleWithName", tabName);// NON-NLS
}
else
{
return Messages.getString("ReportDesignerFrame.TitleWithNameAndPath", tabName, path);// NON-NLS
}
}
private void recomputeAllTabTitles()
{
final JTabbedPane editorPane = getReportEditorPane();
final int count = editorPane.getTabCount();
for (int i = 0; i < count; i++)
{
final Component at = editorPane.getTabComponentAt(i);
if (at instanceof TabRenderer)
{
final TabRenderer renderer = (TabRenderer) at;
renderer.setTitle(renderer.recomputeTabName());
}
}
updateFrameTitle();
}
}