/*
* funCKit - functional Circuit Kit
* Copyright (C) 2013 Lukas Elsner <open@mindrunner.de>
* Copyright (C) 2013 Peter Dahlberg <catdog2@tuxzone.org>
* Copyright (C) 2013 Julian Stier <mail@julian-stier.de>
* Copyright (C) 2013 Sebastian Vetter <mail@b4sti.eu>
* Copyright (C) 2013 Thomas Poxrucker <poxrucker_t@web.de>
* Copyright (C) 2013 Alexander Treml <alex.treml@directbox.com>
*
* 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 de.sep2011.funckit.model.sessionmodel;
import static com.google.common.base.Preconditions.checkNotNull;
import static de.sep2011.funckit.util.Log.gl;
import java.awt.Cursor;
import java.awt.Point;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import de.sep2011.funckit.Application;
import de.sep2011.funckit.controller.CreateTool;
import de.sep2011.funckit.controller.Tool;
import de.sep2011.funckit.drawer.Drawer;
import de.sep2011.funckit.drawer.FancyDrawer;
import de.sep2011.funckit.model.graphmodel.Brick;
import de.sep2011.funckit.model.graphmodel.Circuit;
import de.sep2011.funckit.model.graphmodel.Element;
import de.sep2011.funckit.model.graphmodel.implementations.CircuitImpl;
import de.sep2011.funckit.model.sessionmodel.EditPanelModel.ToolMode;
import de.sep2011.funckit.model.simulationmodel.Simulation;
import de.sep2011.funckit.observer.AbstractObservable;
import de.sep2011.funckit.observer.SessionModelInfo;
import de.sep2011.funckit.observer.SessionModelObserver;
import de.sep2011.funckit.util.Log;
import de.sep2011.funckit.util.command.CommandDispatcher;
import de.sep2011.funckit.util.internationalization.Language;
import de.sep2011.funckit.validator.Result;
import de.sep2011.funckit.view.View;
/**
* Current session model representing data like project path, current assigned
* editing tool, command dispatcher objects, used drawer object or current
* selected brick for creating new bricks.
*/
public class SessionModel extends AbstractObservable<SessionModelObserver, SessionModelInfo> {
public static enum ViewType {
VIEW_TYPE_STANDALONE, VIEW_TYPE_ELEANING_SOLVE, VIEW_TYPE_PRESENTER;
}
/**
* Defines the current global Cursor of the Application.
*/
private Cursor currentCursor;
/**
* The currently shown projects in the project explorer.
*/
private List<Project> projects;
/**
* The current active project.
*/
private Project currentProject;
/**
* Application window position.
*/
private Point windowPosition;
/**
* Current used tool object, specifying a strategy for mouse- or key actions
* on edit events.
*/
private Tool tool;
/**
* Currently used drawer object, specifying strategy how to accept certain
* elements by double dispatching them.
*/
private Drawer drawer;
/**
* Current selected brick for creating new bricks in create mode.
* {@link CreateTool}
*/
private Brick currentBrick;
private final NewBrickListManager newBrickListManager;
private Circuit copyBuffer;
private Tool lastTool;
private final Settings settings;
private final SessionModel.ViewType currentViewType;
/**
* Create a new SessionModel.
*
* @param application
* the associated {@link Application}
* @param settings
* the associated {@link Settings} object
* @param the
* {@link SessionModel.ViewType} this view should be of, not null
*/
@SuppressWarnings("unchecked")
public SessionModel(Application application, Settings settings, ViewType viewType) {
checkNotNull(viewType);
currentViewType = viewType;
initInfo(SessionModelInfo.getInfo());
this.settings = settings;
/*
* Note: cannot properly check if this is a list of Projects because of
* generics
*/
projects = settings.get(Settings.OPENED_PROJECTS, List.class);
if (projects != null) {
for (Project p : projects) {
p.initializeTransient(settings);
if (p.getName().equals("")) {
p.setName(Language.tr("project.unknown"));
}
}
} else {
projects = new LinkedList<Project>();
}
drawer = new FancyDrawer(settings);
currentCursor = new Cursor(Cursor.DEFAULT_CURSOR);
newBrickListManager = new NewBrickListManager(this,
application.getComponentListDirectory(), application.LoadInternalComponentTypes());
currentBrick = getNewBrickList().get(0);
copyBuffer = new CircuitImpl();
}
/**
* Prepare for exit and inform observers that we want exit.
*/
public void prepareExit() {
Log.gl().info("Clean application exit initiated");
setChanged();
getInfo().setPrepareExit(true);
notifyObserversIfAuto();
}
/**
* Returns the {@link SessionModel.ViewType} this {@link View} is of
*
* @return the currentViewType
*/
public SessionModel.ViewType getViewType() {
return currentViewType;
}
/**
* Returns the settings object associated with this session model.
*
* @return the settings object associated with this session model
*/
public Settings getSettings() {
return settings;
}
/**
* Returns the Project that is currently active.
*
* @return the Project that is currently active, null if no Project is
* Active.
*/
public Project getCurrentProject() {
return currentProject;
}
/**
* Sets the current selected Project of this session.
*
* @param project the current selected Project of this session.
*/
public void setCurrentProject(Project project) {
currentProject = project;
setChanged();
getInfo().setChangedProject(project).setCurrentProjectChanged(true);
notifyObserversIfAuto();
}
/**
* Returns a {@link List} of template Bricks to add to the {@link Circuit}.
*
* @return a {@link List} of template Bricks to add to the {@link Circuit}
*/
public java.util.List<Brick> getNewBrickList() {
return newBrickListManager.getNewBrickList();
}
/**
* Returns the {@link NewBrickListManager} associated with this session.
*
* @return the {@link NewBrickListManager} associated with this session
*/
public NewBrickListManager getNewBrickListManager() {
return newBrickListManager;
}
/**
* Getter method for current window position, stored in model.
*
* @return Current stored window position.
*/
public Point getWindowPosition() {
return windowPosition;
}
/**
* Specifies new window position in session model.
*
* @param windowPosition
* the window position
*/
public void setWindowPosition(Point windowPosition) {
this.windowPosition = windowPosition;
}
/**
* Getter method for current assigned tool object.
*
* @return Tool strategy object.
*/
public Tool getTool() {
return tool;
}
public void forceTool(Tool tool) {
this.tool = tool;
gl().debug("Set tool:" + tool);
/* some cleanup */
for (Project p : projects) {
for (EditPanelModel e : p.getOpenedEditPanelModels()) {
e.setToolMode(ToolMode.DEFAULT_MODE);
Set<Element> gh = e.getGhosts();
gh.clear();
e.setGhosts(gh);
e.setSelectionStart(null);
e.setSelectionEnd(null);
}
}
/* set tools default cursor on all editpanel models */
setCursorOnEditPanels(tool.getToolDefaultCursor());
setChanged();
getInfo().setToolChanged(true);
notifyObserversIfAuto();
}
private void setCursorOnEditPanels(Cursor cursor) {
for (Project project : getProjects()) {
for (EditPanelModel epmodel : project.getOpenedEditPanelModels()) {
epmodel.setCursor(cursor);
}
}
}
/**
* Specifies a new tool object.
*
* @param tool
* a new tool object.
*/
public void setTool(Tool tool) {
assert tool != null;
if (currentProject != null) {
if (currentViewType == ViewType.VIEW_TYPE_PRESENTER || currentProject.hasSimulation()
|| (currentProject.getSelectedEditPanelModel() != null && !currentProject
.getSelectedEditPanelModel().hasMainCircuit())) {
gl().warn("tried to set tool in non edit mode");
return;
}
}
forceTool(tool);
}
/**
* Short for {@link Project#getSimulation()} on {@link #getCurrentProject()}
* .
*
*
* @return current simulation, null if there is none
*/
public Simulation getCurrentSimulation() {
return currentProject != null ? currentProject.getSimulation() : null;
}
/**
* Returns currently assigned drawer object.
*
* @return currently assigned drawer object.
*/
public Drawer getDrawer() {
return drawer;
}
/**
* Specifies a new drawer strategy object.
*
* @param drawer
* a new drawer strategy object
*/
public void setDrawer(Drawer drawer) {
this.drawer = drawer;
}
@Override
public void notifyObserver(SessionModelInfo i, SessionModelObserver obs) {
obs.sessionModelChanged(this, i);
}
/**
* Returns set of results from latest performed set of checks of the current
* project.
*
* @return set of results from latest performed set of checks of the current
* project.
*/
public List<Result> getCurrentCheckResults() {
return currentProject != null ? currentProject.getCheckResults() : null;
}
/**
* Sets current brick to create brick of that type in create mode.
*
* @param currentBrick
* current brick to create brick of that type in create mode
*/
public void setCurrentBrick(Brick currentBrick) {
this.currentBrick = currentBrick;
setChanged();
getInfo().setCurrentBrickChanged(true);
notifyObserversIfAuto();
}
/**
* Returns current selected brick to copy and add it in graph model.
*
* @return the current selected brick to copy and add it in graph model.
*/
public Brick getCurrentBrick() {
return currentBrick;
}
/**
* Returns the current {@link Cursor}.
*
* @return the current {@link Cursor}, not null
*/
public Cursor getCurrentCursor() {
return currentCursor;
}
/**
* Set the {@link Cursor}.
*
* @param currentCursor
* the {@link Cursor}, not null
*/
public void setCurrentCursor(Cursor currentCursor) {
if (!this.currentCursor.equals(currentCursor)) {
this.currentCursor = currentCursor;
setChanged();
}
getInfo().setCursorChanged(true);
notifyObserversIfAuto();
}
/**
* Returns the currently selected {@link EditPanelModel} of the current
* project.
*
* @return the currently selected {@link EditPanelModel}, null if none is
* selected
* @since implementation
*/
public EditPanelModel getSelectedEditPanelModel() {
return currentProject != null ? currentProject.getSelectedEditPanelModel() : null;
}
/**
* Stores a Circuit for copy and paste.
*
* @return never null
*/
public Circuit getCopyBuffer() {
return copyBuffer;
}
/**
* Set copy Buffer.
*
* @param copyBuffer
* not null
*/
public void setCopyBuffer(Circuit copyBuffer) {
assert copyBuffer != null;
gl().debug("Set copyBuffer with " + copyBuffer.getElements().size() + " Elements");
this.copyBuffer = copyBuffer;
setChanged();
getInfo().setCopyBufferChanged(true);
notifyObserversIfAuto();
}
/**
* Saves the current {@link Tool} if no {@link Tool} was saved before.
*/
public void saveTool() {
if (lastTool == null) {
lastTool = tool;
gl().debug("Saved tool : " + tool);
}
}
/**
* Returns true if the {@link Tool} was saved before and not restored.
*
* @return true if the {@link Tool} was saved before and not restored.
*/
public boolean isToolSaved() {
return lastTool != null;
}
/**
* Restores the {@link Tool} to the saved {@link Tool} and deletes the saved
* one. If no {link Tool} was saved nothing is done.
*
* @return the restored {@link Tool}.
*/
public Tool restoreTool() {
if (currentProject != null) {
if (currentViewType == ViewType.VIEW_TYPE_PRESENTER || currentProject.hasSimulation()
|| (currentProject.getSelectedEditPanelModel() != null && !currentProject
.getSelectedEditPanelModel().hasMainCircuit())) {
gl().warn("tried to restore tool in non edit mode");
return tool;
}
}
if (lastTool != null) {
setTool(lastTool);
lastTool = null;
gl().debug("Restored tool: " + tool);
}
return tool;
}
/**
* Adds a Project to the model.
*
* @param p
* a Project, not null
*/
public void addProject(Project p) {
projects.add(p);
persistProjects();
setChanged();
getInfo().setChangedProject(p).setProjectAdded(true);
notifyObserversIfAuto();
}
/**
* Removes a Project from the model.
*
* @param p
* a Project inside the model, not null
*/
public void removeProject(Project p) {
projects.remove(p);
if (p == currentProject) {
currentProject = null;
}
persistProjects();
setChanged();
getInfo().setChangedProject(p).setProjectRemoved(true);
notifyObserversIfAuto();
}
/**
* Persists the projects into the settings.
*/
public void persistProjects() {
List<Project> persistentProjects = new LinkedList<Project>();
for (Project persistentProject : projects) {
if (persistentProject.getAbsolutePath() != null
&& !persistentProject.getAbsolutePath().equals("")) {
persistentProjects.add(persistentProject);
}
}
settings.set(Settings.OPENED_PROJECTS, persistentProjects); // update
// settings
}
/**
* Gets the list of currently opened {@link Project}s. Warning! This is a
* reference to the internal used list. Do not modify.
*
* @return the list of currently opened {@link Project}s.
*/
public List<Project> getProjects() {
return projects;
}
/**
* Returns the current Circuit {@link CommandDispatcher} from the Project.
*
* @return the current Circuit {@link CommandDispatcher}, null if there is
* none
*/
public CommandDispatcher getCurrentGraphCommandDispatcher() {
return currentProject != null ? currentProject.getGraphCommandDispatcher() : null;
}
/**
* Returns the current Simulation {@link CommandDispatcher} from the
* Project.
*
* @return the current Simulation {@link CommandDispatcher}, null if there
* is none
*/
public CommandDispatcher getCurrentSimulationCommandDispatcher() {
return currentProject != null ? currentProject.getSimulationCommandDispatcher() : null;
}
/**
* Returns the Path of the current Project.
*
* @return the Path of the current Project, null if there is none
*/
public String getCurrentProjectPath() {
return currentProject != null ? currentProject.getAbsolutePath() : null;
}
}