package com.opendoorlogistics.studio.appframe; import java.awt.BorderLayout; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Rectangle; import java.awt.TexturePaint; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.beans.PropertyVetoException; import java.io.File; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Random; import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JDesktopPane; import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.SwingWorker; import javax.swing.border.BevelBorder; import com.opendoorlogistics.api.app.AppDisposedListener; import com.opendoorlogistics.api.app.ODLApp; import com.opendoorlogistics.api.components.ODLComponent; import com.opendoorlogistics.codefromweb.DesktopScrollPane; import com.opendoorlogistics.codefromweb.TileInternalFrames; import com.opendoorlogistics.core.scripts.ScriptConstants; import com.opendoorlogistics.core.utils.images.ImageUtils; import com.opendoorlogistics.core.utils.strings.Strings; import com.opendoorlogistics.core.utils.ui.LayoutUtils; import com.opendoorlogistics.core.utils.ui.SwingUtils; import com.opendoorlogistics.studio.PreferencesManager; import com.opendoorlogistics.studio.controls.ODLScrollableToolbar; import com.opendoorlogistics.studio.internalframes.ODLInternalFrame; import com.opendoorlogistics.studio.internalframes.ODLInternalFrame.FramesChangedListener; import com.opendoorlogistics.studio.internalframes.ProgressFrame; import com.opendoorlogistics.studio.scripts.editor.ScriptEditor; import com.opendoorlogistics.studio.scripts.execution.ReporterFrame; import com.opendoorlogistics.studio.tables.custom.CustomTableEditorFrame; import com.opendoorlogistics.studio.tables.grid.GridFrame; import com.opendoorlogistics.studio.tables.schema.TableSchemaEditor; import com.opendoorlogistics.studio.utils.WindowState; import com.opendoorlogistics.utils.ui.Icons; /** * Appframe which implements internal frame management * @author Phil * */ public abstract class DesktopAppFrame extends AbstractAppFrame { private volatile BufferedImage background; private final DesktopScrollPane desktopScrollPane; private final ODLScrollableToolbar windowToolBar; private final HashSet<AppDisposedListener> appDisposedListeners = new HashSet<AppDisposedListener>(); private final JDesktopPane desktopPane = new JDesktopPane() { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); AppBackground.paintBackground(this, g, background); // Graphics2D g2d = (Graphics2D) g; // if (background != null) { // TexturePaint paint = new TexturePaint(background, new Rectangle(0, 0, background.getWidth(), background.getHeight())); // // if (paint != null) { // g2d.setPaint(paint); // g2d.fill(g2d.getClip()); // } // } else { // g2d.setColor(AppBackground.BACKGROUND_COLOUR); // g2d.fillRect(0, 0, (int) getSize().getWidth(), (int) getSize().getHeight()); // } // g.drawImage(image, 0, 0, this); } }; public DesktopAppFrame(){ Container con = getContentPane(); con.setLayout(new BorderLayout()); initWindowPosition(); initBackgroundImage(); desktopScrollPane = new DesktopScrollPane(desktopPane); windowToolBar = new ODLScrollableToolbar(); } @Override public BufferedImage getBackgroundImage(){ return background; } protected void initBackgroundImage() { SwingWorker<Void, Void> createBackground = new SwingWorker<Void, Void>() { @Override protected Void doInBackground() throws Exception { // background = new AppBackground().create(); AppBackground ab = new AppBackground(); ab.start(); long lastTime = System.currentTimeMillis(); int lastRendered = 0; while (ab.getNbConsecutiveFails() < 100) { ab.doStep(); long current = System.currentTimeMillis(); if (current - lastTime > 100 && lastRendered != ab.getNbRendered()) { setBackgroundImage( ImageUtils.deepCopy(ab.getImage())); lastTime = current; lastRendered = ab.getNbRendered(); } } ab.finish(); setBackgroundImage( ab.getImage()); return null; } }; createBackground.execute(); } @Override public JInternalFrame[] getInternalFrames() { return desktopPane.getAllFrames(); } /** * Based on http://www.javalobby.org/forums/thread.jspa?threadID=15690&tstart=0 */ public void cascadeWindows() { JInternalFrame[] frames = getInternalFrames(); Rectangle dBounds = desktopPane.getBounds(); int separation = 40; // make standard size which is 2/3 of available width int width = Math.max(100, 2 * dBounds.width / 3); int height = Math.max(100, 2 * dBounds.width / 3); for (int i = 0; i < frames.length; i++) { try { frames[i].setIcon(false); } catch (PropertyVetoException e) { } frames[i].setBounds(i * separation, i * separation, width, height); frames[i].toFront(); } } // Based on http://www.javalobby.org/java/forums/t15696.html public void tileWindows() { JInternalFrame[] frames = getInternalFrames(); if (frames.length == 0) { return; } TileInternalFrames.tile(desktopPane, frames); } @Override public void addInternalFrame(JInternalFrame frame, FramePlacement placement) { desktopPane.add(frame); frame.pack(); frame.setVisible(true); // if(ScriptEditor.class.isInstance(frame)){ // try { // frame.setMaximum(true); // } catch (PropertyVetoException e) { // } // } // else{ // WindowState state = PreferencesManager.getSingleton().getWindowState(frame) if (placement == FramePlacement.AUTOMATIC) { boolean placed = false; if (ODLInternalFrame.class.isInstance(frame)) { ODLInternalFrame odlFrame = (ODLInternalFrame) frame; placed = odlFrame.placeInLastPosition(desktopScrollPane.getViewport().getBounds()); } if (!placed) { LayoutUtils.placeInternalFrame(desktopPane, frame); } } else if (placement == FramePlacement.CENTRAL) { Dimension desktopSize = desktopPane.getSize(); Dimension frameSize = frame.getSize(); int x = (desktopSize.width - frameSize.width) / 2; int y = (desktopSize.height - frameSize.height) / 2; frame.setLocation(x, y); } else if (placement == FramePlacement.CENTRAL_RANDOMISED) { Dimension desktopSize = desktopPane.getSize(); Dimension frameSize = frame.getSize(); Dimension remaining = new Dimension(Math.max(0, desktopSize.width - frameSize.width), Math.max(0, desktopSize.height - frameSize.height)); Dimension halfRemaining = new Dimension(remaining.width / 2, remaining.height / 2); Random random = new Random(); int x = remaining.width / 4 + (halfRemaining.width>0 ?random.nextInt(halfRemaining.width):0); int y = remaining.height / 4 + (halfRemaining.height>0?random.nextInt(halfRemaining.height):0); frame.setLocation(x, y); } if(ODLInternalFrame.class.isInstance(frame)){ ODLInternalFrame odlf = (ODLInternalFrame)frame; odlf.setChangedListener(new FramesChangedListener() { @Override public void internalFrameChange(ODLInternalFrame f) { updateWindowsToolbar(); } }); } frame.toFront(); updateWindowsToolbar(); } protected void updateWindowsToolbar(){ windowToolBar.getToolBar().removeAll(); // get all internal frames, adding progress frames first List<ODLInternalFrame> frames =new ArrayList<ODLInternalFrame>(); boolean hasProgress=false; for(JInternalFrame frame : getInternalFrames()){ if(ODLInternalFrame.class.isInstance(frame)){ if(ProgressFrame.class.isInstance(frame)){ frames.add(0,(ODLInternalFrame)frame); hasProgress = true; }else{ frames.add((ODLInternalFrame)frame); } } } for (final ODLInternalFrame frame : frames) { // get the title String title = frame.getTitle(); if(ScriptEditor.class.isInstance(frame)){ File file = ((ScriptEditor)frame).getFile(); if(file!=null){ title = file.getName(); title = Strings.caseInsensitiveReplace(title,"."+ ScriptConstants.FILE_EXT, ""); } } if(title!=null){ int maxchar = 20; if(title.length()>maxchar){ title = title.substring(0, maxchar) + "..."; } } // get an icon if we can Icon icon = null; if(ReporterFrame.class.isInstance(frame)){ ReporterFrame<?> rf = (ReporterFrame<?>)frame; if(rf.getComponent()!=null){ icon = rf.getComponent().getIcon(getApi(), ODLComponent.MODE_DEFAULT); } } else if(GridFrame.class.isInstance(frame)||CustomTableEditorFrame.class.isInstance(frame)){ icon = Icons.loadFromStandardPath("table-window-toolbar-icon.png"); } else if(TableSchemaEditor.class.isInstance(frame)){ icon = Icons.loadFromStandardPath("table-edit.png"); } else if (ScriptEditor.class.isInstance(frame)){ icon = Icons.loadFromStandardPath("script-window-toolbar.png"); }else if (ProgressFrame.class.isInstance(frame)){ icon = ProgressFrame.ANIMATED_ICON; } // create the button JButton button =null; if(icon!=null){ button = new JButton(title, icon); }else{ button = new JButton(title); } button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if(frame.isIcon()){ try { frame.setIcon(false); } catch (PropertyVetoException e1) { } } frame.toFront(); } }); button.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createSoftBevelBorder(BevelBorder.RAISED), BorderFactory.createEmptyBorder(2, 2, 2, 2))) ; windowToolBar.getToolBar().add(button); } windowToolBar.repaint(); // need updateUI here otherwise toolbar sometimes disappears! windowToolBar.updateUI(); if(hasProgress){ // ensure progress are shown windowToolBar.setScrollViewToInitialPosition(); } } public void tileVisibleFrames(JInternalFrame [] frames){ TileInternalFrames.tile(desktopPane, frames); } protected ODLScrollableToolbar getWindowToolBar() { return windowToolBar; } protected JDesktopPane getDesktopPane() { return desktopPane; } private void initWindowPosition() { WindowState screenState = PreferencesManager.getSingleton().getScreenState(); boolean boundsSet = false; GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); if (screenState != null) { setExtendedState(screenState.getExtendedState()); int safety = 20; int screenWidth = gd.getDisplayMode().getWidth(); int screenHeight = gd.getDisplayMode().getHeight(); if (getExtendedState() == JFrame.NORMAL && screenState.getX() < (screenWidth - safety) && (screenState.getY() < screenHeight - safety && screenState.getWidth() <= screenWidth && screenState.getHeight() <= screenHeight)) { boundsSet = true; setBounds(screenState.getX(), screenState.getY(), screenState.getWidth(), screenState.getHeight()); } } // make a fraction of the screen size by default if (!boundsSet && gd != null && getExtendedState() == JFrame.NORMAL) { int screenWidth = gd.getDisplayMode().getWidth(); int screenHeight = gd.getDisplayMode().getHeight(); setSize(3 * screenWidth / 4, 3 * screenHeight / 4); } } public void closeWindows() { for (JInternalFrame frame :getInternalFrames()) { if (ScriptEditor.class.isInstance(frame)) { ((ScriptEditor) frame).disposeWithSavePrompt(); } else { frame.dispose(); } } } public void minimiseWindows() { for (JInternalFrame frame : getInternalFrames()) { try { frame.setIcon(true); } catch (PropertyVetoException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } protected void setBackgroundImage(BufferedImage img){ this.background = img; SwingUtils.invokeLaterOnEDT(new Runnable() { @Override public void run() { repaint(); } }); } public void addOnDisposedListener(AppDisposedListener listener){ appDisposedListeners.add(listener); } @Override public void dispose() { for(AppDisposedListener adl : appDisposedListeners){ adl.onAppDisposed(this); } super.dispose(); } }