Package edu.zao.fire

Source Code of edu.zao.fire.Renamer$EventListener

package edu.zao.fire;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import edu.zao.fire.ListRule.ListStyle;
import edu.zao.fire.editors.RenamerRuleChangeListener;
import edu.zao.fire.editors.RenamerRuleEditor;
import edu.zao.fire.editors.RenamerRuleEditorManager.ActiveEditorListener;
import edu.zao.fire.filters.BrowserFileFilter;
import edu.zao.fire.filters.BrowserFileFilter.FilterListener;
import edu.zao.fire.filters.UserFilters;
import edu.zao.fire.filters.UserIgnoreFileFilter;
import edu.zao.fire.util.FileGatherer;
import edu.zao.fire.util.Filter;

/**
* Back end class that handles the actual changing of Files' names. It can be
* pointed to a particular directory, then told to apply changes. At that point,
* it will apply its <code>currentRule</code> to each file within that
* directory.
*
* @author dylan
*/
public class Renamer implements RenamerRuleChangeListener, ActiveEditorListener, FilterListener {
  private RenamerRule currentRule;
  private File currentDirectory;
  private final RenamerHistory renamingHistory = new RenamerHistory();
  private final List<File> localFiles = new ArrayList<File>();
  private final List<Filter<File>> fileFilters = new ArrayList<Filter<File>>();
  private final UserFilters userFilters = new UserFilters();
  /**
   *
   * Maps original filenames to their new names; original value is the key
   */
  private final Map<String, String> newNamesMap = new HashMap<String, String>();

  /**
   * File Filter used in conjunction with the "show only changing files"
   * button. This does not affect the state of the fileFilters list, and does
   * not affect whether any file will be renamed.
   */
  public final Filter<File> changingFileFilter = new Filter<File>() {
    @Override
    public boolean accept(File file) {
      String oldName = file.getName();
      String newName = newNamesMap.get(oldName);
      return oldName.compareTo(newName) != 0;
    }
  };

  private static Renamer defaultInstance = new Renamer();

  public static Renamer getDefault() {
    return defaultInstance;
  }

  // ----------------------------------------------------------------
  // Section for event handling and event listeners
  // ----------------------------------------------------------------

  /**
   * Enumeration that describes the types of various events that could happen
   * during the renaming process.
   */
  public static enum EventType {
    UpdatedNames, IOException, BadRegex, NameConflict, RenamedWithNoProblems, CouldNotRename, LessThanOneRomanList, LessThanZeroList
    // TODO: add more when we find more event cases
  }

  /**
   * Interface that defines the behavior of an object that listens to this
   * Renamer for status update events.
   *
   * @author dylan
   */
  public static interface EventListener {
    /**
     * This function will be called if this EventListener has been added to
     * a {@link Renamer} via {@link Renamer#addEventListener(EventListener)}
     * .
     *
     * @param eventType
     *            The type of the error caused by the Renamer.
     * @param file
     *            The file in question that was unable to be renamed.
     * @param rule
     *            The {@link RenamerRule} that was being used when the error
     *            was caused.
     */
    void seeEvent(EventType eventType, File file, RenamerRule rule);
  }

  private final List<EventListener> eventListeners = new ArrayList<EventListener>();

  /**
   * Add an {@link EventListener} to be notified whenever this Renamer goes
   * through some observable event.
   *
   * @param listener
   *            The {@link EventListener} to be added.
   */
  public void addEventListener(EventListener listener) {
    eventListeners.add(listener);
  }

  /**
   * Remove an {@link EventListener} so that it will no longer be notified
   * whenever this Renamer goes through some observable event.
   *
   * @param listener
   *            The {@link EventListener} to be removed.
   */
  public void removeEventListener(EventListener listener) {
    eventListeners.remove(listener);
  }

  /**
   * Notify all {@link EventListener}s that an error has occurred.
   *
   * @param eventType
   *            The type of the error caused by this Renamer.
   * @param file
   *            The file in question that was unable to be renamed.
   * @param rule
   *            The {@link RenamerRule} that was being used when the error was
   *            caused.
   */
  private void fireEvent(EventType eventType, File file, RenamerRule rule) {
    for (EventListener listener : eventListeners) {
      listener.seeEvent(eventType, file, rule);
    }
  }

  // ----------------------------------------------------------------
  // End of event handling section
  // ----------------------------------------------------------------

  public Renamer() {
    userFilters.setIndividualFilter(new UserIgnoreFileFilter());
    addFileFilter(userFilters);
  }

  public UserFilters getUserFilters() {
    return userFilters;
  }

  public void addFileFilter(BrowserFileFilter filter) {
    fileFilters.add(filter);
    filter.addFilterListener(this);
  }

  public void removeFileFilter(BrowserFileFilter filter) {
    fileFilters.remove(filter);
    filter.removeFilterListener(this);
  }

  public boolean filtersAcceptFile(File file) {
    for (Filter<File> filter : fileFilters) {
      if (!filter.accept(file)) {
        return false;
      }
    }
    return true;
  }

  @Override
  public void filterChanged(Filter<File> filter) {
    System.out.println(filter + " just changed");
    rebuildNewNamesCache();
  }

  /**
   * Apply the current renaming rule to all of the files in the current
   * directory. If any errors are encountered during this process, the
   * {@link EventListener}s should be notified.
   */
  public void applyChanges() {
    RenamerEvent newEvent = new RenamerEvent();
    for (File file : localFiles) {
      if (!filtersAcceptFile(file)) {
        continue;
      }
      try {
        String currentName = file.getName();
        String newName = newNamesMap.get(currentName);
        if (!currentName.equals(newName)) {
          RenamedFile newRenamedFile = new RenamedFile();
          String fullName = file.getCanonicalPath();
          newRenamedFile.setBeforePath(fullName);
          int fileNameIndex = fullName.lastIndexOf(file.getName());
          fullName = fullName.substring(0, fileNameIndex) + newName;
          File newFile = new File(fullName);
          newRenamedFile.setAfterPath(fullName);
          boolean success = file.renameTo(newFile);
          if (!success) {
            fireEvent(EventType.CouldNotRename, file, currentRule);
          }
          newEvent.addRenamedFile(newRenamedFile);
        }
      } catch (IOException e) {
        // tell the error listeners that something went wrong
        fireEvent(EventType.IOException, file, currentRule);
      }
    }

    renamingHistory.addRenamerEvent(newEvent);
    setCurrentDirectory(currentDirectory);
  }

  public RenamerHistory getRenamerHistory() {
    return renamingHistory;
  }

  public void undoRenamerEvent() {
    renamingHistory.undo();
    System.out.println("Undoing RenamerEvent\n");
    setCurrentDirectory(currentDirectory);
    rebuildNewNamesCache();
  }

  public void redoRenamerEvent() {
    renamingHistory.redo();
    System.out.println("Redoing RenamerEvent\n");
    setCurrentDirectory(currentDirectory);
    rebuildNewNamesCache();
  }

  /**
   * Move to the specified <code>directory</code> and update the list of local
   * files.
   *
   * @param directory
   *            The directory to set as the current directory
   */
  public void setCurrentDirectory(File directory) {
    if (directory == null) {
      return;
    }
    if (!directory.isDirectory()) {
      throw new IllegalArgumentException("The given 'directory' MUST be a directory.");
    }
    currentDirectory = directory;
    localFiles.clear();
    for (File file : new FileGatherer(directory)) {
      localFiles.add(file);
    }
    System.out.println("Directory changed");
    rebuildNewNamesCache();
  }

  /**
   * @return The current root directory (i.e. the folder that contains all of
   *         the <code>localFile</code>s)
   */
  public File getCurrentDirectory() {
    return currentDirectory;
  }

  /**
   * Sets the current {@link RenamerRule} to the given <code>rule</code>.
   *
   * @param rule
   *            The {@link RenamerRule} to be set as the new current rule.
   */
  public void setCurrentRule(RenamerRule rule) {
    System.out.println("set current rule to " + rule);
    currentRule = rule;
    rebuildNewNamesCache();
  }

  /**
   * @return The current {@link RenamerRule} being used by this Renamer
   */
  public RenamerRule getCurrentRule() {
    return currentRule;
  }

  /**
   * @return An object that can iterate over all of the <code>File</code>s
   *         that are currently considered "Local."
   */
  public Iterable<File> getLocalFiles() {
    return localFiles;
  }

  /**
   * Listener Method: This method is invoked by the RenamerRuleEditorManager
   * when a different RenamerRuleEditor gets user focus. When this happens,
   * this Renamer's <code>currentRule</code> is set to the new active editor's
   * rule.
   */
  @Override
  public void activeEditorChanged(RenamerRuleEditor newActiveEditor) {
    System.out.println("active editor was changed");
    if (newActiveEditor == null) {
      setCurrentRule(null);
    } else {
      setCurrentRule(newActiveEditor.getRule());
    }
  }

  /**
   * Listener Method: This method is invoked by a RenamerRuleEditor whenever
   * that editor's rule has been modified by the UI. When this happens, the
   * modified names of all of the local files will be recalculated.
   */
  @Override
  public void ruleChanged(RenamerRule rule) {
    System.out.println("renamer rule was modified");
    rebuildNewNamesCache();
  }

  /**
   * Recalculate all of the modified names for each local file within the
   * <code>currentDirectory</code>. These names will be stored in a local
   * cache.
   */
  private void rebuildNewNamesCache() {
    System.out.println("rebuilding names cache");
    newNamesMap.clear();
    boolean noProblem = true;

    if (currentRule != null) {
      currentRule.setup();
    }
    for (File file : localFiles) {
      String oldName = file.getName();
      if (!filtersAcceptFile(file)) {
        newNamesMap.put(oldName, oldName);
        continue;
      }
      try {
        String newName = (currentRule == null) ? oldName : currentRule.getNewName(file);
        newNamesMap.put(oldName, newName);
      } catch (UserRegexException e) {
        noProblem = false;
        fireEvent(EventType.BadRegex, file, currentRule);
        return;
      } catch (ListRuleException e) {
        noProblem = false;
        if (e.getListStyle() == ListStyle.ROMAN_NUMERALS)
          fireEvent(EventType.LessThanOneRomanList, file, currentRule);
        else
          fireEvent(EventType.LessThanZeroList, file, currentRule);
        return;
      } catch (IOException e) {
        noProblem = false;
        fireEvent(EventType.IOException, file, currentRule);
        newNamesMap.put(oldName, oldName);
      }
    }
    if (currentRule != null) {
      currentRule.tearDown();
    }

    // Check for naming conflicts
    boolean gotNameConflict = false;
    Set<String> newNames = new TreeSet<String>();
    for (File file : localFiles) {
      String currentName = file.getName();
      String newName = newNamesMap.get(currentName);
      if (newNames.contains(newName)) {
        gotNameConflict = true;
      }
      newNames.add(newName);
    }
    if (gotNameConflict) {
      noProblem = false;
      fireEvent(EventType.NameConflict, null, currentRule);
    }
    fireEvent(EventType.UpdatedNames, null, currentRule);
    System.out.println("updated names...");
    if (noProblem) {
      fireEvent(EventType.RenamedWithNoProblems, null, currentRule);
    }
  }

  public String getNewName(File file) {
    return newNamesMap.get(file.getName());
  }
}
TOP

Related Classes of edu.zao.fire.Renamer$EventListener

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.