/******************************************************************************* * See the NOTICE file distributed with this work for additional information * regarding copyright ownership. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package hr.fer.zemris.vhdllab.applets.editor.schema2.model; import hr.fer.zemris.vhdllab.applets.editor.schema2.enums.EPropertyChange; import hr.fer.zemris.vhdllab.applets.editor.schema2.exceptions.CommandExecutorException; import hr.fer.zemris.vhdllab.applets.editor.schema2.exceptions.InvalidCommandOperationException; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ICommand; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ICommandResponse; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.IQuery; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.IQueryResult; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaController; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaCore; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaInfo; import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.ChangeTuple; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; /** * Lokalni kontroler - pretpostavlja * da su model i view unutar istog procesa. * * @author Axel * */ public class LocalController implements ISchemaController { /* static fields */ private static final int COMMAND_STACK_SIZE = 30; /* private fields */ private PropertyChangeSupport support; private ISchemaCore core; private LinkedList<ICommand> undolist; private LinkedList<ICommand> redolist; private Map<IQuery, IQueryResult> querycache; private Map<EPropertyChange, List<IQuery>> queryindex; /* ctors */ public LocalController() { support = new PropertyChangeSupport(this); core = null; undolist = new LinkedList<ICommand>(); redolist = new LinkedList<ICommand>(); querycache = new HashMap<IQuery, IQueryResult>(); queryindex = new HashMap<EPropertyChange, List<IQuery>>(); } public LocalController(ISchemaCore coreToSendTo) { support = new PropertyChangeSupport(this); core = coreToSendTo; undolist = new LinkedList<ICommand>(); redolist = new LinkedList<ICommand>(); querycache = new HashMap<IQuery, IQueryResult>(); queryindex = new HashMap<EPropertyChange, List<IQuery>>(); } /* methods */ public void registerCore(ISchemaCore coreToSendTo) { core = coreToSendTo; } public void addListener(EPropertyChange changeType, PropertyChangeListener listener) { changeType.assignListenerToSupport(listener, support); } public void removeListener(PropertyChangeListener listener) { support.removePropertyChangeListener(listener); } // public void handleChanges(List<ChangeTuple> changes) { // if (changes != null) { // for (ChangeTuple change : changes) { // change.changetype.firePropertyChanges(support, change.oldval, change.oldval); // } // } // } public ISchemaInfo getSchemaInfo() { return core.getSchemaInfo(); } public ICommandResponse send(ICommand command) { ICommandResponse response = core.executeCommand(command); if (response.isSuccessful()) { redolist.clear(); if (command.isUndoable()) { undolist.add(command); if (undolist.size() > COMMAND_STACK_SIZE) undolist.removeFirst(); } else { undolist.clear(); } } reportChanges(response); return response; } public IQueryResult send(IQuery query) { boolean iscacheable = query.isCacheable(); IQueryResult queryresult = (iscacheable) ? (querycache.get(query)) : (null); if (queryresult != null) return queryresult; queryresult = query.performQuery(core.getSchemaInfo()); // cache query if successful if (queryresult.isSuccessful() && iscacheable) { querycache.put(query, queryresult); List<EPropertyChange> propdeps = query.getPropertyDependency(); for (EPropertyChange propdep : propdeps) { List<IQuery> qlist = queryindex.get(propdep); if (qlist == null) { qlist = new ArrayList<IQuery>(); queryindex.put(propdep, qlist); } qlist.add(query); } } return queryresult; } private void clearCacheFor(EPropertyChange propchange) { List<IQuery> tobedel = queryindex.get(propchange); if (tobedel == null) return; for (IQuery q : tobedel) { querycache.remove(q); } tobedel.clear(); } private void reportChanges(ICommandResponse response) { List<ChangeTuple> changes = response.getPropertyChanges(); if (changes != null) for (ChangeTuple ct : changes) { ct.changetype.firePropertyChanges(support, ct.oldval, ct.newval); clearCacheFor(ct.changetype); } } public boolean canRedo() { return (!redolist.isEmpty()); } public boolean canUndo() { return (!undolist.isEmpty() && undolist.get(undolist.size() - 1).isUndoable()); } public List<String> getRedoList() { List<String> list = new LinkedList<String>(); for (ICommand comm : redolist) { list.add(comm.getCommandName()); } return list; } public List<String> getUndoList() { List<String> list = new LinkedList<String>(); for (ICommand comm : undolist) { list.add(comm.getCommandName()); } return list; } public ICommandResponse redo() throws CommandExecutorException { if (redolist.isEmpty()) throw new CommandExecutorException("Empty redo command stack."); ICommand comm = redolist.getLast(); redolist.removeLast(); ICommandResponse response = core.executeCommand(comm); if (!response.isSuccessful()) { undolist.clear(); redolist.clear(); throw new CommandExecutorException("Cannot redo command."); } undolist.add(comm); reportChanges(response); return response; } public ICommandResponse undo() throws CommandExecutorException { if (undolist.isEmpty()) throw new CommandExecutorException("Empty undo command stack."); ICommand comm = undolist.getLast(); undolist.removeLast(); ICommandResponse response; try { response = core.undoCommand(comm); } catch (InvalidCommandOperationException e) { throw new CommandExecutorException(e); } if (!response.isSuccessful()) { undolist.clear(); redolist.clear(); throw new CommandExecutorException("Cannot undo command. Reason: " + response.getError().toString()); } redolist.add(comm); reportChanges(response); return response; } public void clearCommandCache() { undolist.clear(); redolist.clear(); } public void clearQueryCache() { querycache.clear(); queryindex.clear(); } }