Package com.agifans.picedit

Source Code of com.agifans.picedit.PicEdit

package com.agifans.picedit;

import java.awt.*;
import java.awt.event.HierarchyBoundsAdapter;
import java.awt.event.HierarchyEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyVetoException;
import java.io.File;
import java.util.*;
import java.util.Timer;
import java.util.prefs.Preferences;

import javax.swing.*;

import com.agifans.picedit.gui.PicEditDesktopManager;
import com.agifans.picedit.gui.PictureCodeList;
import com.agifans.picedit.gui.StatusBarPanel;
import com.agifans.picedit.gui.frame.PictureFrame;
import com.agifans.picedit.gui.frame.PicturePanel;
import com.agifans.picedit.gui.menu.Menu;
import com.agifans.picedit.gui.toolbar.ToolPanel;
import com.agifans.picedit.gui.toolbar.ToolPanelLocation;
import com.agifans.picedit.picture.EditStatus;
import com.agifans.picedit.picture.Picture;

/**
* The main class for the PICEDIT application.
*
* @author Lance Ewing
*/
@SuppressWarnings("serial")
public final class PicEdit extends JApplet {

    /**
     * Constant for the name of the current version of PICEDIT.
     */
    private static final String PICEDIT_NAME = "PICEDIT v1.3M6";
   
    /**
     * The most recently active picture window.
     */
    private PictureFrame activePictureFrame;
   
    /**
     * The desktop pane that the picture frames live in.
     */
    private JDesktopPane desktopPane;
   
    /**
     * The PICEDIT menu handler.
     */
    private Menu menu;
   
    /**
     * PicEdit application preferences.
     */
    private Preferences prefs;
   
    /**
     * The most recently opened or saved pictures.
     */
    private LinkedList<String> recentPictures;
   
    /**
     * The name of the most recently used directory.
     */
    private String lastUsedDirectory;
   
    /**
     * Where the tool panel currently is. Starts on the left.
     */
    private ToolPanelLocation toolPanelLocation;
   
    /**
     * The scroll pane for the currently active picture code JList.
     */
    private JScrollPane pictureCodeScrollPane;
   
    /**
     * The tool panel containing all of the picture drawing tools.
     */
    private ToolPanel toolPanel;
   
    /**
     * The status bar at the bottom of the PICEDIT screen.
     */
    private StatusBarPanel statusBarPanel;
   
    /**
     * Constructor for PicEdit.
     */
    @SuppressWarnings("unchecked")
    public PicEdit() {
        // This stops the PicEdit applet from getting default focus. Instead we want the PictureFrame to get the focus.
        this.setFocusable(false);
       
        // Load the preferences saved the last time the application was closed down.
        loadPreferences();
       
        this.activePictureFrame = new PictureFrame(this, prefs.getInt("ZOOM_FACTOR", 3), "Untitled");
        this.activePictureFrame.setLocation(20, 20);
        try {
            this.activePictureFrame.setSelected(true);
        } catch (PropertyVetoException e) {
        }
       
        // This allows us to use TAB in the application (default within Java is that it traverses between fields).
        this.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, Collections.EMPTY_SET);
        this.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, Collections.EMPTY_SET);
       
        this.getContentPane().setLayout(new BorderLayout());
       
        // Add the status bar above the picture.
        statusBarPanel = new StatusBarPanel(this);
        statusBarPanel.setPreferredSize(new Dimension(320, 20));
        this.getContentPane().add(statusBarPanel, BorderLayout.SOUTH);
       
        JPanel desktopPanel = new JPanel();
        desktopPanel.setLayout(new BorderLayout());
        desktopPanel.setFocusable(false);
       
        // Add the desktop pane that holds the picture that is being edited.
        desktopPane = new JDesktopPane();
        desktopPane.setBackground(new Color(0x4169AA));
        desktopPane.setDesktopManager(new PicEditDesktopManager(desktopPane.getDesktopManager()));
        desktopPane.add(activePictureFrame);
        desktopPane.setFocusable(false);
        desktopPane.setPreferredSize(new Dimension(700, 440));
        desktopPane.addMouseWheelListener(new MouseWheelListener() {
          public void mouseWheelMoved(MouseWheelEvent event) {
            getPictureFrame().getMouseHandler().mouseWheelMoved(event);
          }
        });
        desktopPanel.add(desktopPane, BorderLayout.CENTER);
       
        // Tool panel.
        ToolPanelLocation toolPanelLocation = getToolPanelLocation();
        toolPanel = new ToolPanel(this);
        switch (toolPanelLocation) {
            case DOCKED_LEFT:
                desktopPanel.add(toolPanel, BorderLayout.WEST);
                break;
            case DOCKED_RIGHT:
                desktopPanel.add(toolPanel, BorderLayout.EAST);
                break;
            case DOCKED_TOP:
                toolPanel.setOrientation(JToolBar.HORIZONTAL);
                desktopPanel.add(toolPanel, BorderLayout.NORTH);
                break;
            case FLOATING:
                // TODO: Not sure if this one is possible, so might need to default to WEST.
                desktopPanel.add(toolPanel, BorderLayout.NORTH);
                break;
        }
       
        JTabbedPane leftTabbedPane = new JTabbedPane();
        leftTabbedPane.setFocusable(false);
        pictureCodeScrollPane = new JScrollPane(activePictureFrame.getPictureCodeList());
        pictureCodeScrollPane.setFocusable(false);
        //leftTabbedPane.add("Pictures", pictureListScrollPane);
        leftTabbedPane.add("Commands", pictureCodeScrollPane);
       
        JSplitPane centerSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftTabbedPane, desktopPanel);
        centerSplitPane.setFocusable(false);
        centerSplitPane.setDividerLocation(175);
       
        this.getContentPane().add(centerSplitPane, BorderLayout.CENTER);
       
        // Create the menu and register the menu event listeners.
        this.menu = new Menu(this);
       
        // Start a timer to preform regular screen repaints.
        startRepaintTimer();
    }

    /**
     * Starts a timer to trigger regular screen repaints. In addition to
     * this, it also checks if the currently selected PictureFrame needs
     * to process a mouse motion event. Performing this check at the same
     * time as the screen repaint appears to be more reliable than receiving
     * mouse motion events to a registered listener for some reason, and it
     * has the added benefit of tracking the mouse when it is outside of the
     * PICEDIT window.
     */
    public void startRepaintTimer() {
        Timer timer = new Timer();
        TimerTask timerTask = new TimerTask() {
            boolean lastPictureBeingDrawn = false;
            int repaintCounter;
            int lastPicturePosition;
            int lastPictureSize;

            boolean shouldPaintOffscreenImage() {
                boolean shouldPaintOffscreenImage = false;
                EditStatus editStatus = getEditStatus();
                Picture picture = getPicture();
               
                // We return true at least every second, but there are other updates that trigger a render immediately.
                if (((editStatus.hasUnrenderedChanges()) || editStatus.isEgoTestEnabled() || !lastPictureBeingDrawn ||
                    ((lastPicturePosition != picture.getPicturePosition()) || (lastPictureSize != picture.getSize()))) &&
                      !picture.isBeingDrawn()) {
                    shouldPaintOffscreenImage = true;
                }
               
                editStatus.clearUnrenderedChanges();
                lastPicturePosition = picture.getPicturePosition();
                lastPictureSize = picture.getSize();
                return shouldPaintOffscreenImage;
            }

            public void run() {
                // Check if selected PictureFrame needs to process mouse motion.
                PictureFrame selectedPictureFrame = (PictureFrame)getDesktopPane().getSelectedFrame();
                if (selectedPictureFrame != null) {
                    selectedPictureFrame.getMouseHandler().checkForMouseMotion();
                }
               
                // The off screen parts of the picture panel rendering don't need to be refreshed as often.
                if (shouldPaintOffscreenImage()) {
                  getPictureFrame().getPicturePanel().paintOffscreenImage();
                }
               
                // Repaints the changing parts of the PICEDIT screen 20 times a second.
                getPictureFrame().repaint();
                toolPanel.repaint();
                statusBarPanel.repaint();
            }
        };
        timer.scheduleAtFixedRate(timerTask, 50, 50);
    }
   
    /**
     * Loads and applies the user preferences related to the Edit Status.
     */
    public void loadPreferences() {
        prefs = Preferences.userNodeForPackage(this.getClass());
       
        this.lastUsedDirectory = prefs.get("LAST_USED_DIRECTORY", new File(".").getAbsolutePath());
       
        this.recentPictures = new LinkedList<String>();
        this.recentPictures.add(0, prefs.get("RECENT_PICTURE_1", ""));
        this.recentPictures.add(1,prefs.get("RECENT_PICTURE_2", ""));
        this.recentPictures.add(2,prefs.get("RECENT_PICTURE_3", ""));
        this.recentPictures.add(3,prefs.get("RECENT_PICTURE_4", ""));
       
        this.toolPanelLocation = ToolPanelLocation.valueOf(prefs.get("TOOL_PANEL_LOCATION", "DOCKED_TOP"));
    }
   
    /**
     * Saves the user preferences related to the Edit Status.
     */
    public void savePreferences() {
        prefs.put("LAST_USED_DIRECTORY", this.lastUsedDirectory);
        prefs.putInt("ZOOM_FACTOR", getEditStatus().getZoomFactor());
        prefs.put("RECENT_PICTURE_1", this.recentPictures.get(0));
        prefs.put("RECENT_PICTURE_2", this.recentPictures.get(1));
        prefs.put("RECENT_PICTURE_3", this.recentPictures.get(2));
        prefs.put("RECENT_PICTURE_4", this.recentPictures.get(3));
        prefs.put("TOOL_PANEL_LOCATION", this.toolPanelLocation.name());
    }
   
    /**
     * Gets the list of recently opened pictures.
     *
     * @return The list of recently opened pictures.
     */
    public LinkedList<String> getRecentPictures() {
        return recentPictures;
    }
   
    /**
     * Updates the list of recently loaded or saved pictures.
     *
     * @param pictureFile The File to add to the list of recent pictures.
     */
    public void updateRecentPictures(File pictureFile) {
        // Rotate the recent picture name list.
        if (recentPictures.contains(pictureFile.getAbsolutePath())) {
          // If the list already contains this file, then remove it.
          recentPictures.remove(pictureFile.getAbsolutePath());
        } else {
          // Otherwise remove the last item.
          recentPictures.removeLast();
        }
       
        // The most recent is always added as the first item.
        recentPictures.add(0, pictureFile.getAbsolutePath());
    }
   
    /**
     * Gets the last used directory.
     *
     * @return The last used directory.
     */
    public String getLastUsedDirectory() {
        return this.lastUsedDirectory;
    }
   
    /**
     * Sets the last used directory.
     *
     * @param lastUsedDirectory The last used directory.
     */
    public void setLastUsedDirectory(String lastUsedDirectory) {
        this.lastUsedDirectory = lastUsedDirectory;
    }
   
    /**
     * Gets the current tool panel location.
     *
     * @return The current tool panel location.
     */
    public ToolPanelLocation getToolPanelLocation() {
      return toolPanelLocation;
    }

    /**
     * Sets the current tool panel location.
     *
     * @param toolPanelLocation The current tool panel location.
     */
    public void setToolPanelLocation(ToolPanelLocation toolPanelLocation) {
      this.toolPanelLocation = toolPanelLocation;
    }
   
    /**
     * Gets the desktop pane that the picture frames live within.
     *
     * @return The desktop pane that the picture frames live within.
     */
    public JDesktopPane getDesktopPane() {
        return desktopPane;
    }
   
    /**
     * Gets the Picture that is currently being edited with PicEdit.
     *
     * @return The Picture that is currently being edited.
     */
    public Picture getPicture() {
        return getPictureFrame().getPicture();
    }
   
    /**
     * Gets the EditStatus for this PicEdit application. This object contains the
     * editing state of everything within PicEdit.
     *
     * @return The EditStatus.
     */
    public EditStatus getEditStatus() {
        return getPictureFrame().getEditStatus();
    }
   
    /**
     * Returns the Menu used by PICEDIT.
     *
     * @return The Menu used by PICEDIT.
     */
    public Menu getMenu() {
        return menu;
    }
   
    /**
     * Returns the panel that holds the picture.
     *
     * @return The panel that holds the picture.
     */
    public PicturePanel getPicturePanel() {
        return getPictureFrame().getPicturePanel();
    }
   
    /**
     * Gets the currently active PictureFrame.
     *
     * @return The currently active PictureFrame.
     */
    public PictureFrame getPictureFrame() {
        PictureFrame selectedFrame = (PictureFrame)this.desktopPane.getSelectedFrame();
        if (selectedFrame != null) {
            activePictureFrame = selectedFrame;
        }
       
        return activePictureFrame;
    }

    /**
     * Returns true if the application has at least one visible picture frame.
     *
     * @return true if the application has at least one visible picture frame.
     */
    public boolean hasVisiblePictureFrame() {
      if (desktopPane != null) {
        return (desktopPane.getAllFrames().length > 0);
      } else {
        return false;
      }
    }
   
    /**
     * Switches to the next picture frame on the desktop. This would normally be invoked when the
     * previously active picture frame is closed thereby automatically activating the next
     * picture frame.
     */
    public void selectNextPictureFrame() {
        JInternalFrame[] allPictureFrames = desktopPane.getAllFrames();
        if ((allPictureFrames == null) || (allPictureFrames.length == 0)) {
            // If there are no frames currently on the desktop then we create a blank one for
            // the purposes of resetting the tool bar, status bar and picture code list.
            activePictureFrame = new PictureFrame(this, prefs.getInt("ZOOM_FACTOR", 3), "Untitled");
            switchPictureCodeList();
           
        } else {
            // Otherwise proceed with selecting the next picture frame.
            desktopPane.selectFrame(true);
        }
    }
   
    /**
     * Switches the PictureCodeList currently being displayed with the one for the current picture.
     */
    public void switchPictureCodeList() {
        PictureCodeList activeList = this.getPictureFrame().getPictureCodeList();
        pictureCodeScrollPane.setViewportView(activeList);
        pictureCodeScrollPane.repaint();
    }
   
    /**
     * Resizes the screen according to the new zoom factor.
     *
     * @param zoomFactor the new zoom factor.
     */
    public void resizeScreen(int zoomFactor) {
        getPictureFrame().resizeForZoomFactor(zoomFactor);
    }

    /**
     * Paints the PICEDIT applet.
     */
    public void paint(Graphics g) {
        super.paint(g);
    }
   
    /**
     * Run PICEDIT as a standalone Java application.
     */
    public static void main(String[] args) {
        try {
          UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
        }
     
        final PicEdit app = new PicEdit();
        JFrame frame = new JFrame();
        frame.setTitle(PICEDIT_NAME);
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent event) {
                app.savePreferences();
            }
        });
       
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.getContentPane().add(app, BorderLayout.CENTER);
        frame.pack();
        frame.setMinimumSize(frame.getSize());
        frame.setLocationRelativeTo(null);
        frame.setResizable(true);
        frame.setVisible(true);
        frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
       
        // Register a listener for when the window is resizing so that we can resize the
        // internal frames. The HierarchyBoundsListener gets events while it is resizing,
        // whereas the ComponentListener only gets them after the resize.
        frame.getContentPane().addHierarchyBoundsListener(new HierarchyBoundsAdapter(){
            @Override
            public void ancestorResized(HierarchyEvent e) {
                // Start by checking that the internal frame will fit and adjust if required.
                PictureFrame pictureFrame = app.getPictureFrame();
                Dimension desktopSize = app.getDesktopPane().getSize();
                int newWidth = Math.min(desktopSize.width, pictureFrame.getWidth());
                int newHeight = Math.min(desktopSize.height, pictureFrame.getHeight());
                pictureFrame.setSize(new Dimension(newWidth, newHeight));
               
                // Now check to see if we need to move it to keep within the viewable area.
                int newTop = pictureFrame.getY();
                int newLeft = pictureFrame.getX();
                if ((pictureFrame.getX() + pictureFrame.getWidth()) > desktopSize.width) {
                    newLeft = desktopSize.width - pictureFrame.getWidth();
                }
                if ((pictureFrame.getY() + pictureFrame.getHeight()) > desktopSize.height) {
                    newTop = desktopSize.height - pictureFrame.getHeight();
                }
                if ((newLeft != pictureFrame.getY()) || (newTop != pictureFrame.getX())) {
                    pictureFrame.setLocation(new Point(newLeft, newTop));
                }
            }          
        });
       
        app.getDesktopPane().selectFrame(true);
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                PictureFrame pictureFrame = app.getPictureFrame();
                pictureFrame.resizeForZoomFactor(app.getEditStatus().getZoomFactor());
            }
        });
    }
}
TOP

Related Classes of com.agifans.picedit.PicEdit

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.