Java tutorial
/** * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.datavyu.controllers.project; import org.datavyu.models.db.DatastoreFactory; import java.io.File; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.filechooser.FileFilter; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.filefilter.FileFilterUtils; import org.apache.commons.io.filefilter.IOFileFilter; import org.apache.commons.io.filefilter.TrueFileFilter; import org.jdesktop.application.Application; import org.jdesktop.application.ResourceMap; import org.datavyu.Datavyu; import org.datavyu.controllers.component.MixerController; import org.datavyu.controllers.id.IDController; import org.datavyu.models.component.TrackModel; import org.datavyu.models.project.Project; import org.datavyu.models.project.TrackSettings; import org.datavyu.models.project.ViewerSetting; import org.datavyu.plugins.PluginManager; import org.datavyu.util.OFileUtils; import org.datavyu.views.DataControllerV; import com.google.common.collect.Lists; import org.datavyu.models.db.Cell; import org.datavyu.models.db.Datastore; import org.datavyu.models.db.Variable; import org.datavyu.plugins.DataViewer; import org.datavyu.plugins.Plugin; /** * This class is responsible for managing a project. */ public final class ProjectController { /** The current project we are working on. */ private Project project; /** The current database we are working on. */ private Datastore db = null; /** The last cell that was created. */ private Cell lastCreatedCell; /** The last cell that was selected. */ private Cell lastSelectedCell; /** The last variable that was created. */ private Variable lastCreatedVariable; /** * Controller state */ /** has the project been changed since it was created. */ private boolean changed; /** Is the project new? */ private boolean newProject; /** Last option used for saving. */ private FileFilter lastSaveOption; /** * Default constructor. */ public ProjectController() { project = new Project(); db = DatastoreFactory.newDatastore(); db.setTitleNotifier(Datavyu.getApplication()); changed = false; newProject = true; lastCreatedCell = null; lastSelectedCell = null; lastCreatedVariable = null; } public ProjectController(final Project project) { this.project = project; changed = false; newProject = false; lastCreatedCell = null; lastSelectedCell = null; lastCreatedVariable = null; } /** * Set the last save option used. This affects the "Save" functionality. * * @param saveOption The latest option used for "saving". */ public void setLastSaveOption(final FileFilter saveOption) { lastSaveOption = saveOption; } /** * @return The last "saved" option used when saving. */ public FileFilter getLastSaveOption() { return lastSaveOption; } public void createNewProject(final String name) { project = new Project(); setProjectName(name); changed = false; newProject = true; } /** * Sets the name of the project. * * @param newProjectName * The new name to use for this project. */ public void setProjectName(final String newProjectName) { project.setProjectName(newProjectName); } /** * Gets the MacshapaDatabase associated with this project. Should eventually * be replaced with a Datastore. * * @return The single database to use with this project. */ public Datastore getDB() { return db; } /** * Sets the datastore to use with this project. This is used when loading a * database from file. * * @param newDS The new datastore we are using. */ public void setDatastore(final Datastore newDS) { db = newDS; db.setTitleNotifier(Datavyu.getApplication()); } /** * @return The last cell created for the datastore. */ public Cell getLastCreatedCell() { return lastCreatedCell; } /** * Sets the last created cell to the specified parameter. * * @param newCell The newly created cell. */ public void setLastCreatedCell(final Cell newCell) { lastCreatedCell = newCell; } /** * @return The last selected cell. */ public Cell getLastSelectedCell() { return lastSelectedCell; } /** * Sets the last selected cell to the specified cell. * * @param newCell The newly selected cell. */ public void setLastSelectedCell(final Cell newCell) { lastSelectedCell = newCell; } /** * @return The last variable created for the datastore. */ public Variable getLastCreatedVariable() { return lastCreatedVariable; } /** * Sets the newly created variable to the specified parameter. * * @param newVariable The newly created variable. */ public void setLastCreatedVariable(final Variable newVariable) { lastCreatedVariable = newVariable; } /** * @return the changed */ public boolean isChanged() { return (changed || ((db != null) && db.isChanged())); } /** * @return the newProject */ public boolean isNewProject() { return newProject; } /** * @return the project name */ public String getProjectName() { return project.getProjectName(); } /** * Set the database file name, directory not included. * * @param fileName */ public void setDatabaseFileName(final String fileName) { project.setDatabaseFileName(fileName); } /** * @return the database file name, directory not included. */ public String getDatabaseFileName() { return project.getDatabaseFileName(); } /** * Set the directory the project file (and all project specific resources) * resides in. * * @param directory */ public void setProjectDirectory(final String directory) { project.setProjectDirectory(directory); } /** * @return the directory the project file (and all project specific * resources) resides in. */ public String getProjectDirectory() { return project.getProjectDirectory(); } public void setOriginalProjectDirectory(final String directory) { project.setOriginalProjectDirectory(directory); } public String getOriginalProjectDirectory() { return project.getOriginalProjectDirectory(); } /** * Load the settings from the current project. */ public void loadProject() { // Use the plugin manager to load up the data viewers PluginManager pm = PluginManager.getInstance(); DataControllerV dataController = Datavyu.getDataController(); // Load the plugins required for each media file boolean showController = false; List<String> missingFilesList = Lists.newLinkedList(); List<String> missingPluginList = Lists.newLinkedList(); final MixerController mixerController = dataController.getMixerController(); // Load the viewer settings. for (ViewerSetting setting : project.getViewerSettings()) { showController = true; File file = new File(setting.getFilePath()); File currentDir = new File(project.getProjectDirectory()); String dataFileName = FilenameUtils.getName(setting.getFilePath()); if (!file.exists()) { // Look for a file by generating OS-independent paths. File searchedFile = genRelative(project.getOriginalProjectDirectory(), setting.getFilePath(), project.getProjectDirectory()); if (searchedFile != null) { file = searchedFile; } } if (!file.exists()) { // Look for a file that _might_ be the file we are looking for. // This is a brute force search. Ideally we would never want to // do this. File searchedFile = huntForFile(currentDir, dataFileName); if (searchedFile != null) { file = searchedFile; } } // The file is actually missing. if (!file.exists()) { missingFilesList.add(setting.getFilePath()); continue; } Plugin plugin = pm.getAssociatedPlugin(setting.getPluginName()); // BugzID:2110 if ((plugin == null) && (setting.getPluginClassifier() != null)) { plugin = pm.getCompatiblePlugin(setting.getPluginClassifier(), file); } if (plugin == null) { // Record missing plugin. missingPluginList.add(setting.getPluginName()); continue; } final DataViewer viewer = plugin.getNewDataViewer(Datavyu.getApplication().getMainFrame(), false); viewer.setIdentifier(IDController.generateIdentifier()); if (setting.getSettingsId() != null) { // new project file viewer.loadSettings(setting.getSettingsInputStream()); } else { // old project file viewer.setOffset(setting.getOffset()); } viewer.setDataFeed(file); viewer.setDatastore(db); dataController.addViewer(viewer, viewer.getOffset()); dataController.addTrack(viewer.getIdentifier(), plugin.getTypeIcon(), file.getAbsolutePath(), file.getName(), viewer.getDuration(), viewer.getOffset(), viewer.getTrackPainter()); if (setting.getTrackSettings() != null) { final TrackSettings ts = setting.getTrackSettings(); mixerController.setTrackInterfaceSettings(viewer.getIdentifier(), ts.getBookmarkPositions(), ts.isLocked()); } mixerController.bindTrackActions(viewer.getIdentifier(), viewer.getCustomActions()); viewer.addViewerStateListener( mixerController.getTracksEditorController().getViewerStateListener(viewer.getIdentifier())); } // Do not remove; this is here for backwards compatibility. for (TrackSettings setting : project.getTrackSettings()) { File file = new File(setting.getFilePath()); if (!file.exists()) { // Look for a file by generating OS-independent paths. // This is not guaranteed for older project file formats. File searchedFile = genRelative(project.getOriginalProjectDirectory(), setting.getFilePath(), project.getProjectDirectory()); if (searchedFile != null) { file = searchedFile; } } if (!file.exists()) { // BugzID:1804 - If absolute path does not find the file, look // in the relative path (as long as we are dealing with a newer // project file type). if (project.getOriginalProjectDirectory() != null) { File searchedFile = huntForFile(new File(project.getProjectDirectory()), file.getName()); if (searchedFile != null) { file = searchedFile; } } } if (!file.exists()) { missingFilesList.add(setting.getFilePath()); continue; } mixerController.setTrackInterfaceSettings(setting.getFilePath(), setting.getBookmarkPositions(), setting.isLocked()); } if (!missingFilesList.isEmpty() || !missingPluginList.isEmpty()) { JFrame mainFrame = Datavyu.getApplication().getMainFrame(); ResourceMap rMap = Application.getInstance(Datavyu.class).getContext().getResourceMap(Datavyu.class); StringBuilder sb = new StringBuilder(); if (!missingFilesList.isEmpty()) { sb.append("The following files are missing:\n\n"); for (String filePath : missingFilesList) { sb.append(filePath); sb.append('\n'); } } if (!missingPluginList.isEmpty()) { if (sb.length() != 0) { sb.append('\n'); } sb.append("The following plugins are missing:\n\n"); for (String pluginName : missingPluginList) { sb.append(pluginName); sb.append('\n'); } } JOptionPane.showMessageDialog(mainFrame, sb.toString(), rMap.getString("ProjectLoadError.title"), JOptionPane.WARNING_MESSAGE); showController = true; } // Show the data controller if (showController) { Datavyu.getApplication().showDataController(); } } /** * Gather and update the various project specific settings. */ public void updateProject() { DataControllerV dataController = Datavyu.getDataController(); // Gather the data viewer settings List<ViewerSetting> viewerSettings = new LinkedList<ViewerSetting>(); int settingsId = 1; for (DataViewer viewer : dataController.getDataViewers()) { ViewerSetting vs = new ViewerSetting(); vs.setFilePath(viewer.getDataFeed().getAbsolutePath()); vs.setPluginName(viewer.getClass().getName()); // BugzID:2108 Plugin p = PluginManager.getInstance().getAssociatedPlugin(vs.getPluginName()); assert p.getClassifier() != null; assert !"".equals(p.getClassifier()); vs.setPluginClassifier(p.getClassifier()); // BugzID:1806 vs.setSettingsId(Integer.toString(settingsId++)); viewer.storeSettings(vs.getSettingsOutputStream()); // BugzID:2107 TrackModel tm = dataController.getMixerController().getTrackModel(viewer.getIdentifier()); TrackSettings ts = new TrackSettings(); ts.setBookmarkPositions(tm.getBookmarks()); ts.setLocked(tm.isLocked()); vs.setTrackSettings(ts); viewerSettings.add(vs); } project.setViewerSettings(viewerSettings); } /** * Marks the project state as being saved. */ public void markProjectAsUnchanged() { changed = false; newProject = false; } /** * Marks the project as being changed. This method will not trigger a * project state update. */ public void projectChanged() { changed = true; Datavyu.getApplication().updateTitle(); } /** * @return the current project model. */ public Project getProject() { return project; } private File genRelative(final String originalDir, final String originalFilePath, final String currentDir) { // 1. Find the longest common directory for the original dir and // original file path. String baseLCD = OFileUtils.longestCommonDir(originalDir, originalFilePath); if (baseLCD == null) { return null; } // 2. Use the longest common directory to find the difference in // directory levels with the original directory. The LCD is the original // base dir. int diff = OFileUtils.levelDifference(baseLCD, originalDir); if (diff == -1) { return null; } // 3. Use the difference in levels to generate a new base directory // using the current directory. File newBase = new File(currentDir); while (diff > 0) { newBase = newBase.getParentFile(); if (newBase == null) { return null; } diff--; } // 4. Find the path relative to the original base directory for the // original file path. String rel = OFileUtils.relativeToBase(baseLCD, originalFilePath); if (rel == null) { return null; } // 5. Combine the relative path with the current base dir and return // that as the file to try. return new File(newBase, rel); } private File huntForFile(final File workingDir, final String fileName) { // If we can't find the file, we will start looking for the file // using the easiest solution first and bump up the complexity as // we go along. // Solution 1: It is in the same directory as the project file. File file = new File(workingDir, fileName); if (file.exists()) { return file; } IOFileFilter fileNameFilter = FileFilterUtils.nameFileFilter(fileName); // Solution 2: It is in a sub-directory of the project file. { Iterator<File> subFiles = FileUtils.iterateFiles(workingDir, fileNameFilter, TrueFileFilter.TRUE); if (subFiles.hasNext()) { file = subFiles.next(); } if (file.exists()) { return file; } } // Solution 3: It is in the parent of the current directory. { Iterator<File> subFiles = FileUtils.iterateFiles(workingDir.getParentFile(), fileNameFilter, null); if (subFiles.hasNext()) { file = subFiles.next(); } if (file.exists()) { return file; } } return null; } }