checks for file modifications

This commit is contained in:
bancika
2011-01-15 14:04:33 +00:00
parent d16ee1d890
commit 52df431beb
8 changed files with 248 additions and 52 deletions
@@ -26,6 +26,12 @@ public enum EventType {
* or loaded with undo/redo operations. * or loaded with undo/redo operations.
*/ */
PROJECT_LOADED, PROJECT_LOADED,
/**
* Called when either current file name or modified flag are changed. The
* first parameter is the current file name, the second one is a boolean
* modified flag.
*/
FILE_STATUS_CHANGED,
/** /**
* Called when selection rectangle is changed. Object of type * Called when selection rectangle is changed. Object of type
* {@link Rectangle} is the only parameter and it contains the new selection * {@link Rectangle} is the only parameter and it contains the new selection
@@ -74,6 +74,18 @@ public interface IPlugInPort {
*/ */
void loadProject(Project project, boolean freshStart); void loadProject(Project project, boolean freshStart);
void createNewProject();
void loadProjectFromFile(String fileName);
void saveProjectToFile(String fileName);
String getCurrentFileName();
boolean isProjectModified();
boolean allowFileAction();
/** /**
* Returns all available {@link ComponentType}s classified by category. * Returns all available {@link ComponentType}s classified by category.
* Result is a {@link Map} between category name to a {@link List} of all * Result is a {@link Map} between category name to a {@link List} of all
@@ -45,8 +45,8 @@ public class Project implements Serializable {
gridSpacing = DEFAULT_GRID_SPACING; gridSpacing = DEFAULT_GRID_SPACING;
} }
public Project(String title, String author, String description, Size width, Size height, Size gridSpacing, public Project(String title, String author, String description, Size width, Size height,
List<IDIYComponent<?>> components, Set<Set<IDIYComponent<?>>> groups) { Size gridSpacing, List<IDIYComponent<?>> components, Set<Set<IDIYComponent<?>>> groups) {
super(); super();
this.title = title; this.title = title;
this.author = author; this.author = author;
@@ -103,7 +103,7 @@ public class Project implements Serializable {
this.height = height; this.height = height;
} }
@EditableProperty @EditableProperty(name = "Grid spacing")
public Size getGridSpacing() { public Size getGridSpacing() {
return gridSpacing; return gridSpacing;
} }
@@ -47,4 +47,8 @@ public interface IView {
* @param parentMenuName * @param parentMenuName
*/ */
void addSubmenu(String name, Icon icon, String parentMenuName); void addSubmenu(String name, Icon icon, String parentMenuName);
void showMessage(String message, String title, int messageType);
int showConfirmDialog(String message, String title, int optionType, int messageType);
} }
@@ -7,6 +7,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent; import java.awt.event.WindowEvent;
import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -17,12 +18,15 @@ import javax.swing.JComponent;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.JMenu; import javax.swing.JMenu;
import javax.swing.JMenuBar; import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
import javax.swing.Timer; import javax.swing.Timer;
import org.diylc.common.BadPositionException; import org.diylc.common.BadPositionException;
import org.diylc.core.Project; import org.diylc.common.EventType;
import org.diylc.common.IPlugIn;
import org.diylc.common.IPlugInPort;
import org.diylc.plugins.canvas.CanvasPlugin; import org.diylc.plugins.canvas.CanvasPlugin;
import org.diylc.plugins.clipboard.ClipboardManager; import org.diylc.plugins.clipboard.ClipboardManager;
import org.diylc.plugins.file.FileManager; import org.diylc.plugins.file.FileManager;
@@ -50,7 +54,7 @@ public class MainFrame extends JFrame implements IView {
public MainFrame() { public MainFrame() {
super("DIYLC 3"); super("DIYLC 3");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
setPreferredSize(new Dimension(800, 600)); setPreferredSize(new Dimension(800, 600));
createBasePanels(); createBasePanels();
menuMap = new HashMap<String, JMenu>(); menuMap = new HashMap<String, JMenu>();
@@ -58,8 +62,6 @@ public class MainFrame extends JFrame implements IView {
this.presenter = new Presenter(this); this.presenter = new Presenter(this);
setTitle(getTitle() + " v." + presenter.getCurrentVersionNumber());
presenter.installPlugin(new ToolBox()); presenter.installPlugin(new ToolBox());
presenter.installPlugin(new FileManager()); presenter.installPlugin(new FileManager());
presenter.installPlugin(new ClipboardManager()); presenter.installPlugin(new ClipboardManager());
@@ -69,21 +71,28 @@ public class MainFrame extends JFrame implements IView {
presenter.installPlugin(new StatusBar()); presenter.installPlugin(new StatusBar());
canvasPlugin = new CanvasPlugin(); canvasPlugin = new CanvasPlugin();
presenter.installPlugin(canvasPlugin); presenter.installPlugin(canvasPlugin);
presenter.installPlugin(new FramePlugin());
Project project = new Project(); presenter.createNewProject();
// project.getComponents().add(new MockDIYComponent());
presenter.loadProject(project, true);
addWindowListener(new WindowAdapter() { addWindowListener(new WindowAdapter() {
@Override @Override
public void windowClosed(WindowEvent e) { public void windowClosed(WindowEvent e) {
presenter.dispose(); if (presenter.allowFileAction()) {
dispose();
presenter.dispose();
System.exit(0);
}
} }
@Override @Override
public void windowClosing(WindowEvent e) { public void windowClosing(WindowEvent e) {
presenter.dispose(); if (presenter.allowFileAction()) {
dispose();
presenter.dispose();
System.exit(0);
}
} }
}); });
@@ -195,6 +204,16 @@ public class MainFrame extends JFrame implements IView {
menuMap.put(name, submenu); menuMap.put(name, submenu);
} }
@Override
public void showMessage(String message, String title, int messageType) {
JOptionPane.showMessageDialog(this, message, title, messageType);
}
@Override
public int showConfirmDialog(String message, String title, int optionType, int messageType) {
return JOptionPane.showConfirmDialog(this, message, title, optionType, messageType);
}
private JMenu findOrCreateMenu(String menuName) { private JMenu findOrCreateMenu(String menuName) {
JMenu menu; JMenu menu;
if (menuMap.containsKey(menuName)) { if (menuMap.containsKey(menuName)) {
@@ -206,4 +225,31 @@ public class MainFrame extends JFrame implements IView {
} }
return menu; return menu;
} }
class FramePlugin implements IPlugIn {
private IPlugInPort plugInPort;
@Override
public void connect(IPlugInPort plugInPort) {
this.plugInPort = plugInPort;
}
@Override
public EnumSet<EventType> getSubscribedEventTypes() {
return EnumSet.of(EventType.FILE_STATUS_CHANGED);
}
@Override
public void processMessage(EventType eventType, Object... params) {
if (eventType == EventType.FILE_STATUS_CHANGED) {
String fileName = plugInPort.getCurrentFileName() == null ? "Untitled" : plugInPort
.getCurrentFileName();
String modified = plugInPort.isProjectModified() ? " (modified)" : "";
setTitle(String.format("DIYLC 3.%s - %s %s", plugInPort.getCurrentVersionNumber(),
fileName, modified));
}
}
}
} }
@@ -2,7 +2,6 @@ package org.diylc.plugins.file;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
@@ -15,7 +14,6 @@ import org.apache.log4j.Logger;
import org.diylc.common.EventType; import org.diylc.common.EventType;
import org.diylc.common.IPlugIn; import org.diylc.common.IPlugIn;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.core.Project;
import org.diylc.gui.DialogFactory; import org.diylc.gui.DialogFactory;
import org.diylc.images.IconLoader; import org.diylc.images.IconLoader;
@@ -79,8 +77,10 @@ public class FileManager implements IPlugIn {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
LOG.info("Creating blank project."); if (!plugInPort.allowFileAction()) {
plugInPort.loadProject(new Project(), true); return;
}
plugInPort.createNewProject();
} }
} }
@@ -96,23 +96,13 @@ public class FileManager implements IPlugIn {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (!plugInPort.allowFileAction()) {
return;
}
File file = DialogFactory.getInstance().showOpenDialog(FileFilterEnum.DIY.getFilter(), File file = DialogFactory.getInstance().showOpenDialog(FileFilterEnum.DIY.getFilter(),
null, FileFilterEnum.DIY.getExtensions()[0], new ProjectPreview()); null, FileFilterEnum.DIY.getExtensions()[0], new ProjectPreview());
if (file != null) { if (file != null) {
LOG.info("Loading project from file."); plugInPort.loadProjectFromFile(file.getAbsolutePath());
FileInputStream fis;
try {
fis = new FileInputStream(file);
Project project = (Project) xStream.fromXML(fis);
plugInPort.loadProject(project, true);
fis.close();
} catch (FileNotFoundException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
} catch (IOException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}
} }
} }
} }
@@ -277,7 +267,9 @@ public class FileManager implements IPlugIn {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
System.exit(0); if (plugInPort.allowFileAction()) {
System.exit(0);
}
} }
} }
@@ -64,6 +64,16 @@ public class ProjectPreview extends JPanel implements PropertyChangeListener, IF
@Override @Override
public void addSubmenu(String name, Icon icon, String parentMenuName) { public void addSubmenu(String name, Icon icon, String parentMenuName) {
} }
@Override
public int showConfirmDialog(String message, String title, int optionType,
int messageType) {
return 0;
}
@Override
public void showMessage(String message, String title, int messageType) {
}
}); });
xStream = new XStream(new DomDriver()); xStream = new XStream(new DomDriver());
@@ -137,12 +147,12 @@ public class ProjectPreview extends JPanel implements PropertyChangeListener, IF
zoomRatio = rect.getHeight() / d.getHeight(); zoomRatio = rect.getHeight() / d.getHeight();
} }
// d.setSize(d.getWidth() * zoomRatio, d.getHeight() * zoomRatio); // d.setSize(d.getWidth() * zoomRatio, d.getHeight() * zoomRatio);
// int x = (int) (rect.getWidth() - d.getWidth() * zoomRatio) / 2; // int x = (int) (rect.getWidth() - d.getWidth() * zoomRatio) / 2;
// int y = (int) (rect.getHeight() - d.getHeight() * zoomRatio) / 2; // int y = (int) (rect.getHeight() - d.getHeight() * zoomRatio) / 2;
// System.out.println(x + "," + y); // System.out.println(x + "," + y);
// g2d.translate(x, y); // g2d.translate(x, y);
g2d.scale(zoomRatio, zoomRatio); g2d.scale(zoomRatio, zoomRatio);
presenter.draw(g2d, EnumSet.noneOf(DrawOption.class), null); presenter.draw(g2d, EnumSet.noneOf(DrawOption.class), null);
@@ -10,6 +10,11 @@ import java.awt.Rectangle;
import java.awt.RenderingHints; import java.awt.RenderingHints;
import java.awt.geom.Area; import java.awt.geom.Area;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@@ -24,6 +29,7 @@ import java.util.Set;
import javax.swing.Action; import javax.swing.Action;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JOptionPane;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.diylc.common.BadPositionException; import org.diylc.common.BadPositionException;
@@ -48,6 +54,8 @@ import com.diyfever.gui.miscutils.Utils;
import com.diyfever.gui.simplemq.MessageDispatcher; import com.diyfever.gui.simplemq.MessageDispatcher;
import com.diyfever.gui.update.VersionNumber; import com.diyfever.gui.update.VersionNumber;
import com.rits.cloning.Cloner; import com.rits.cloning.Cloner;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
/** /**
* The main presenter class, contains core app logic and drawing routines. * The main presenter class, contains core app logic and drawing routines.
@@ -70,6 +78,8 @@ public class Presenter implements IPlugInPort {
private double zoomLevel = 1; private double zoomLevel = 1;
private Map<IDIYComponent<?>, Area> componentAreaMap; private Map<IDIYComponent<?>, Area> componentAreaMap;
private Project currentProject; private Project currentProject;
private String currentFileName = null;
private boolean modified = false;
private Map<String, List<ComponentType>> componentTypes; private Map<String, List<ComponentType>> componentTypes;
// Maps component class names to ComponentType objects. // Maps component class names to ComponentType objects.
private Map<String, ComponentType> componentTypeMap; private Map<String, ComponentType> componentTypeMap;
@@ -80,7 +90,9 @@ public class Presenter implements IPlugInPort {
// that designate which of their control points are being dragged. // that designate which of their control points are being dragged.
private Map<IDIYComponent<?>, Set<Integer>> controlPointMap; private Map<IDIYComponent<?>, Set<Integer>> controlPointMap;
// Utilities
private Cloner cloner; private Cloner cloner;
private XStream xStream = new XStream(new DomDriver());
private Rectangle selectionRect; private Rectangle selectionRect;
@@ -187,6 +199,82 @@ public class Presenter implements IPlugInPort {
messageDispatcher.dispatchMessage(EventType.REPAINT); messageDispatcher.dispatchMessage(EventType.REPAINT);
} }
@Override
public void createNewProject() {
LOG.info("createNewFile()");
try {
Project project = new Project();
setDefaultProperties(project);
loadProject(project, true);
this.currentFileName = null;
this.modified = false;
fireFileStatusChanged();
} catch (Exception e) {
LOG.error("Could not create new file", e);
}
}
@Override
public void loadProjectFromFile(String fileName) {
LOG.info(String.format("loadProjectFromFile(%s)", fileName));
try {
FileInputStream fis = new FileInputStream(fileName);
Project project = (Project) xStream.fromXML(fis);
loadProject(project, true);
fis.close();
this.currentFileName = fileName;
this.modified = false;
fireFileStatusChanged();
} catch (FileNotFoundException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
} catch (IOException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}
}
@Override
public boolean allowFileAction() {
if (this.modified) {
int response = view.showConfirmDialog(
"There are unsaved changes. Are you sure you want to abandon these changes?",
"Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
return response == JOptionPane.YES_OPTION;
}
return true;
}
@Override
public void saveProjectToFile(String fileName) {
LOG.info(String.format("saveProjectToFile(%s)", fileName));
FileOutputStream fos;
try {
fos = new FileOutputStream(fileName);
xStream.toXML(currentProject, fos);
fos.close();
this.currentFileName = fileName;
this.modified = false;
fireFileStatusChanged();
} catch (FileNotFoundException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
} catch (IOException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}
}
@Override
public String getCurrentFileName() {
return this.currentFileName;
}
@Override
public boolean isProjectModified() {
return this.modified;
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public Map<String, List<ComponentType>> getComponentTypes() { public Map<String, List<ComponentType>> getComponentTypes() {
@@ -699,6 +787,7 @@ public class Presenter implements IPlugInPort {
if (!preDragProject.equals(currentProject)) { if (!preDragProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, preDragProject, cloner messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, preDragProject, cloner
.deepClone(currentProject), "Move"); .deepClone(currentProject), "Move");
fireFileStatusChanged();
} }
fireSelectionChanged(); fireSelectionChanged();
messageDispatcher.dispatchMessage(EventType.REPAINT); messageDispatcher.dispatchMessage(EventType.REPAINT);
@@ -714,18 +803,26 @@ public class Presenter implements IPlugInPort {
} }
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner
.deepClone(currentProject), "Add"); .deepClone(currentProject), "Add");
this.modified = true;
fireFileStatusChanged();
messageDispatcher.dispatchMessage(EventType.REPAINT); messageDispatcher.dispatchMessage(EventType.REPAINT);
} }
@Override @Override
public void deleteSelectedComponents() { public void deleteSelectedComponents() {
LOG.debug("deleteSelectedComponents()"); LOG.debug("deleteSelectedComponents()");
if (selectedComponents.isEmpty()) {
LOG.debug("Nothing to delete");
return;
}
Project oldProject = cloner.deepClone(currentProject); Project oldProject = cloner.deepClone(currentProject);
// Remove selected components from any groups. // Remove selected components from any groups.
ungroupComponents(selectedComponents); ungroupComponents(selectedComponents);
currentProject.getComponents().removeAll(selectedComponents); currentProject.getComponents().removeAll(selectedComponents);
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner
.deepClone(currentProject), "Delete"); .deepClone(currentProject), "Delete");
this.modified = true;
fireFileStatusChanged();
messageDispatcher.dispatchMessage(EventType.REPAINT); messageDispatcher.dispatchMessage(EventType.REPAINT);
} }
@@ -787,6 +884,8 @@ public class Presenter implements IPlugInPort {
if (!oldProject.equals(currentProject)) { if (!oldProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner
.deepClone(currentProject), "Group"); .deepClone(currentProject), "Group");
this.modified = true;
fireFileStatusChanged();
} }
} }
@@ -800,6 +899,8 @@ public class Presenter implements IPlugInPort {
if (!oldProject.equals(currentProject)) { if (!oldProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner
.deepClone(currentProject), "Group"); .deepClone(currentProject), "Group");
this.modified = true;
fireFileStatusChanged();
} }
} }
@@ -819,6 +920,11 @@ public class Presenter implements IPlugInPort {
calculateSelectionDimension()); calculateSelectionDimension());
} }
private void fireFileStatusChanged() {
messageDispatcher.dispatchMessage(EventType.FILE_STATUS_CHANGED, this.currentFileName,
this.modified);
}
/** /**
* Removes all the groups that contain at least one of the specified * Removes all the groups that contain at least one of the specified
* components. * components.
@@ -956,24 +1062,14 @@ public class Presenter implements IPlugInPort {
} }
} }
// Extract properties. setDefaultProperties(component);
List<PropertyWrapper> properties = ComponentProcessor.getInstance().extractProperties(
componentType.getInstanceClass());
// Override with default values if available.
for (PropertyWrapper property : properties) {
Object defaultValue = ConfigurationManager.getInstance().getConfigurationItem(
DEFAULTS_KEY + componentType.getInstanceClass().getName() + ":"
+ property.getName());
if (defaultValue != null) {
property.setValue(cloner.deepClone(defaultValue));
property.writeTo(component);
}
}
// Notify the listeners. // Notify the listeners.
if (!oldProject.equals(currentProject)) { if (!oldProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner
.deepClone(currentProject), "Add " + componentType.getName()); .deepClone(currentProject), "Add " + componentType.getName());
this.modified = true;
fireFileStatusChanged();
} }
fireSelectionChanged(); fireSelectionChanged();
@@ -984,6 +1080,32 @@ public class Presenter implements IPlugInPort {
messageDispatcher.dispatchMessage(EventType.REPAINT); messageDispatcher.dispatchMessage(EventType.REPAINT);
} }
/**
* Finds any properties that have default values and injects default values.
* Typically it should be used for {@link IDIYComponent} and {@link Project}
* objects.
*
* @param object
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
private void setDefaultProperties(Object object) throws IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
// Extract properties.
List<PropertyWrapper> properties = ComponentProcessor.getInstance().extractProperties(
object.getClass());
// Override with default values if available.
for (PropertyWrapper property : properties) {
Object defaultValue = ConfigurationManager.getInstance().getConfigurationItem(
DEFAULTS_KEY + object.getClass().getName() + ":" + property.getName());
if (defaultValue != null) {
property.setValue(cloner.deepClone(defaultValue));
property.writeTo(object);
}
}
}
@Override @Override
public List<PropertyWrapper> getMutualSelectionProperties() { public List<PropertyWrapper> getMutualSelectionProperties() {
try { try {
@@ -1012,6 +1134,8 @@ public class Presenter implements IPlugInPort {
if (!oldProject.equals(currentProject)) { if (!oldProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner
.deepClone(currentProject), "Edit Selection"); .deepClone(currentProject), "Edit Selection");
this.modified = true;
fireFileStatusChanged();
} }
messageDispatcher.dispatchMessage(EventType.REPAINT); messageDispatcher.dispatchMessage(EventType.REPAINT);
messageDispatcher.dispatchMessage(EventType.SELECTION_SIZE_CHANGED, messageDispatcher.dispatchMessage(EventType.SELECTION_SIZE_CHANGED,
@@ -1049,6 +1173,8 @@ public class Presenter implements IPlugInPort {
if (!oldProject.equals(currentProject)) { if (!oldProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, cloner
.deepClone(currentProject), "Edit Project"); .deepClone(currentProject), "Edit Project");
this.modified = true;
fireFileStatusChanged();
} }
messageDispatcher.dispatchMessage(EventType.REPAINT); messageDispatcher.dispatchMessage(EventType.REPAINT);
messageDispatcher.dispatchMessage(EventType.ZOOM_CHANGED, zoomLevel); messageDispatcher.dispatchMessage(EventType.ZOOM_CHANGED, zoomLevel);