Package kameleon.gui.model

Source Code of kameleon.gui.model.FileModel

/*
* Copyright (c) 2012, Fromentin Xavier, Schnell Michaël, Dervin Cyrielle, Brabant Quentin
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*      * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*      * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*      * The names of its contributors may not be used to endorse or promote products
*       derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Fromentin Xavier, Schnell Michaël, Dervin Cyrielle OR Brabant Quentin
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package kameleon.gui.model;

import java.io.File;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.*;

import kameleon.exception.KameleonException;
import kameleon.exception.NotUniquePlugInInfoException;
import kameleon.exception.UnknownExtensionException;
import kameleon.gui.exception.InvalidOutputFileException;
import kameleon.gui.util.FileConstants;
import kameleon.gui.util.LanguageConstants;
import kameleon.plugin.PlugInInfo;
import kameleon.util.IOObject;
import kameleon.util.WorkSpaceManager;

/**
* Model responsible for the handling of the files. Allows the user
* to add new files, remove files from the history, save the most
* recently used files from one session to another, set the analyzers
* used by the files and the generators used for the next generation,
* choose the file charset and view detailed information about the
* files.
*
* @author    Schnell Michaël
* @version    1.0
*/
public class FileModel extends MessageModel
implements FileConstants, LanguageConstants {

  /**
   * Number of files which are stored from session to session.
   */
  public static final int HISTORY_SIZE = 10 ;

  /**
   * Default format of the dates displayed in the graphical interface.
   */
  public static final String DEFAULT_DATE_FORMAT = "dd/MM/yyyy HH:mm" ; //$NON-NLS-1$

  /**
   * Formatter used to display the dates in the default format.
   *
   * @see    #DEFAULT_DATE_FORMAT
   */
  public static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat(DEFAULT_DATE_FORMAT) ;

  /**
   * Index of the currently selected file (or {@code null} if no file
   * is selected)
   */
  protected Integer currentFileIndex ;

  /**
   * Index of the last file which was removed from the history.
   */
  protected int deletedIndex ;

  /**
   * History of the recently used files and their generations.
   */
  protected List<FileInfo> recentFiles ;

  /**
   * Target file for the generation (provided by the user).
   */
  protected File outputFile ;

  /**
   * Charset used to decode the analyzed files.
   */
  protected String charset ;

  /**
   * Flag indicating if a new file has just been added.
   */
  protected boolean newFileAdded ;

  /**
   * Flag indicating that the selected file in the
   * history has just changed.
   */
  protected boolean selectionHasChanged ;

  /**
   * Flag indicating that a file has just been removed.
   */
  protected boolean fileRemoved ;

  /**
   * Ids of the currently selected generators.
   */
  protected List<String> selectedGenerators ;

  /**
   * Builds an instance with the given options.
   *
   * <p>Reads the history of the recently used files.
   *
   * @param   debugMode
   *       flag indicating whether the debug mode
   *       should be activated ({@code true} means
   *       activated)
   */
  public FileModel(boolean debugMode) {
    super(debugMode) ;
    this.currentFileIndex = null ;
    this.newFileAdded = false ;
    this.selectionHasChanged = false ;
    this.fileRemoved = false ;
    this.charset = Charset.defaultCharset().displayName() ;
    this.readHistory() ;
  }// FileModel(boolean)

  /**
   * Builds an instance with default options.
   */
  public FileModel() {
    this(DEFAULT_DEBUG_MODE) ;
  }// FileModel()

  /**
   * Reads the list of recently used files from the history file.
   */
  protected void readHistory() {
    try {
      File history = new File(CONFIG_HISTORY_FILE) ;
      if (history.exists()) {
        Object obj = IOObject.readObjectFromFile(
            CONFIG_HISTORY_FILE) ;
        if (obj instanceof List<?>) {
          this.recentFiles = (List<FileInfo>) obj ;
          return ;
        }// if
      }// if
    } catch (KameleonException ke) {
      this.displayDebugInformation(ke) ;
      Message infoMsg = new InformationMessage(
          InformationMessage.State.INFORMATION,
          READING_HISTORY_ERROR) ;
      this.addMessage(infoMsg) ;
    }// try
    this.recentFiles = new LinkedList<FileInfo>() ;
  }// readHistory()

  /**
   * Writes the list of recently used files to the history file.
   */
  protected void writeHistory() {
    try {
      WorkSpaceManager.ensureWorkSpace() ;
      // We only keep the HISTORY_SIZE files inside history.
      List<FileInfo> subList = new LinkedList<FileInfo>() ;
      int maxI = Math.min(this.recentFiles.size(), HISTORY_SIZE) ;
      Iterator<FileInfo> iter = this.recentFiles.iterator() ;
      for(int i=0; i<maxI; ++i) {
        FileInfo element = iter.next() ;
        subList.add(element) ;
      }// for
      IOObject.writeObjectToFile(CONFIG_HISTORY_FILE, subList) ;
    } catch (KameleonException ke) {
      this.displayDebugInformation(ke) ;
      Message infoMsg = new InformationMessage(
          InformationMessage.State.INFORMATION,
          WRITING_HISTORY_ERROR) ;
      this.addMessage(infoMsg) ;
    }// try
  }// writeHistory()

  /**
   * Indicates if a file is currently selected.
   *
   * @return  {@code true} if a file is currently selected,
   *       {@code false} otherwise
   */
  public boolean fileIsSelected() {
    return (this.currentFileIndex != null) ;
  }// fileIsSelected()

  /**
   * Returns the index of the file with the given path
   * in the history file list.
   *
   * @param   path
   *       absolute path of the requested file
   *
   * @return  index of the requested file or {@code null}
   *       if the file was not found
   */
  public Integer getPosition(String path) {
    int position = 0 ;
    boolean found = false ;
    Iterator<FileInfo> iter = this.recentFiles.iterator() ;
    while (iter.hasNext() && !found) {
      FileInfo fi = iter.next() ;
      found = fi.getPath().equals(path) ;
      ++position ;
    }// while
    //TODO Review - possibly throw an exception here
    // The given path was not found
    if (!found) {
      return null ;
    }// if
    return new Integer(position-1) ;
  }// getPosition(String)

  /**
   * Sets the index for the currently selected file.
   *
   * @param   position
   *       index of the selected file
   */
  public void setCurrentFilePosition(int position) {
    this.currentFileIndex = new Integer(position) ;
  }// setCurrentFilePosition(int)

  /**
   * Returns the index of the currently selected file.
   *
   * @return  Index of the currently selected file or {@code -1}
   *       if no file is selected
   */
  public int getCurrentFilePosition() {
    if (this.currentFileIndex == null) {
      return -1 ;
    }// if
    return this.currentFileIndex.intValue() ;
  }// getCurrentFilePosition()

  /**
   * Returns a formatted {@code String} the last generation date
   * of the currently selected file.
   *
   * @return  Last generation date of the currently selected
   *       file or {@code null} if the file was never generated
   *       or if there is no selected file
   */
  public String getFileLastGenerationDate() {
    FileInfo current = this.getSelectedFileInfo() ;
    if (current != null) {
      Date last = current.getLastGeneration() ;
      if (last != null) {
        return DATE_FORMATTER.format(last) ;
      }// if
    }// if
    return null ;
  }// getFileLastGenerationDate()

  /**
   * Returns the extension of the currently selected file.
   *
   * @return  Extension of the currently selected file or
   *       {@code null} if no file is selected or {@code ""}
   *       if the file has no extension
   */
  public String getFileType() {
    FileInfo current = this.getSelectedFileInfo() ;
    if (current != null) {
      String fileName = current.getName() ;
      int positionDot = fileName.lastIndexOf('.') ;
      if (positionDot != -1) {
        // Extract the extension and return it
        return fileName.substring(positionDot+1) ;
      }// if
      return "" ;//$NON-NLS-1$
    }// if
    return null ;
  }// getFileType()

  /**
   * Returns an array with the information about the
   * recently used files.
   *
   * @return  Array containing all the information about the
   *       recently used files
   */
  public FileInfo[] getRecentFileInfo() {
    return this.recentFiles.toArray(
        new FileInfo[this.recentFiles.size()]) ;
  }// getRecentFileInfo()

  /**
   * Sets the output file for future generations.
   *
   * @param  selectedFile
   *       new output file
   *
   * @throws   InvalidOutputFileException
   *       if an invalid file is provided
   *///TODO Further test if the given file is valid
  public void setOutputFile(File selectedFile)
      throws InvalidOutputFileException {
    if (selectedFile == null) {
      throw new InvalidOutputFileException() ;
    }// if
    this.outputFile = selectedFile ;
  }// setOutPutFile(File)

  /**
   * Adds a new file. The model will add the file to history
   * and select it.
   *
   * @param  newFile
   *       added file
   */
  public void addFile(File newFile) {
    String extension = getExtension(newFile) ;
    FileInfo fi = new FileInfo(newFile.getAbsolutePath()) ;
   
    // Test if the file is already in the history
    if (this.recentFiles.contains(fi)) {
      // We simply selected the added file
      this.currentFileIndex = this.getPosition(fi.getPath()) ;
      this.selectionHasChanged = true ;
    } else {
      int insertIndex = 0 ;
      if (this.recentFiles.isEmpty()) {
        this.recentFiles.add(fi) ;
      } else {
        this.recentFiles.add(insertIndex, fi);
      }// if
      this.setCurrentFilePosition(insertIndex) ;
      try {
        if (this.am.getNAnalyzers(extension) > 0) {
          try {
            PlugInInfo analyzer =
                this.am.getAnalyzerInfo(extension) ;
            fi.setIdFormat(analyzer.getId()) ;
          } catch (NotUniquePlugInInfoException ex) {
            fi.setIdFormat(null) ;
          }// try
        }// if
      } catch (UnknownExtensionException ex) {
        fi.setIdFormat(null);
      }// try
      this.writeHistory() ;
      this.selectionHasChanged = true ;
      this.newFileAdded = true ;
    }// if
    try {
      this.notifyObservers() ;
    } catch (KameleonException ke) {
      this.displayDebugInformation(ke) ;
    }// try
    this.selectionHasChanged = false ;
    this.newFileAdded = false ;
  }// addFile(File)

  /**
   * Indicates if a new file has just been added.
   *
   * @return  {@code true} if a new file has just been added,
   *       {@code false} otherwise
   */
  public boolean newFileAdded() {
    return this.newFileAdded ;
  }// newFileAdded()

  /**
   * Indicates if the current selection has just changed.
   *
   * @return  {@code true} if the current selection has just changed,
   *       {@code false} otherwise
   */
  public boolean selectionHasChanged() {
    return this.selectionHasChanged ;
  }// selectedHasChanged()

  /**
   * Returns the information about the currently selected file.
   *
   * @return  {@code PlugInInfo} for the current selection or
   *       {@code null} if no file is selected
   */
  public FileInfo getSelectedFileInfo() {
    if(this.currentFileIndex != null) {
      return this.recentFiles.get(
          this.currentFileIndex.intValue()) ;
    }// if
    return null ;
  }// getSelectedFileInfo()

  /**
   * Selects the file with the given path in the history.
   *
   * @param  filePath
   *       absolute path the of the file to select
   */
  public void selectFile(String filePath) {
    this.currentFileIndex = this.getPosition(filePath) ;
    this.selectionHasChanged = true ;
    try {
      this.notifyObservers() ;
    } catch (KameleonException ke) {
      this.displayDebugInformation(ke) ;
    }// try
    this.selectionHasChanged = false ;
  }// selectFile(String)

  /**
   * Clears the current selection if there is one.
   */
  public void clearSelection() {
    if (this.currentFileIndex != null) {
      this.currentFileIndex = null ;
      this.selectionHasChanged = true ;
      this.fileRemoved = false ;
      try {
        this.notifyObservers() ;
      } catch (KameleonException ke) {
        this.displayDebugInformation(ke) ;
      }// try
      this.selectionHasChanged = false ;
    }// if
  }// clearSelection()

  /**
   * Sets the analyzer used for the currently selected file.
   *
   * @param   analyzerId
   *       id of the new analyzer for the currently selected file
   *///TODO Review the case of no file selected
  public void setCurrentFileAnalyzerId(String analyzerId) {
    FileInfo current = this.getSelectedFileInfo() ;
    if (current != null) {
      current.setIdFormat(analyzerId) ;
    } // if
  }// setCurrentFileAnalyzerId(String)

  /**
   *  Sets the analyzer used for the currently selected file
   *  and updates the history file.
   *
   * @param   analyzer
   *       analyzer for the currently selected file
   */
  public void setCurrentFileAnalyzer(PlugInInfo analyzer) {
    this.setCurrentFileAnalyzerId(analyzer.getId()) ;
    this.writeHistory() ;
    this.selectionHasChanged = true ;
    try {
      this.notifyObservers() ;
    } catch (KameleonException ke) {
      this.displayDebugInformation(ke) ;
    }// try
    this.selectionHasChanged = false ;
  }// setCurrentFileAnalyzer(PlugInInfo)

  /**
   * Returns the informations about the analyzer for the currently
   * selected file.
   *
   * @return  instance of {@code PlugInInfo} for the analyzer used
   *       by the currently selected file or {@code null} if
   *       the analyzer is unknown or no file is selected
   */
  public PlugInInfo getCurrentFileFormat() {
    FileInfo current = this.getSelectedFileInfo() ;
    if (current != null) {
      String formatId = current.getIdFormat() ;
      if (formatId != null) {
        return this.getAnalyzer(formatId) ;
      }// if
    }// if
    return null ;
  }// getCurrentFileFormat()

  /**
   * Indicates if the format of the currently selected file is known.
   *
   * @return  {@code true} if the currently selected file has
   *       a known analyzer, {@code false} otherwise
   */
  public boolean currentFileFormatIsKnown() {
    return (this.getCurrentFileFormat() != null) ;
  }// currentFileFormatIsKnown()

  /**
   * Removes the current selection from the history list and from
   * the history file. If no file is currently selected, nothing
   * is done.
   */
  public void deleteCurrentSelection() {
    if (this.currentFileIndex != null) {
      this.deletedIndex = this.currentFileIndex.intValue() ;
      this.recentFiles.remove(this.deletedIndex) ;
      this.currentFileIndex = null ;
      this.writeHistory() ;
      this.fileRemoved = true ;
      try {
        this.notifyObservers() ;
      } catch (KameleonException ke) {
        this.displayDebugInformation(ke) ;
      }// try
      this.fileRemoved = false ;
    }// if
  }// deleteCurrentSelection()

  /**
   * Indicates if a file has just been removed from the history.
   *
   * @return  {@code true} if a file has just been removed from
   *       the history, {@code false} otherwise
   */
  public boolean fileRemoved() {
    return this.fileRemoved ;
  }// fileRemoved()

  /**
   * Returns the index of the deleted file in the history.
   *
   * @return  Index of the deleted file in the history
   */
  public int getDeletedIndex() {
    return this.deletedIndex ;
  }// getDeletedIndex()

  /**
   * Returns the names of all the available charsets.
   *
   * @return  Array containing the names of all the available
   *       charsets
   *
   * @see    Charset#availableCharsets()
   */
  public static String[] getDefaultCharsets() {
    SortedMap<String, Charset> scs = Charset.availableCharsets() ;
    return scs.keySet().toArray(new String[scs.size()]) ;
  }// getDefaultCharsets()

  /**
   * Sets the charset used to decode the analyzed files and to
   * encode the generated files.
   *
   * @param  charsetName
   *       name of the new charset
   *///TODO Add exception if invalid charset ?
  public void setCharset(String charsetName) {
    if (Charset.isSupported(charsetName)) {
      this.charset = charsetName ;
    }// if
  }// setCharset(String)

  /**
   * Returns the charset used to decode the analyzed files and to
   * encode the generated files.
   *
   * @return  Name of the charset used to encode and decode files
   */
  public String getCharset() {
    return this.charset ;
  }// getCharset()

  /**
   * Returns the file extension. The extension is considered to be any sequence of characters behind the
   * {@code .} in the file name. If the given file is {@code null} or has no extension, {@code null} is returned.
   *
   * @param   file
   *       file whose extension is requested
   *
   * @return   Extension of the given file or {@code null}
   *
   * @see    #getExtension(String)
   */
  public static String getExtension(File file) {
    return getExtension(file.getName()) ;
  }// getExtension(File)

  /**
   * Returns the file extension. The extension is considered to be any sequence of characters behind the
   * {@code .} in the file name. If the given file is {@code null} or has no extension, {@code null} is returned.
   *
   * @param   name
   *       name or path of the file whose extension is requested
   *
   * @return   Extension of the given file or {@code null}
   */
  public static String getExtension(String name) {
    if (name == null) return null ;
    int posDot = name.lastIndexOf('.') ;
    if (posDot == -1) return null ;
    return name.substring(posDot+1) ;
  }// getExtension(String)
 
  /**
   * Indicates if at least one generator is selected.
   *
   * @return  {@code true} if at least one generator is selected,
   *       {@code false} otherwise
   */
  public boolean atLeastOneFormatSelected() {
    return !this.selectedGenerators.isEmpty() ;
  }// atLeastOneFormatSelected()

  /**
   * Adds the given generator to the list of currently selected
   * generators.
   *
   * @param  formatId
   *       id of the added generator
   */
  public void addSelectedFormat(String formatId) {
    if (!this.selectedGenerators.contains(formatId)) {
                        this.selectedGenerators.add(formatId) ;
                }// if
    try {
      this.notifyObservers() ;
    } catch (KameleonException ke) {
      this.displayDebugInformation(ke) ;
    }// try
  }// addSelectedFormat(String)

  /**
   * Removes the given generator to the list of currently selected
   * generators.
   *
   * @param  formatId
   *       id of the removed generator
   */
  public void removeSelectedFormat(String formatId) {
    this.selectedGenerators.remove(formatId) ;
    try {
      this.notifyObservers() ;
    } catch (KameleonException ke) {
      this.displayDebugInformation(ke) ;
    }// try
  }// removeSelectedFormat(String)

  /**
   * Indicates whether is possible to make a generation. A generation
   * is possible if:
   * <ul>
   * <li>a file is selected
   * <li>the format of the selected file is selected
   * <li>at least one generator is selected
   * </ul>
   *
   * @return  {@code true} if is possible to make a generation,
   *       {@code false} otherwise
   */
  public boolean generationIsPossible() {
    return this.fileIsSelected()
        && this.currentFileFormatIsKnown()
        && this.atLeastOneFormatSelected()  ;
  }// generationIsPossible()

  /**
   * Returns all the ids of the selected generators. If no generator
   * is selected, an empty list is returned.
   *
   * @return  instance of {@code List<String>} with all the ids
   *       of the selected generators
   */
  public List<String> getSelectedOutputFormats() {
    return this.selectedGenerators ;
  }// getSelectedOutputFormats()

}// class FileModel
TOP

Related Classes of kameleon.gui.model.FileModel

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.