Package net.sf.rej.gui

Source Code of net.sf.rej.gui.SystemFacade

/* Copyright (C) 2004-2007 Sami Koivu
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/
package net.sf.rej.gui;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

import net.sf.rej.ProjectIterator;
import net.sf.rej.files.Archive;
import net.sf.rej.files.ClassIndex;
import net.sf.rej.files.ClassLocator;
import net.sf.rej.files.FileSet;
import net.sf.rej.files.Folder;
import net.sf.rej.files.Project;
import net.sf.rej.files.SingleFile;
import net.sf.rej.gui.action.GroupAction;
import net.sf.rej.gui.action.MarkClassFileModifiedAction;
import net.sf.rej.gui.action.RemoveFileAction;
import net.sf.rej.gui.dialog.PreferencesDialog;
import net.sf.rej.gui.editor.RecentFiles;
import net.sf.rej.gui.event.Event;
import net.sf.rej.gui.event.EventDispatcher;
import net.sf.rej.gui.event.EventObserver;
import net.sf.rej.gui.event.EventType;
import net.sf.rej.gui.preferences.Preferences;
import net.sf.rej.gui.tab.Tab;
import net.sf.rej.java.ClassFactory;
import net.sf.rej.java.ClassFile;
import net.sf.rej.java.ClassParsingException;
import net.sf.rej.java.Disassembler;
import net.sf.rej.java.MethodFactory;

/**
* Common entry point for ReJ GUI system level operations.
*
* @author Sami Koivu
*/
public class SystemFacade implements EventObserver {

    private static SystemFacade instance = null;
    private RecentFiles recent = new RecentFiles(new File("rej.recentfiles"));
    private Preferences preferences = new Preferences();
    private PreferencesDialog preferencesDialog = new PreferencesDialog(MainWindow.getInstance());
    ClassIndex classIndex = new ClassIndex();
    private ClassFactory classFactory = new ClassFactory();
    private MethodFactory methodFactory = new MethodFactory();
   
    private Project project = null;
    private String openFile = null;
    private EventDispatcher dispatcher = null;

    private ProgressMonitor progressMonitor = new ProgressMonitor() {
        public void setProgress(int progressPct) {
            SystemFacade.this.setProgress(progressPct);
        }

        public void setProgressScope(int min, int max) {
            SystemFacade.this.setProgressScope(min, max);
        }

    };

    private SystemFacade() {
        init();
    }

    private void init() {
        try {
            this.recent.load();
            this.preferences.setFile(new File("rej.preferences"));
            this.preferences.load();
         
            // update class index
            List list = this.preferences.getClassPathList();
            for (int i = 0; i < list.size(); i++) {
                File file = (File) list.get(i);
                FileSet fs = getFileSet(file);
                this.classIndex.addElement(fs);
            }

            updateClassIndex();
        } catch (Exception e) {
            handleException(e);
        }
    }

    public static synchronized SystemFacade getInstance() {
        if (instance == null)
            instance = new SystemFacade();

        return instance;
    }

    public void showPreferencesDialog() {
      try {
         List<File> prevList = this.preferences.getClassPathList();
         this.preferencesDialog.setClasspathList(prevList);
         this.preferencesDialog.invoke();
         List<File> curList = this.preferencesDialog.getClasspathList();
           synchronized(this.preferences) {
          this.preferences.setClassPathList(curList);
          this.preferences.save();
        }

        List<File> newItems = new ArrayList<File>();
        newItems.addAll(curList);
        newItems.removeAll(prevList);

        List<File> removedItems = new ArrayList<File>();
        removedItems.addAll(prevList);
        removedItems.removeAll(curList);

        for (int i=0; i < removedItems.size(); i++) {
          File file = removedItems.get(i);
          FileSet fs = getFileSet(file);
          this.classIndex.removeElement(fs);
        }

        for (int i=0; i < newItems.size(); i++){
          File file = newItems.get(i);
          FileSet fs = getFileSet(file);
          this.classIndex.addElement(fs);
        }

        updateClassIndex();
      } catch(Exception e) {
        handleException(e);
      }
    }

    /**
     * Exit application
     */
    public void exit() {
        if (this.project != null && this.project.isModified()) {
            int answer = JOptionPane.showOptionDialog(MainWindow.getInstance(),
                    "There are unsaved changes, quit without saving changes?",
                    "Unsaved changes.", JOptionPane.YES_NO_OPTION,
                    JOptionPane.QUESTION_MESSAGE, null, new String[] {
                            "Quit without saving", "Cancel" }, "Cancel");
            if (answer == 0) {
                System.exit(0);
            }
        } else {
            System.exit(0);
        }
    }

    public void openFile(File f) {
        if (this.project != null) {
            this.classIndex.removeElement(this.project.getFileSet());
        }

        Project project = new Project();

        project.setFile(f);
        try {
            FileSet set = getFileSet(f);
            this.classIndex.addElement(set);
            updateClassIndex();
            project.setFileSet(set);

            openProject(project);
        } catch(Exception e) {
          handleException(e);
        }
    }
   
    public void openProject(Project project) {
      try {
        if (this.project != null) {
          Event closeEvent = new Event(EventType.PROJECT_UPDATE);
          this.dispatcher.notifyObservers(closeEvent);
        }
        Event event = new Event(EventType.PROJECT_UPDATE);
        event.setProject(project);
        this.dispatcher.notifyObservers(event);

        Event fileEvent = new Event(EventType.CLASS_OPEN);
            if (project.getFileSet() instanceof SingleFile) {
                fileEvent.setFile(project.getFile().getName());
                fileEvent.setClassFile(project.getClassFile(project.getFile().getName()));
            }
            this.dispatcher.notifyObservers(fileEvent);

            if (project.getFileSet() instanceof SingleFile) {
                MainWindow.getInstance().setTab(Tab.EDITOR);
            } else {
                MainWindow.getInstance().setTab(Tab.FILES);
            }

            setTitle();
            this.recent.add(project.getFile().getPath());
            MainWindow.getInstance().updateRecentFilesMenu();
        } catch (Exception e) {
            handleException(e);
        }
    }

    public void saveFile() {
        try {
            this.project.save();
            setTitle();
        } catch (Exception e) {
            handleException(e);
        }
    }

    public void saveFile(File file) {
        try {
            this.project.saveAs(file);
            setTitle();
        } catch (Exception e) {
            handleException(e);
        }
    }

    public void setProgress(int i) {
        MainWindow.getInstance().setProgress(i);
    }

    public void setProgressScope(int min, int max) {
        MainWindow.getInstance().setProgressScope(min, max);
    }

    public void setStatus(final String status) {
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
              MainWindow.getInstance().setStatus(status);
        }
      });
    }

    public void handleException(Exception ex) {
        try {
          MainWindow mw = MainWindow.getInstance();
          if (mw != null) {
            mw.setStatus("Last exception: " + ex.getMessage());
            MainWindow.getInstance().showErrorMessage(
                    "Exception was thrown: " + ex.getMessage());
                ex.printStackTrace();
          } else {
            ex.printStackTrace();
          }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void handleExceptions(List errors) {
        try {
            Iterator iterator = errors.iterator();
            while (iterator.hasNext()) {
                Exception ex = (Exception) iterator.next();
                // TODO: cancel option to be able not view all errors
                MainWindow.getInstance().setStatus(
                        "Last exception: " + ex.getMessage());
                MainWindow.getInstance().showErrorMessage(
                        "Exception was thrown: " + ex.getMessage());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public FileSet getFileSet(File f) throws IOException {
        if (f.getName().endsWith(".class")) {
            return new SingleFile(f);
        } else if (f.isDirectory()) {
            return new Folder(f);
        } else if (f.getName().endsWith(".zip") || f.getName().endsWith(".jar")) {
            return new Archive(f);
        } else {
            throw new RuntimeException("File of wrong type: " + f.getName());
        }
    }

    public void setTitle(String title) {
        MainWindow.getInstance().setTitle(title);
    }

    public void setTitle() {
        if (this.project.isModified()) {
            setTitle("reJ - *" + this.project.getFile().getPath());
        } else {
            setTitle("reJ - " + this.project.getFile().getPath());
        }
    }

    public void performAction(Undoable action) {
      performAction(action, this.openFile);
    }

    /**
   * Performs the action specified by <code>action</code> (by calling the
   * execute() method) on the project file specified by
   * <code>targetFile</code>. The action is added to the
   * <code>UndoManager</code> of the target file and project modified status
   * is set accordingly. An application-wide CLASS_UPDATE notification is
   * dispatched.
   *
   * @param action
   *            <code>Undoable</code> that is to be performed.
   * @param targetFile
   *            the file on which the action is performed on.
   */
    public void performAction(Undoable action, String targetFile) {
        try {
            UndoManager um = project.getUndoManager(targetFile);
            if (!this.project.isModified(targetFile)) {
              // is the file in question is not modified yet, group the new action
              // with an action that changes the status of the file.
                GroupAction ga = new GroupAction();
                ga.add(action);
              ClassFile cf = getClassFile(targetFile);
                ga.add(new MarkClassFileModifiedAction(this.project, targetFile, cf));
                um.add(ga);
                ga.execute();
            } else {
              um.add(action);
              action.execute();
            }
            this.dispatcher.notifyObservers(new Event(EventType.CLASS_UPDATE));
            setTitle();
        } catch (Exception e) {
            handleException(e);
            throw new RuntimeException(e);
        }
    }

    public void performProjectAction(Undoable action) {
        try {
            UndoManager um = this.project.getProjectUndoManager();
            um.add(action);
            action.execute();
            Event event = new Event(EventType.PROJECT_UPDATE);
            event.setProject(this.project);
            this.dispatcher.notifyObservers(event);
            setTitle();
        } catch (Exception e) {
            handleException(e);
            throw new RuntimeException(e);
        }
    }

    public void performUndo(String targetFile) {
        try {
            UndoManager um = this.project.getUndoManager(targetFile);
            um.undo();
            this.dispatcher.notifyObservers(new Event(EventType.CLASS_UPDATE));
            setTitle();
        } catch (Exception e) {
            handleException(e);
        }
    }

    public void performRedo(String targetFile) {
        try {
            UndoManager um = this.project.getUndoManager(targetFile);
            um.redo();
            this.dispatcher.notifyObservers(new Event(EventType.CLASS_UPDATE));
            setTitle();
        } catch (Exception e) {
            handleException(e);
        }
    }

    public void performProjectUndo() {
        try {
            UndoManager um = this.project.getProjectUndoManager();
            um.undo();
            Event event = new Event(EventType.PROJECT_UPDATE);
            event.setProject(this.project);
            this.dispatcher.notifyObservers(event);
        } catch (Exception e) {
            handleException(e);
        }
    }

    public void performProjectRedo() {
        try {
            UndoManager um = this.project.getProjectUndoManager();
            um.redo();
            Event event = new Event(EventType.PROJECT_UPDATE);
            event.setProject(this.project);
            this.dispatcher.notifyObservers(event);
        } catch (Exception e) {
            handleException(e);
        }
    }

    public void performFind() {
        try {
            throw new RuntimeException("Find operation not implmented.");
        } catch (Exception e) {
            handleException(e);
        }
    }

    public void removeFile(List<String> files) {
        try {
            RemoveFileAction rfa = new RemoveFileAction(project, files);
            this.performProjectAction(rfa);
        } catch (Exception e) {
            handleException(e);
        }
    }

    public List getRecentFiles() {
        return this.recent.getList();
    }

    public void goTo(Link link) {
        if (link.getFile() != null) {
          if (!link.getFile().equals(this.openFile)) {
        Event event = new Event(EventType.CLASS_OPEN);
        try {
          ClassFile cf = this.project.getClassFile(link.getFile());
          event.setClassFile(cf);
          event.setFile(link.getFile());
          this.dispatcher.notifyObservers(event);
        } catch(Exception ex) {
          SystemFacade.getInstance().handleException(ex);
        }
          }
        }
        MainWindow.getInstance().setTab(link.getTab());
        MainWindow.getInstance().getSelectedTab().goTo(link);
    }

    public void search(final IteratorAgent matcher) {
        ProjectIterator.iterate(project, matcher);
    }

    /**
     * Return the Default GUI progress monitor
     *
     * @return ProgressMonitor
     */
    public ProgressMonitor getProgressMonitor() {
        return this.progressMonitor;
    }

    /**
     * Return the ClassFile object of the selected file in the open project
     *
     * @param filename
     * @return ClassFile The parsed ClassFile object
     * @throws IOException
     *             I/O problem reading/parsing the ClassFile
     * @throws ClassParsingException
     *             Parsing Exception - the ClassFile was malformed
     */
    public ClassFile getClassFile(String filename) throws IOException,
            ClassParsingException {
        return this.project.getClassFile(filename);
    }

    public ClassFile getClassFile(ClassLocator classLocator)
            throws IOException, ClassParsingException {
        FileSet projectFileSet = this.project.getFileSet();
        if (projectFileSet.equals(classLocator.getFileSet())) {
            return getClassFile(classLocator.getFile());
        } else {
            // TODO: should these be cached as well? that is, ClassFile objects
            // of classes that are not in the open project(but are in the
            // classpath)
            try {
                byte[] data = classLocator.getFileSet().getData(
                        classLocator.getFile());
                ClassFile cf = Disassembler.readClass(data);
                return cf;
            } catch (Exception e) {
                throw new ClassParsingException("Error opening file "
                        + classLocator.dumpDetails(), e);
            }
        }
    }

    public ClassIndex getClassIndex() {
        return this.classIndex;
    }

    public void updateClassIndex() {
        Thread thread = new Thread(new Runnable() {
            public void run() {
                SystemFacade.this.classIndex.conditionalUpdate();
            }
        });
        thread.start();
    }

    public void createNewArchiveProject(File archiveFile) {
        if (archiveFile.exists()) {
            int answer = JOptionPane.showOptionDialog(MainWindow.getInstance(),
                    "File already exists. Overwrite?",
                    "File already exists.", JOptionPane.YES_NO_OPTION,
                    JOptionPane.QUESTION_MESSAGE, null, new String[] {
                            "Overwrite", "Cancel" }, "Cancel");
            if (answer != 0) {
                return; // EARLY RETURN
            }
        }
       
        try {
      Archive archive = Archive.createNew(archiveFile);
      Project project = new Project();
      project.setFile(archiveFile);
      project.setFileSet(archive);
      project.save();
      openProject(project);
    } catch (Exception e) {
      handleException(e);
    }
    }

    public void createNewClass(String fullClassName, String selectedFile) {
        // TODO: Creating a new class should be an undoable action?
        ClassFile cf = this.classFactory.createClass(fullClassName);
        this.project.addFile(selectedFile, cf);
       
        /* TODO: the file hasn't been saved into the set yet at this point
         * sor the following throws a NullPointerException
        try {
          getClassIndex().addLocator(this.project.getFileSet(), selectedFile);
        } catch(IOException ioe) {
          handleException(ioe);
        }*/
       
        Event event = new Event(EventType.PROJECT_UPDATE);
        event.setProject(this.project);
        this.dispatcher.notifyObservers(event);       
       
        event = new Event(EventType.CLASS_OPEN);
        event.setClassFile(cf);
        event.setFile(selectedFile);
        this.dispatcher.notifyObservers(event);
    }

    public MethodFactory getMethodFactory() {
        return this.methodFactory;
    }

  public void processEvent(Event event) {
    switch (event.getType()) {
    case INIT:
      this.dispatcher = event.getDispatcher();
      break;
    case PROJECT_UPDATE:
      this.project = event.getProject();
      break;
    case CLASS_OPEN:
      this.openFile = event.getFile();
      break;
    case CLASS_UPDATE:
    case CLASS_REPARSE:
    case CLASS_PARSE_ERROR:
    case DISPLAY_PARAMETER_UPDATE:
    case DEBUG_ATTACH:
    case DEBUG_DETACH:
    case DEBUG_RESUMED:
    case DEBUG_SUSPENDED:
    case DEBUG_THREAD_CHANGE_REQUESTED:
    case DEBUG_STEP_INTO_REQUESTED:
    case DEBUG_STEP_OUT_REQUESTED:
    case DEBUG_STEP_OVER_REQUESTED:
    case DEBUG_RESUME_REQUESTED:
    case DEBUG_STACK_FRAME_CHANGE_REQUESTED:
    case DEBUG_STACK_FRAME_CHANGED:
    case DEBUG_SUSPEND_REQUESTED:
    case DEBUG_THREAD_CHANGED:
      // do nothing
      break;
    }
  }
 
  public Preferences getPreferences() {
    return this.preferences;
  }

}
TOP

Related Classes of net.sf.rej.gui.SystemFacade

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.