Added support for component templates

This commit is contained in:
bancika
2012-08-31 11:10:22 +00:00
parent 8804295df6
commit f164473d25
15 changed files with 310 additions and 129 deletions
@@ -10,6 +10,9 @@
<classpathentry kind="lib" path="lib/jettison-1.0.1.jar"/> <classpathentry kind="lib" path="lib/jettison-1.0.1.jar"/>
<classpathentry kind="lib" path="lib/poi-3.5-FINAL-20090928.jar"/> <classpathentry kind="lib" path="lib/poi-3.5-FINAL-20090928.jar"/>
<classpathentry kind="lib" path="library/main.jar" sourcepath="/diylc-library"/> <classpathentry kind="lib" path="library/main.jar" sourcepath="/diylc-library"/>
<classpathentry kind="lib" path="lib/org-openide-awt.jar"/>
<classpathentry kind="lib" path="lib/org-openide-util.jar"/>
<classpathentry kind="lib" path="lib/org-openide-util-lookup.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/diylc-core"/> <classpathentry combineaccessrules="false" kind="src" path="/diylc-core"/>
<classpathentry combineaccessrules="false" kind="src" path="/app-framework"/> <classpathentry combineaccessrules="false" kind="src" path="/app-framework"/>
<classpathentry combineaccessrules="false" kind="src" path="/swing-framework"/> <classpathentry combineaccessrules="false" kind="src" path="/swing-framework"/>
@@ -32,7 +32,7 @@ public enum IconLoader {
"icon_medium.png"), IconSmall("icon_small.png"), DocumentEdit("document_edit.png"), EditComponent( "icon_medium.png"), IconSmall("icon_small.png"), DocumentEdit("document_edit.png"), EditComponent(
"edit_component.png"), Size("size.png"), Front("front.png"), Back("back.png"), Pens( "edit_component.png"), Size("size.png"), Front("front.png"), Back("back.png"), Pens(
"pens.png"), Sort("sort.png"), ElementsSelection("elements_selection.png"), BranchAdd( "pens.png"), Sort("sort.png"), ElementsSelection("elements_selection.png"), BranchAdd(
"branch_add.png"); "branch_add.png"), Briefcase_Add("briefcase_add.png");
protected String name; protected String name;
@@ -10,6 +10,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke; import javax.swing.KeyStroke;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
@@ -131,6 +132,11 @@ public class ActionFactory {
return new DeleteSelectionAction(plugInPort); return new DeleteSelectionAction(plugInPort);
} }
public SaveAsTemplateAction createSaveAsTemplateAction(
IPlugInPort plugInPort) {
return new SaveAsTemplateAction(plugInPort);
}
public ExpandSelectionAction createExpandSelectionAction( public ExpandSelectionAction createExpandSelectionAction(
IPlugInPort plugInPort, ExpansionMode expansionMode) { IPlugInPort plugInPort, ExpansionMode expansionMode) {
return new ExpandSelectionAction(plugInPort, expansionMode); return new ExpandSelectionAction(plugInPort, expansionMode);
@@ -804,6 +810,32 @@ public class ActionFactory {
} }
} }
public static class SaveAsTemplateAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private IPlugInPort plugInPort;
public SaveAsTemplateAction(IPlugInPort plugInPort) {
super();
this.plugInPort = plugInPort;
putValue(AbstractAction.NAME, "Save as Template");
putValue(AbstractAction.SMALL_ICON, IconLoader.Briefcase_Add
.getIcon());
}
@Override
public void actionPerformed(ActionEvent e) {
LOG.info("Save as template triggered");
String templateName = JOptionPane.showInputDialog(null,
"Template name:", "Save as Template",
JOptionPane.PLAIN_MESSAGE);
if (templateName != null && !templateName.trim().isEmpty()) {
plugInPort.saveSelectedComponentAsTemplate(templateName);
}
}
}
public static class ExpandSelectionAction extends AbstractAction { public static class ExpandSelectionAction extends AbstractAction {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -93,7 +93,7 @@ class CanvasPanel extends JComponent implements Autoscroll {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
CanvasPanel.this.plugInPort.setNewComponentTypeSlot(null); CanvasPanel.this.plugInPort.setNewComponentTypeSlot(null, null);
} }
}); });
} }
@@ -59,6 +59,7 @@ public class CanvasPlugin implements IPlugIn, ClipboardOwner {
private ActionFactory.PasteAction pasteAction; private ActionFactory.PasteAction pasteAction;
private ActionFactory.EditSelectionAction editSelectionAction; private ActionFactory.EditSelectionAction editSelectionAction;
private ActionFactory.DeleteSelectionAction deleteSelectionAction; private ActionFactory.DeleteSelectionAction deleteSelectionAction;
private ActionFactory.SaveAsTemplateAction saveAsTemplateAction;
private ActionFactory.GroupAction groupAction; private ActionFactory.GroupAction groupAction;
private ActionFactory.UngroupAction ungroupAction; private ActionFactory.UngroupAction ungroupAction;
private ActionFactory.SendToBackAction sendToBackAction; private ActionFactory.SendToBackAction sendToBackAction;
@@ -101,7 +102,8 @@ public class CanvasPlugin implements IPlugIn, ClipboardOwner {
@Override @Override
public void mouseReleased(MouseEvent e) { public void mouseReleased(MouseEvent e) {
if (plugInPort.getNewComponentTypeSlot() == null && e.isPopupTrigger()) { if (plugInPort.getNewComponentTypeSlot() == null
&& e.isPopupTrigger()) {
// Enable actions. // Enable actions.
boolean enabled = !plugInPort.getSelectedComponents() boolean enabled = !plugInPort.getSelectedComponents()
.isEmpty(); .isEmpty();
@@ -125,6 +127,9 @@ public class CanvasPlugin implements IPlugIn, ClipboardOwner {
getSendToBackAction().setEnabled(enabled); getSendToBackAction().setEnabled(enabled);
getBringToFrontAction().setEnabled(enabled); getBringToFrontAction().setEnabled(enabled);
getSaveAsTemplateAction().setEnabled(
plugInPort.getSelectedComponents().size() == 1);
showPopupAt(e.getX(), e.getY()); showPopupAt(e.getX(), e.getY());
} }
} }
@@ -220,6 +225,7 @@ public class CanvasPlugin implements IPlugIn, ClipboardOwner {
popupMenu.addSeparator(); popupMenu.addSeparator();
popupMenu.add(getEditSelectionAction()); popupMenu.add(getEditSelectionAction());
popupMenu.add(getDeleteSelectionAction()); popupMenu.add(getDeleteSelectionAction());
popupMenu.add(getSaveAsTemplateAction());
popupMenu.add(getGroupAction()); popupMenu.add(getGroupAction());
popupMenu.add(getUngroupAction()); popupMenu.add(getUngroupAction());
popupMenu.add(getSendToBackAction()); popupMenu.add(getSendToBackAction());
@@ -311,6 +317,14 @@ public class CanvasPlugin implements IPlugIn, ClipboardOwner {
return deleteSelectionAction; return deleteSelectionAction;
} }
public ActionFactory.SaveAsTemplateAction getSaveAsTemplateAction() {
if (saveAsTemplateAction == null) {
saveAsTemplateAction = ActionFactory.getInstance()
.createSaveAsTemplateAction(plugInPort);
}
return saveAsTemplateAction;
}
public ActionFactory.GroupAction getGroupAction() { public ActionFactory.GroupAction getGroupAction() {
if (groupAction == null) { if (groupAction == null) {
groupAction = ActionFactory.getInstance().createGroupAction( groupAction = ActionFactory.getInstance().createGroupAction(
@@ -1,106 +0,0 @@
package org.diylc.swing.plugins.toolbox;
import java.awt.Insets;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragSource;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import org.diylc.common.ComponentType;
import org.diylc.common.IPlugInPort;
import org.diylc.core.IDIYComponent;
/**
* {@link JButton} that displays component type icon and instantiates the
* component when clicked.
*
* @author Branislav Stojkovic
*/
class ComponentButton extends JButton {
private static final long serialVersionUID = 1L;
public static int MARGIN = 2;
private IPlugInPort plugInPort;
private ComponentType componentType;
public ComponentButton(final IPlugInPort plugInPort, final ComponentType componentType) {
super(componentType.getIcon());
this.plugInPort = plugInPort;
this.componentType = componentType;
setMargin(new Insets(MARGIN, MARGIN, MARGIN, MARGIN));
setToolTipText("<html><b>" + componentType.getName() + "</b><br>"
+ componentType.getDescription() + "<br>Author: " + componentType.getAuthor()
+ "<br><br>Right click to select all components of this type"
+ "</html>");
// initializeDnD();
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
plugInPort.setNewComponentTypeSlot(componentType);
} else {
List<IDIYComponent<?>> components = plugInPort.getCurrentProject().getComponents();
List<IDIYComponent<?>> newSelection = new ArrayList<IDIYComponent<?>>();
for (IDIYComponent<?> component : components) {
if (componentType.getInstanceClass().equals(component.getClass())) {
newSelection.add(component);
}
}
plugInPort.updateSelection(newSelection);
plugInPort.setNewComponentTypeSlot(null);
plugInPort.refresh();
}
}
});
// addActionListener(new ActionListener() {
//
// @Override
// public void actionPerformed(ActionEvent e) {
// // plugInPort.setCursorIcon(componentType.getIcon());
// plugInPort.setNewComponentTypeSlot(componentType);
// // try {
// // plugInPort.instantiateComponent(componentType
// // .getComponentInstanceClass(), null);
// // } catch (Exception e1) {
// // e1.printStackTrace();
// // }
// }
// });
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_DELETE) {
plugInPort.deleteSelectedComponents();
}
}
});
// addKeyListener(new KeyAdapter() {
//
// @Override
// public void keyPressed(KeyEvent e) {
// if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
// plugInPort.setNewComponentSlot(null);
// }
// }
// });
}
private void initializeDnD() {
// Initialize drag source recognizer.
DragSource.getDefaultDragSource().createDefaultDragGestureRecognizer(this,
DnDConstants.ACTION_MOVE,
new ToolboxGestureListener(plugInPort, componentType.getInstanceClass().getName()));
}
}
@@ -0,0 +1,169 @@
package org.diylc.swing.plugins.toolbox;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import org.diylc.common.ComponentType;
import org.diylc.common.IPlugInPort;
import org.diylc.core.IDIYComponent;
import org.diylc.core.Template;
import org.diylc.images.IconLoader;
import org.openide.awt.DropDownButtonFactory;
/**
* {@link JButton} that displays component type icon and instantiates the
* component when clicked.
*
* @author Branislav Stojkovic
*/
class ComponentButtonFactory {
private static final long serialVersionUID = 1L;
public static int MARGIN = 4;
public static JButton create(final IPlugInPort plugInPort,
final ComponentType componentType, final JPopupMenu menu) {
JButton button = DropDownButtonFactory.createDropDownButton(
componentType.getIcon(), menu);
button.setBorder(BorderFactory.createEmptyBorder(MARGIN, MARGIN,
MARGIN, MARGIN));
// mainButton.setBorder(BorderFactory.createEmptyBorder());
// dropDownButton.setBorder(BorderFactory.createEmptyBorder());
// setBorder(BorderFactory.createLineBorder(Color.gray));
button.setToolTipText("<html><b>" + componentType.getName()
+ "</b><br>" + componentType.getDescription() + "<br>Author: "
+ componentType.getAuthor()
+ "<br><br>Right click to select all components of this type"
+ "</html>");
// initializeDnD();
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
plugInPort.setNewComponentTypeSlot(componentType, null);
}
});
button.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
List<IDIYComponent<?>> components = plugInPort
.getCurrentProject().getComponents();
List<IDIYComponent<?>> newSelection = new ArrayList<IDIYComponent<?>>();
for (IDIYComponent<?> component : components) {
if (componentType.getInstanceClass().equals(
component.getClass())) {
newSelection.add(component);
}
}
plugInPort.updateSelection(newSelection);
plugInPort.setNewComponentTypeSlot(null, null);
plugInPort.refresh();
}
}
});
// addActionListener(new ActionListener() {
//
// @Override
// public void actionPerformed(ActionEvent e) {
// // plugInPort.setCursorIcon(componentType.getIcon());
// plugInPort.setNewComponentTypeSlot(componentType);
// // try {
// // plugInPort.instantiateComponent(componentType
// // .getComponentInstanceClass(), null);
// // } catch (Exception e1) {
// // e1.printStackTrace();
// // }
// }
// });
button.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
plugInPort.keyPressed(e.getKeyCode(), e.isControlDown(), e
.isShiftDown(), e.isAltDown());
}
});
// addKeyListener(new KeyAdapter() {
//
// @Override
// public void keyPressed(KeyEvent e) {
// if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
// plugInPort.setNewComponentSlot(null);
// }
// }
// });
return button;
}
// private void initializeDnD() {
// // Initialize drag source recognizer.
// DragSource.getDefaultDragSource().createDefaultDragGestureRecognizer(
// this,
// DnDConstants.ACTION_MOVE,
// new ToolboxGestureListener(plugInPort, componentType
// .getInstanceClass().getName()));
// }
public static JMenuItem createTemplateItem(final IPlugInPort plugInPort,
final Template template, final ComponentType componentType) {
final JMenuItem item = new JMenuItem(template.getName()) {
private static final long serialVersionUID = 1L;
// Customize item size to fit the delete button
public java.awt.Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
return new Dimension(d.width + 18, d.height);
}
};
item.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
plugInPort.setNewComponentTypeSlot(componentType, template);
}
});
JLabel label = new JLabel(IconLoader.Garbage.getIcon());
label.setToolTipText("Delete template");
label.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
plugInPort.deleteTemplate(componentType.getCategory(),
componentType.getName(), template.getName());
e.consume();
// Hide the menu
Container c = item.getParent();
if (c != null && c instanceof JPopupMenu) {
JPopupMenu m = (JPopupMenu) c;
m.setVisible(false);
}
}
});
item.setLayout(new FlowLayout(FlowLayout.RIGHT, 0, 0));
item.add(label);
return item;
}
}
@@ -9,11 +9,14 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import javax.swing.BoxLayout; import javax.swing.BoxLayout;
import javax.swing.JButton; import javax.swing.JMenuItem;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTabbedPane; import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener; import javax.swing.event.ChangeListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.diylc.appframework.miscutils.ConfigurationManager; import org.diylc.appframework.miscutils.ConfigurationManager;
@@ -21,6 +24,7 @@ import org.diylc.appframework.miscutils.IConfigListener;
import org.diylc.common.ComponentType; import org.diylc.common.ComponentType;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.Template;
import org.diylc.presenter.ComparatorFactory; import org.diylc.presenter.ComparatorFactory;
import org.diylc.presenter.ComponentProcessor; import org.diylc.presenter.ComponentProcessor;
import org.diylc.presenter.Presenter; import org.diylc.presenter.Presenter;
@@ -34,9 +38,11 @@ class ComponentTabbedPane extends JTabbedPane {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOG = Logger.getLogger(ComponentTabbedPane.class); private static final Logger LOG = Logger
.getLogger(ComponentTabbedPane.class);
public static int SCROLL_STEP = Presenter.ICON_SIZE + ComponentButton.MARGIN * 2 + 2; public static int SCROLL_STEP = Presenter.ICON_SIZE
+ ComponentButtonFactory.MARGIN * 2 + 2;
private final IPlugInPort plugInPort; private final IPlugInPort plugInPort;
private Container recentToolbar; private Container recentToolbar;
@@ -46,7 +52,8 @@ class ComponentTabbedPane extends JTabbedPane {
super(); super();
this.plugInPort = plugInPort; this.plugInPort = plugInPort;
addTab("Recently Used", createRecentComponentsPanel()); addTab("Recently Used", createRecentComponentsPanel());
Map<String, List<ComponentType>> componentTypes = plugInPort.getComponentTypes(); Map<String, List<ComponentType>> componentTypes = plugInPort
.getComponentTypes();
List<String> categories = new ArrayList<String>(componentTypes.keySet()); List<String> categories = new ArrayList<String>(componentTypes.keySet());
Collections.sort(categories); Collections.sort(categories);
for (String category : categories) { for (String category : categories) {
@@ -57,10 +64,12 @@ class ComponentTabbedPane extends JTabbedPane {
@Override @Override
public void stateChanged(ChangeEvent e) { public void stateChanged(ChangeEvent e) {
ComponentTabbedPane.this.plugInPort.setNewComponentTypeSlot(null); ComponentTabbedPane.this.plugInPort.setNewComponentTypeSlot(
null, null);
// Refresh recent components if needed // Refresh recent components if needed
if (pendingRecentComponents != null) { if (pendingRecentComponents != null) {
refreshRecentComponentsToolbar(getRecentToolbar(), pendingRecentComponents); refreshRecentComponentsToolbar(getRecentToolbar(),
pendingRecentComponents);
getRecentToolbar().invalidate(); getRecentToolbar().invalidate();
pendingRecentComponents = null; pendingRecentComponents = null;
} }
@@ -124,7 +133,8 @@ class ComponentTabbedPane extends JTabbedPane {
public Container getRecentToolbar() { public Container getRecentToolbar() {
if (recentToolbar == null) { if (recentToolbar == null) {
recentToolbar = new Container(); recentToolbar = new Container();
recentToolbar.setLayout(new BoxLayout(recentToolbar, BoxLayout.X_AXIS)); recentToolbar.setLayout(new BoxLayout(recentToolbar,
BoxLayout.X_AXIS));
} }
return recentToolbar; return recentToolbar;
} }
@@ -135,7 +145,8 @@ class ComponentTabbedPane extends JTabbedPane {
.getComponentTypeComparator()); .getComponentTypeComparator());
toolbar.setLayout(new BoxLayout(toolbar, BoxLayout.X_AXIS)); toolbar.setLayout(new BoxLayout(toolbar, BoxLayout.X_AXIS));
for (ComponentType componentType : componentTypes) { for (ComponentType componentType : componentTypes) {
JButton button = new ComponentButton(plugInPort, componentType); Component button = ComponentButtonFactory.create(plugInPort,
componentType, createTemplatePopup(componentType));
toolbar.add(button); toolbar.add(button);
} }
@@ -147,14 +158,17 @@ class ComponentTabbedPane extends JTabbedPane {
panel.setOpaque(false); panel.setOpaque(false);
final Container toolbar = getRecentToolbar(); final Container toolbar = getRecentToolbar();
refreshRecentComponentsToolbar(toolbar, (List<String>) ConfigurationManager.getInstance() refreshRecentComponentsToolbar(toolbar,
.readObject(IPlugInPort.RECENT_COMPONENTS_KEY, new ArrayList<String>())); (List<String>) ConfigurationManager.getInstance().readObject(
ConfigurationManager.getInstance().addConfigListener(IPlugInPort.RECENT_COMPONENTS_KEY, IPlugInPort.RECENT_COMPONENTS_KEY,
new IConfigListener() { new ArrayList<String>()));
ConfigurationManager.getInstance().addConfigListener(
IPlugInPort.RECENT_COMPONENTS_KEY, new IConfigListener() {
@Override @Override
public void valueChanged(String key, Object value) { public void valueChanged(String key, Object value) {
// Cache the new list, we'll refresh when there's a chance // Cache the new list, we'll refresh when there's a
// chance
pendingRecentComponents = (List<String>) value; pendingRecentComponents = (List<String>) value;
} }
}); });
@@ -170,13 +184,52 @@ class ComponentTabbedPane extends JTabbedPane {
for (String componentClassName : recentComponentClassList) { for (String componentClassName : recentComponentClassList) {
ComponentType componentType; ComponentType componentType;
try { try {
componentType = ComponentProcessor.getInstance().extractComponentTypeFrom( componentType = ComponentProcessor.getInstance()
(Class<? extends IDIYComponent<?>>) Class.forName(componentClassName)); .extractComponentTypeFrom(
JButton button = new ComponentButton(plugInPort, componentType); (Class<? extends IDIYComponent<?>>) Class
.forName(componentClassName));
Component button = ComponentButtonFactory.create(plugInPort,
componentType, createTemplatePopup(componentType));
toolbar.add(button); toolbar.add(button);
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
LOG.error("Could not create recent component button for " + componentClassName, e); LOG.error("Could not create recent component button for "
+ componentClassName, e);
} }
} }
} }
private JPopupMenu createTemplatePopup(final ComponentType componentType) {
final JPopupMenu templatePopup = new JPopupMenu();
templatePopup.add("Loading...");
templatePopup.addPopupMenuListener(new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
templatePopup.removeAll();
List<Template> templates = plugInPort.getTemplatesFor(
componentType.getCategory(), componentType.getName());
if (templates == null || templates.isEmpty()) {
JMenuItem item = new JMenuItem("<no templates>");
item.setEnabled(false);
templatePopup.add(item);
} else {
for (Template template : templates) {
JMenuItem item = ComponentButtonFactory
.createTemplateItem(plugInPort, template,
componentType);
templatePopup.add(item);
}
}
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {
}
});
return templatePopup;
}
} }
@@ -845,5 +845,21 @@
</changes> </changes>
<url>http://code.google.com/p/diy-layout-creator/downloads/list</url> <url>http://code.google.com/p/diy-layout-creator/downloads/list</url>
</org.diylc.appframework.update.Version> </org.diylc.appframework.update.Version>
<org.diylc.appframework.update.Version>
<versionNumber>
<major>3</major>
<minor>15</minor>
<build>0</build>
</versionNumber>
<releaseDate>2012-08-27 20:00:00.000 CET</releaseDate>
<name></name>
<changes>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Added support for component templates</description>
</org.diylc.appframework.update.Change>
</changes>
<url>http://code.google.com/p/diy-layout-creator/downloads/list</url>
</org.diylc.appframework.update.Version>
</a> </a>
</java.util.Arrays_-ArrayList> </java.util.Arrays_-ArrayList>