diff --git a/diylc-swing/.classpath b/diylc-swing/.classpath new file mode 100644 index 00000000..ec3f46f8 --- /dev/null +++ b/diylc-swing/.classpath @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/diylc-swing/.project b/diylc-swing/.project new file mode 100644 index 00000000..8a641248 --- /dev/null +++ b/diylc-swing/.project @@ -0,0 +1,17 @@ + + + diylc-swing + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/diylc-swing/.settings/org.eclipse.jdt.ui.prefs b/diylc-swing/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000..b00bc72a --- /dev/null +++ b/diylc-swing/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,4 @@ +#Sun Nov 08 15:11:18 CET 2009 +eclipse.preferences.version=1 +org.eclipse.jdt.ui.javadoc=false +org.eclipse.jdt.ui.text.custom_code_templates= diff --git a/diylc-swing/DIYLCStarter.launch b/diylc-swing/DIYLCStarter.launch new file mode 100644 index 00000000..1e31e94a --- /dev/null +++ b/diylc-swing/DIYLCStarter.launch @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/diylc-swing/associations.bat b/diylc-swing/associations.bat new file mode 100644 index 00000000..2956d38d --- /dev/null +++ b/diylc-swing/associations.bat @@ -0,0 +1,2 @@ +ftype diyfile="%CD%\diylc.exe" "%%1" +assoc .diy=diyfile \ No newline at end of file diff --git a/diylc-swing/build.xml b/diylc-swing/build.xml new file mode 100644 index 00000000..82e97c8c --- /dev/null +++ b/diylc-swing/build.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + Compile with JDK ${java.runtime.version} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/diylc-swing/config.properties b/diylc-swing/config.properties new file mode 100644 index 00000000..614427b5 --- /dev/null +++ b/diylc-swing/config.properties @@ -0,0 +1,3 @@ +# Uncomment lines you want to edit and change the part after the "=" sign. +#org.diylc.presenter.InstantiationManager.MAX_RECENT_COMPONENTS=20 +#org.diylc.swing.plugins.canvas.CanvasPanel.USE_HARDWARE_ACCELLERATION=true \ No newline at end of file diff --git a/diylc-swing/lib/cloning-1.5.jar b/diylc-swing/lib/cloning-1.5.jar new file mode 100644 index 00000000..781fe27d Binary files /dev/null and b/diylc-swing/lib/cloning-1.5.jar differ diff --git a/diylc-swing/lib/diylc-core.jar b/diylc-swing/lib/diylc-core.jar new file mode 100644 index 00000000..29dd1951 Binary files /dev/null and b/diylc-swing/lib/diylc-core.jar differ diff --git a/diylc-swing/lib/iText-2.1.7.jar b/diylc-swing/lib/iText-2.1.7.jar new file mode 100644 index 00000000..3f2c1882 Binary files /dev/null and b/diylc-swing/lib/iText-2.1.7.jar differ diff --git a/diylc-swing/lib/jettison-1.0.1.jar b/diylc-swing/lib/jettison-1.0.1.jar new file mode 100644 index 00000000..fed929fd Binary files /dev/null and b/diylc-swing/lib/jettison-1.0.1.jar differ diff --git a/diylc-swing/lib/junit-4.7.jar b/diylc-swing/lib/junit-4.7.jar new file mode 100644 index 00000000..700ad695 Binary files /dev/null and b/diylc-swing/lib/junit-4.7.jar differ diff --git a/diylc-swing/lib/log4j-1.2.15.jar b/diylc-swing/lib/log4j-1.2.15.jar new file mode 100644 index 00000000..c930a6ab Binary files /dev/null and b/diylc-swing/lib/log4j-1.2.15.jar differ diff --git a/diylc-swing/lib/objenesis-1.1.jar b/diylc-swing/lib/objenesis-1.1.jar new file mode 100644 index 00000000..f178db33 Binary files /dev/null and b/diylc-swing/lib/objenesis-1.1.jar differ diff --git a/diylc-swing/lib/poi-3.5-FINAL-20090928.jar b/diylc-swing/lib/poi-3.5-FINAL-20090928.jar new file mode 100644 index 00000000..9ff92b02 Binary files /dev/null and b/diylc-swing/lib/poi-3.5-FINAL-20090928.jar differ diff --git a/diylc-swing/lib/xstream-1.3.1.jar b/diylc-swing/lib/xstream-1.3.1.jar new file mode 100644 index 00000000..4ef4219c Binary files /dev/null and b/diylc-swing/lib/xstream-1.3.1.jar differ diff --git a/diylc-swing/library/main.jar b/diylc-swing/library/main.jar new file mode 100644 index 00000000..920e5157 Binary files /dev/null and b/diylc-swing/library/main.jar differ diff --git a/diylc-swing/src/org/diylc/DIYLCStarter.java b/diylc-swing/src/org/diylc/DIYLCStarter.java new file mode 100644 index 00000000..063fc0e8 --- /dev/null +++ b/diylc-swing/src/org/diylc/DIYLCStarter.java @@ -0,0 +1,82 @@ +package org.diylc; + +import java.io.FileInputStream; +import java.net.URL; +import java.util.Properties; + +import javax.swing.UIManager; + +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.appframework.miscutils.PropertyInjector; +import org.diylc.presenter.Presenter; +import org.diylc.swing.gui.MainFrame; +import org.diylc.swing.gui.TemplateDialog; + +/** + * Main class that runs DIYLC. + * + * @author Branislav Stojkovic + * + * @see Presenter + * @see MainFrame + */ +public class DIYLCStarter { + + private static final Logger LOG = Logger.getLogger(DIYLCStarter.class); + + /** + * @param args + */ + public static void main(String[] args) { + URL url = DIYLCStarter.class.getResource("log4j.properties"); + Properties properties = new Properties(); + try { + properties.load(url.openStream()); + PropertyConfigurator.configure(properties); + } catch (Exception e) { + LOG.error("Could not initialize log4j configuration", e); + } + + LOG.debug("Java version: " + System.getProperty("java.runtime.version") + + " by " + System.getProperty("java.vm.vendor")); + LOG.debug("OS: " + System.getProperty("os.name") + " " + + System.getProperty("os.version")); + + LOG.info("Starting DIYLC with working directory " + + System.getProperty("user.dir")); + + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + LOG.error("Could not set Look&Feel", e); + } + + MainFrame mainFrame = new MainFrame(); + mainFrame.setLocationRelativeTo(null); + mainFrame.setVisible(true); + if (args.length > 0) { + mainFrame.getPresenter().loadProjectFromFile(args[0]); + } else { + boolean showTemplates = ConfigurationManager.getInstance() + .readBoolean(TemplateDialog.SHOW_TEMPLATES_KEY, true); + if (showTemplates) { + TemplateDialog templateDialog = new TemplateDialog(mainFrame, + mainFrame.getPresenter()); + if (!templateDialog.getFiles().isEmpty()) { + templateDialog.setVisible(true); + } + } + } + + properties = new Properties(); + try { + LOG.info("Injecting default properties."); + properties.load(new FileInputStream("config.properties")); + PropertyInjector.injectProperties(properties); + } catch (Exception e) { + LOG.error("Could not read config.properties file", e); + } + } +} diff --git a/diylc-swing/src/org/diylc/images/IconLoader.java b/diylc-swing/src/org/diylc/images/IconLoader.java new file mode 100644 index 00000000..f2034622 --- /dev/null +++ b/diylc-swing/src/org/diylc/images/IconLoader.java @@ -0,0 +1,62 @@ +package org.diylc.images; + +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.swing.Icon; +import javax.swing.ImageIcon; + +/** + * Loads image resources as Icons. + * + * @author Branislav Stojkovic + */ +public enum IconLoader { + + Delete("delete.png"), Add("add.png"), FolderOut("folder_out.png"), Garbage("garbage.png"), DiskBlue( + "disk_blue.png"), SaveAs("save_as.png"), Exit("exit.png"), DocumentPlainYellow( + "document_plain_yellow.png"), PhotoScenery("photo_scenery.png"), LightBulbOn( + "lightbulb_on.png"), LightBulbOff("lightbulb_off.png"), NotebookAdd("notebook_add.png"), FormGreen( + "form_green.png"), Gears("gears.png"), About("about.png"), WindowColors( + "window_colors.png"), WindowGear("window_gear.png"), NavigateCheck("navigate_check.png"), Undo( + "undo.png"), Error("error.png"), Warning("warning.png"), ZoomSmall("zoom_small.png"), MoveSmall( + "move_small.png"), Print("print.png"), PDF("pdf.png"), Excel("excel.png"), CSV( + "csv.png"), HTML("html.png"), Image("image.png"), Cut("cut.png"), Copy("copy.png"), Paste( + "paste.png"), Selection("selection.png"), BOM("bom.png"), BlackBoard("blackboard.png"), IdCard( + "id_card.png"), IdCardAdd("id_card_add.png"), Chest("chest.png"), Upload("upload.png"), Wrench( + "wrench.png"), Group("group.png"), Ungroup("ungroup.png"), TraceMask("trace_mask.png"), Faq( + "faq.png"), Component("component.png"), Plugin("plugin.png"), Manual("manual.png"), Donate( + "donate.png"), Bug("bug.png"), IconLarge("icon_large.png"), IconMedium( + "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( + "pens.png"), Sort("sort.png"), ElementsSelection("elements_selection.png"), BranchAdd( + "branch_add.png"); + + protected String name; + + private IconLoader(String name) { + this.name = name; + } + + public Icon getIcon() { + java.net.URL imgURL = getClass().getResource(name); + if (imgURL != null) { + return new ImageIcon(imgURL, name); + } else { + System.err.println("Couldn't find file: " + name); + return null; + } + } + + public Image getImage() { + BufferedImage img = null; + try { + img = ImageIO.read(getClass().getResourceAsStream(name)); + } catch (IOException e) { + System.err.println("Couldn't find file: " + name); + } + return img; + } +} diff --git a/diylc-swing/src/org/diylc/images/about.png b/diylc-swing/src/org/diylc/images/about.png new file mode 100644 index 00000000..a8e64236 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/about.png differ diff --git a/diylc-swing/src/org/diylc/images/add.png b/diylc-swing/src/org/diylc/images/add.png new file mode 100644 index 00000000..8a73c4f6 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/add.png differ diff --git a/diylc-swing/src/org/diylc/images/arrow_down_blue.png b/diylc-swing/src/org/diylc/images/arrow_down_blue.png new file mode 100644 index 00000000..38b5739c Binary files /dev/null and b/diylc-swing/src/org/diylc/images/arrow_down_blue.png differ diff --git a/diylc-swing/src/org/diylc/images/arrow_left_blue.png b/diylc-swing/src/org/diylc/images/arrow_left_blue.png new file mode 100644 index 00000000..ff99225c Binary files /dev/null and b/diylc-swing/src/org/diylc/images/arrow_left_blue.png differ diff --git a/diylc-swing/src/org/diylc/images/arrow_right_blue.png b/diylc-swing/src/org/diylc/images/arrow_right_blue.png new file mode 100644 index 00000000..299f298e Binary files /dev/null and b/diylc-swing/src/org/diylc/images/arrow_right_blue.png differ diff --git a/diylc-swing/src/org/diylc/images/arrow_up_blue.png b/diylc-swing/src/org/diylc/images/arrow_up_blue.png new file mode 100644 index 00000000..e491e547 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/arrow_up_blue.png differ diff --git a/diylc-swing/src/org/diylc/images/at.png b/diylc-swing/src/org/diylc/images/at.png new file mode 100644 index 00000000..206cf23a Binary files /dev/null and b/diylc-swing/src/org/diylc/images/at.png differ diff --git a/diylc-swing/src/org/diylc/images/back.png b/diylc-swing/src/org/diylc/images/back.png new file mode 100644 index 00000000..df446d87 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/back.png differ diff --git a/diylc-swing/src/org/diylc/images/blackboard.png b/diylc-swing/src/org/diylc/images/blackboard.png new file mode 100644 index 00000000..6bcf8dd2 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/blackboard.png differ diff --git a/diylc-swing/src/org/diylc/images/bom.png b/diylc-swing/src/org/diylc/images/bom.png new file mode 100644 index 00000000..233f3687 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/bom.png differ diff --git a/diylc-swing/src/org/diylc/images/branch_add.png b/diylc-swing/src/org/diylc/images/branch_add.png new file mode 100644 index 00000000..cd047e54 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/branch_add.png differ diff --git a/diylc-swing/src/org/diylc/images/bug.png b/diylc-swing/src/org/diylc/images/bug.png new file mode 100644 index 00000000..9086622e Binary files /dev/null and b/diylc-swing/src/org/diylc/images/bug.png differ diff --git a/diylc-swing/src/org/diylc/images/check.png b/diylc-swing/src/org/diylc/images/check.png new file mode 100644 index 00000000..ff611c8a Binary files /dev/null and b/diylc-swing/src/org/diylc/images/check.png differ diff --git a/diylc-swing/src/org/diylc/images/chest.png b/diylc-swing/src/org/diylc/images/chest.png new file mode 100644 index 00000000..5f83ea57 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/chest.png differ diff --git a/diylc-swing/src/org/diylc/images/component.png b/diylc-swing/src/org/diylc/images/component.png new file mode 100644 index 00000000..ce05570f Binary files /dev/null and b/diylc-swing/src/org/diylc/images/component.png differ diff --git a/diylc-swing/src/org/diylc/images/copy.png b/diylc-swing/src/org/diylc/images/copy.png new file mode 100644 index 00000000..4757339f Binary files /dev/null and b/diylc-swing/src/org/diylc/images/copy.png differ diff --git a/diylc-swing/src/org/diylc/images/csv.png b/diylc-swing/src/org/diylc/images/csv.png new file mode 100644 index 00000000..1ae75a5f Binary files /dev/null and b/diylc-swing/src/org/diylc/images/csv.png differ diff --git a/diylc-swing/src/org/diylc/images/cut.png b/diylc-swing/src/org/diylc/images/cut.png new file mode 100644 index 00000000..e354a22c Binary files /dev/null and b/diylc-swing/src/org/diylc/images/cut.png differ diff --git a/diylc-swing/src/org/diylc/images/delete.png b/diylc-swing/src/org/diylc/images/delete.png new file mode 100644 index 00000000..312bb3f5 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/delete.png differ diff --git a/diylc-swing/src/org/diylc/images/disk_blue.png b/diylc-swing/src/org/diylc/images/disk_blue.png new file mode 100644 index 00000000..d2d0d6e1 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/disk_blue.png differ diff --git a/diylc-swing/src/org/diylc/images/disks.png b/diylc-swing/src/org/diylc/images/disks.png new file mode 100644 index 00000000..532ccc6e Binary files /dev/null and b/diylc-swing/src/org/diylc/images/disks.png differ diff --git a/diylc-swing/src/org/diylc/images/document.png b/diylc-swing/src/org/diylc/images/document.png new file mode 100644 index 00000000..af78223e Binary files /dev/null and b/diylc-swing/src/org/diylc/images/document.png differ diff --git a/diylc-swing/src/org/diylc/images/document_edit.png b/diylc-swing/src/org/diylc/images/document_edit.png new file mode 100644 index 00000000..35d01513 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/document_edit.png differ diff --git a/diylc-swing/src/org/diylc/images/document_info.png b/diylc-swing/src/org/diylc/images/document_info.png new file mode 100644 index 00000000..453f2290 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/document_info.png differ diff --git a/diylc-swing/src/org/diylc/images/document_plain_yellow.png b/diylc-swing/src/org/diylc/images/document_plain_yellow.png new file mode 100644 index 00000000..3e88b651 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/document_plain_yellow.png differ diff --git a/diylc-swing/src/org/diylc/images/donate.gif b/diylc-swing/src/org/diylc/images/donate.gif new file mode 100644 index 00000000..43cef691 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/donate.gif differ diff --git a/diylc-swing/src/org/diylc/images/donate.png b/diylc-swing/src/org/diylc/images/donate.png new file mode 100644 index 00000000..0d2baa8d Binary files /dev/null and b/diylc-swing/src/org/diylc/images/donate.png differ diff --git a/diylc-swing/src/org/diylc/images/edit.png b/diylc-swing/src/org/diylc/images/edit.png new file mode 100644 index 00000000..ae851759 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/edit.png differ diff --git a/diylc-swing/src/org/diylc/images/edit_component.png b/diylc-swing/src/org/diylc/images/edit_component.png new file mode 100644 index 00000000..9f438c3e Binary files /dev/null and b/diylc-swing/src/org/diylc/images/edit_component.png differ diff --git a/diylc-swing/src/org/diylc/images/elements_selection.png b/diylc-swing/src/org/diylc/images/elements_selection.png new file mode 100644 index 00000000..be9d2df1 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/elements_selection.png differ diff --git a/diylc-swing/src/org/diylc/images/error.png b/diylc-swing/src/org/diylc/images/error.png new file mode 100644 index 00000000..f2bd64fd Binary files /dev/null and b/diylc-swing/src/org/diylc/images/error.png differ diff --git a/diylc-swing/src/org/diylc/images/excel.png b/diylc-swing/src/org/diylc/images/excel.png new file mode 100644 index 00000000..3705304e Binary files /dev/null and b/diylc-swing/src/org/diylc/images/excel.png differ diff --git a/diylc-swing/src/org/diylc/images/exit.png b/diylc-swing/src/org/diylc/images/exit.png new file mode 100644 index 00000000..65d3c548 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/exit.png differ diff --git a/diylc-swing/src/org/diylc/images/export.png b/diylc-swing/src/org/diylc/images/export.png new file mode 100644 index 00000000..113a7cda Binary files /dev/null and b/diylc-swing/src/org/diylc/images/export.png differ diff --git a/diylc-swing/src/org/diylc/images/faq.png b/diylc-swing/src/org/diylc/images/faq.png new file mode 100644 index 00000000..ee0dd88f Binary files /dev/null and b/diylc-swing/src/org/diylc/images/faq.png differ diff --git a/diylc-swing/src/org/diylc/images/folder_music.png b/diylc-swing/src/org/diylc/images/folder_music.png new file mode 100644 index 00000000..dc3da81b Binary files /dev/null and b/diylc-swing/src/org/diylc/images/folder_music.png differ diff --git a/diylc-swing/src/org/diylc/images/folder_out.png b/diylc-swing/src/org/diylc/images/folder_out.png new file mode 100644 index 00000000..80895073 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/folder_out.png differ diff --git a/diylc-swing/src/org/diylc/images/forbidden.png b/diylc-swing/src/org/diylc/images/forbidden.png new file mode 100644 index 00000000..530433e6 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/forbidden.png differ diff --git a/diylc-swing/src/org/diylc/images/form_blue.png b/diylc-swing/src/org/diylc/images/form_blue.png new file mode 100644 index 00000000..687cbf32 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/form_blue.png differ diff --git a/diylc-swing/src/org/diylc/images/form_blue_add.png b/diylc-swing/src/org/diylc/images/form_blue_add.png new file mode 100644 index 00000000..15fb1f21 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/form_blue_add.png differ diff --git a/diylc-swing/src/org/diylc/images/front.png b/diylc-swing/src/org/diylc/images/front.png new file mode 100644 index 00000000..302a04ca Binary files /dev/null and b/diylc-swing/src/org/diylc/images/front.png differ diff --git a/diylc-swing/src/org/diylc/images/garbage.png b/diylc-swing/src/org/diylc/images/garbage.png new file mode 100644 index 00000000..a8fe2a3c Binary files /dev/null and b/diylc-swing/src/org/diylc/images/garbage.png differ diff --git a/diylc-swing/src/org/diylc/images/gear.png b/diylc-swing/src/org/diylc/images/gear.png new file mode 100644 index 00000000..8e1411f2 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/gear.png differ diff --git a/diylc-swing/src/org/diylc/images/gears.png b/diylc-swing/src/org/diylc/images/gears.png new file mode 100644 index 00000000..90ecf65c Binary files /dev/null and b/diylc-swing/src/org/diylc/images/gears.png differ diff --git a/diylc-swing/src/org/diylc/images/graph_edge.png b/diylc-swing/src/org/diylc/images/graph_edge.png new file mode 100644 index 00000000..537388ca Binary files /dev/null and b/diylc-swing/src/org/diylc/images/graph_edge.png differ diff --git a/diylc-swing/src/org/diylc/images/graph_edge_curved.png b/diylc-swing/src/org/diylc/images/graph_edge_curved.png new file mode 100644 index 00000000..dcb67b42 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/graph_edge_curved.png differ diff --git a/diylc-swing/src/org/diylc/images/graph_edge_directed.png b/diylc-swing/src/org/diylc/images/graph_edge_directed.png new file mode 100644 index 00000000..09e881bc Binary files /dev/null and b/diylc-swing/src/org/diylc/images/graph_edge_directed.png differ diff --git a/diylc-swing/src/org/diylc/images/group.png b/diylc-swing/src/org/diylc/images/group.png new file mode 100644 index 00000000..be9d2df1 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/group.png differ diff --git a/diylc-swing/src/org/diylc/images/html.png b/diylc-swing/src/org/diylc/images/html.png new file mode 100644 index 00000000..292f755f Binary files /dev/null and b/diylc-swing/src/org/diylc/images/html.png differ diff --git a/diylc-swing/src/org/diylc/images/icon_large.png b/diylc-swing/src/org/diylc/images/icon_large.png new file mode 100644 index 00000000..edd52f73 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/icon_large.png differ diff --git a/diylc-swing/src/org/diylc/images/icon_medium.png b/diylc-swing/src/org/diylc/images/icon_medium.png new file mode 100644 index 00000000..d5559652 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/icon_medium.png differ diff --git a/diylc-swing/src/org/diylc/images/icon_small.png b/diylc-swing/src/org/diylc/images/icon_small.png new file mode 100644 index 00000000..ca6af1c6 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/icon_small.png differ diff --git a/diylc-swing/src/org/diylc/images/id_card.png b/diylc-swing/src/org/diylc/images/id_card.png new file mode 100644 index 00000000..b72bae75 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/id_card.png differ diff --git a/diylc-swing/src/org/diylc/images/id_card_add.png b/diylc-swing/src/org/diylc/images/id_card_add.png new file mode 100644 index 00000000..212dcc26 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/id_card_add.png differ diff --git a/diylc-swing/src/org/diylc/images/image.png b/diylc-swing/src/org/diylc/images/image.png new file mode 100644 index 00000000..b1d3ad27 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/image.png differ diff --git a/diylc-swing/src/org/diylc/images/lightbulb_off.png b/diylc-swing/src/org/diylc/images/lightbulb_off.png new file mode 100644 index 00000000..d38e9e6c Binary files /dev/null and b/diylc-swing/src/org/diylc/images/lightbulb_off.png differ diff --git a/diylc-swing/src/org/diylc/images/lightbulb_on.png b/diylc-swing/src/org/diylc/images/lightbulb_on.png new file mode 100644 index 00000000..032d1650 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/lightbulb_on.png differ diff --git a/diylc-swing/src/org/diylc/images/manual.png b/diylc-swing/src/org/diylc/images/manual.png new file mode 100644 index 00000000..41c04a0b Binary files /dev/null and b/diylc-swing/src/org/diylc/images/manual.png differ diff --git a/diylc-swing/src/org/diylc/images/media_play_green.png b/diylc-swing/src/org/diylc/images/media_play_green.png new file mode 100644 index 00000000..0a06be81 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/media_play_green.png differ diff --git a/diylc-swing/src/org/diylc/images/media_stop_red.png b/diylc-swing/src/org/diylc/images/media_stop_red.png new file mode 100644 index 00000000..02fbdd17 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/media_stop_red.png differ diff --git a/diylc-swing/src/org/diylc/images/move_small.png b/diylc-swing/src/org/diylc/images/move_small.png new file mode 100644 index 00000000..3d00db3c Binary files /dev/null and b/diylc-swing/src/org/diylc/images/move_small.png differ diff --git a/diylc-swing/src/org/diylc/images/navigate_check.png b/diylc-swing/src/org/diylc/images/navigate_check.png new file mode 100644 index 00000000..8fc0a6a5 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/navigate_check.png differ diff --git a/diylc-swing/src/org/diylc/images/navigate_plus.png b/diylc-swing/src/org/diylc/images/navigate_plus.png new file mode 100644 index 00000000..a751af18 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/navigate_plus.png differ diff --git a/diylc-swing/src/org/diylc/images/notebook_add.png b/diylc-swing/src/org/diylc/images/notebook_add.png new file mode 100644 index 00000000..62bdeacb Binary files /dev/null and b/diylc-swing/src/org/diylc/images/notebook_add.png differ diff --git a/diylc-swing/src/org/diylc/images/paste.png b/diylc-swing/src/org/diylc/images/paste.png new file mode 100644 index 00000000..fe5c0e94 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/paste.png differ diff --git a/diylc-swing/src/org/diylc/images/pdf.png b/diylc-swing/src/org/diylc/images/pdf.png new file mode 100644 index 00000000..1dddc483 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/pdf.png differ diff --git a/diylc-swing/src/org/diylc/images/pens.png b/diylc-swing/src/org/diylc/images/pens.png new file mode 100644 index 00000000..16d091b2 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/pens.png differ diff --git a/diylc-swing/src/org/diylc/images/photo_scenery.png b/diylc-swing/src/org/diylc/images/photo_scenery.png new file mode 100644 index 00000000..b1d3ad27 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/photo_scenery.png differ diff --git a/diylc-swing/src/org/diylc/images/plugin.png b/diylc-swing/src/org/diylc/images/plugin.png new file mode 100644 index 00000000..2bee22c4 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/plugin.png differ diff --git a/diylc-swing/src/org/diylc/images/print.png b/diylc-swing/src/org/diylc/images/print.png new file mode 100644 index 00000000..ae807b13 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/print.png differ diff --git a/diylc-swing/src/org/diylc/images/redo.png b/diylc-swing/src/org/diylc/images/redo.png new file mode 100644 index 00000000..092ff424 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/redo.png differ diff --git a/diylc-swing/src/org/diylc/images/refresh.png b/diylc-swing/src/org/diylc/images/refresh.png new file mode 100644 index 00000000..1f23890d Binary files /dev/null and b/diylc-swing/src/org/diylc/images/refresh.png differ diff --git a/diylc-swing/src/org/diylc/images/save_as.png b/diylc-swing/src/org/diylc/images/save_as.png new file mode 100644 index 00000000..a38d1fa2 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/save_as.png differ diff --git a/diylc-swing/src/org/diylc/images/selection.png b/diylc-swing/src/org/diylc/images/selection.png new file mode 100644 index 00000000..dbb0a1a9 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/selection.png differ diff --git a/diylc-swing/src/org/diylc/images/size.png b/diylc-swing/src/org/diylc/images/size.png new file mode 100644 index 00000000..16fd65eb Binary files /dev/null and b/diylc-swing/src/org/diylc/images/size.png differ diff --git a/diylc-swing/src/org/diylc/images/sort.png b/diylc-swing/src/org/diylc/images/sort.png new file mode 100644 index 00000000..e7f43647 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/sort.png differ diff --git a/diylc-swing/src/org/diylc/images/trace_mask.png b/diylc-swing/src/org/diylc/images/trace_mask.png new file mode 100644 index 00000000..38bf1602 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/trace_mask.png differ diff --git a/diylc-swing/src/org/diylc/images/undo.png b/diylc-swing/src/org/diylc/images/undo.png new file mode 100644 index 00000000..f7e5f935 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/undo.png differ diff --git a/diylc-swing/src/org/diylc/images/ungroup.png b/diylc-swing/src/org/diylc/images/ungroup.png new file mode 100644 index 00000000..383e6330 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/ungroup.png differ diff --git a/diylc-swing/src/org/diylc/images/upload.png b/diylc-swing/src/org/diylc/images/upload.png new file mode 100644 index 00000000..113a7cda Binary files /dev/null and b/diylc-swing/src/org/diylc/images/upload.png differ diff --git a/diylc-swing/src/org/diylc/images/view.png b/diylc-swing/src/org/diylc/images/view.png new file mode 100644 index 00000000..21aae811 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/view.png differ diff --git a/diylc-swing/src/org/diylc/images/warning.png b/diylc-swing/src/org/diylc/images/warning.png new file mode 100644 index 00000000..a6cdac6e Binary files /dev/null and b/diylc-swing/src/org/diylc/images/warning.png differ diff --git a/diylc-swing/src/org/diylc/images/window_colors.png b/diylc-swing/src/org/diylc/images/window_colors.png new file mode 100644 index 00000000..8f5f13ba Binary files /dev/null and b/diylc-swing/src/org/diylc/images/window_colors.png differ diff --git a/diylc-swing/src/org/diylc/images/wrench.png b/diylc-swing/src/org/diylc/images/wrench.png new file mode 100644 index 00000000..e6b6a1b5 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/wrench.png differ diff --git a/diylc-swing/src/org/diylc/images/zoom_in.png b/diylc-swing/src/org/diylc/images/zoom_in.png new file mode 100644 index 00000000..f575d423 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/zoom_in.png differ diff --git a/diylc-swing/src/org/diylc/images/zoom_out.png b/diylc-swing/src/org/diylc/images/zoom_out.png new file mode 100644 index 00000000..4641b520 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/zoom_out.png differ diff --git a/diylc-swing/src/org/diylc/images/zoom_small.png b/diylc-swing/src/org/diylc/images/zoom_small.png new file mode 100644 index 00000000..7020e117 Binary files /dev/null and b/diylc-swing/src/org/diylc/images/zoom_small.png differ diff --git a/diylc-swing/src/org/diylc/log4j.properties b/diylc-swing/src/org/diylc/log4j.properties new file mode 100644 index 00000000..0e4b1681 --- /dev/null +++ b/diylc-swing/src/org/diylc/log4j.properties @@ -0,0 +1,9 @@ +log4j.rootLogger = DEBUG, fileout, stdout +log4j.appender.fileout = org.diylc.appframework.miscutils.NewLogForEachRunFileAppender +log4j.appender.fileout.layout.ConversionPattern = %d{ABSOLUTE} %5p [%t] %c{1} - %m%n +log4j.appender.fileout.layout = org.apache.log4j.PatternLayout +log4j.appender.fileout.File = log/log.log + +log4j.appender.stdout = org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} %5p [%t] %c{1} - %m%n +log4j.appender.stdout.layout = org.apache.log4j.PatternLayout \ No newline at end of file diff --git a/diylc-swing/src/org/diylc/swing/ActionFactory.java b/diylc-swing/src/org/diylc/swing/ActionFactory.java new file mode 100644 index 00000000..a3d24065 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/ActionFactory.java @@ -0,0 +1,909 @@ +package org.diylc.swing; + +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.ClipboardOwner; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.awt.print.PrinterException; +import java.io.File; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.KeyStroke; + +import org.apache.log4j.Logger; +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ITask; +import org.diylc.common.PropertyWrapper; +import org.diylc.core.ExpansionMode; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IView; +import org.diylc.core.Theme; +import org.diylc.images.IconLoader; +import org.diylc.swing.gui.DialogFactory; +import org.diylc.swing.gui.editor.PropertyEditorDialog; +import org.diylc.swing.plugins.edit.ComponentTransferable; +import org.diylc.swing.plugins.file.BomDialog; +import org.diylc.swing.plugins.file.FileFilterEnum; +import org.diylc.swingframework.ButtonDialog; +import org.diylc.swingframework.IDrawingProvider; +import org.diylc.swingframework.export.DrawingExporter; +import org.diylc.utils.BomEntry; + +import com.rits.cloning.Cloner; + +public class ActionFactory { + + private static final Logger LOG = Logger.getLogger(ActionFactory.class); + + private static ActionFactory instance; + private static Cloner cloner = new Cloner(); + + public static ActionFactory getInstance() { + if (instance == null) { + instance = new ActionFactory(); + } + return instance; + } + + private ActionFactory() { + } + + // File menu actions. + + public NewAction createNewAction(IPlugInPort plugInPort) { + return new NewAction(plugInPort); + } + + public OpenAction createOpenAction(IPlugInPort plugInPort, ISwingUI swingUI) { + return new OpenAction(plugInPort, swingUI); + } + + public SaveAction createSaveAction(IPlugInPort plugInPort, ISwingUI swingUI) { + return new SaveAction(plugInPort, swingUI); + } + + public SaveAsAction createSaveAsAction(IPlugInPort plugInPort, ISwingUI swingUI) { + return new SaveAsAction(plugInPort, swingUI); + } + + public CreateBomAction createBomAction(IPlugInPort plugInPort) { + return new CreateBomAction(plugInPort); + } + + public ExportPDFAction createExportPDFAction(IDrawingProvider drawingProvider, ISwingUI swingUI) { + return new ExportPDFAction(drawingProvider, swingUI); + } + + public ExportPNGAction createExportPNGAction(IDrawingProvider drawingProvider, ISwingUI swingUI) { + return new ExportPNGAction(drawingProvider, swingUI); + } + + public PrintAction createPrintAction(IDrawingProvider drawingProvider) { + return new PrintAction(drawingProvider); + } + + public ExitAction createExitAction(IPlugInPort plugInPort) { + return new ExitAction(plugInPort); + } + + // Edit menu actions. + + public CutAction createCutAction(IPlugInPort plugInPort, Clipboard clipboard, + ClipboardOwner clipboardOwner) { + return new CutAction(plugInPort, clipboard, clipboardOwner); + } + + public CopyAction createCopyAction(IPlugInPort plugInPort, Clipboard clipboard, + ClipboardOwner clipboardOwner) { + return new CopyAction(plugInPort, clipboard, clipboardOwner); + } + + public PasteAction createPasteAction(IPlugInPort plugInPort, Clipboard clipboard) { + return new PasteAction(plugInPort, clipboard); + } + + public SelectAllAction createSelectAllAction(IPlugInPort plugInPort) { + return new SelectAllAction(plugInPort); + } + + public GroupAction createGroupAction(IPlugInPort plugInPort) { + return new GroupAction(plugInPort); + } + + public UngroupAction createUngroupAction(IPlugInPort plugInPort) { + return new UngroupAction(plugInPort); + } + + public EditProjectAction createEditProjectAction(IPlugInPort plugInPort) { + return new EditProjectAction(plugInPort); + } + + public EditSelectionAction createEditSelectionAction(IPlugInPort plugInPort) { + return new EditSelectionAction(plugInPort); + } + + public DeleteSelectionAction createDeleteSelectionAction(IPlugInPort plugInPort) { + return new DeleteSelectionAction(plugInPort); + } + + public ExpandSelectionAction createExpandSelectionAction(IPlugInPort plugInPort, + ExpansionMode expansionMode) { + return new ExpandSelectionAction(plugInPort, expansionMode); + } + + public SendToBackAction createSendToBackAction(IPlugInPort plugInPort) { + return new SendToBackAction(plugInPort); + } + + public BringToFrontAction createBringToFrontAction(IPlugInPort plugInPort) { + return new BringToFrontAction(plugInPort); + } + + // Config actions. + + public ConfigAction createConfigAction(IPlugInPort plugInPort, String title, String configKey, + boolean defaultValue) { + return new ConfigAction(plugInPort, title, configKey, defaultValue); + } + + public ThemeAction createThemeAction(IPlugInPort plugInPort, Theme theme) { + return new ThemeAction(plugInPort, theme); + } + + public RenumberAction createRenumberAction(IPlugInPort plugInPort, boolean xAxisFirst) { + return new RenumberAction(plugInPort, xAxisFirst); + } + + // File menu actions. + + public static class NewAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + + public NewAction(IPlugInPort plugInPort) { + super(); + this.plugInPort = plugInPort; + putValue(AbstractAction.NAME, "New"); + putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_N, + ActionEvent.CTRL_MASK)); + putValue(AbstractAction.SMALL_ICON, IconLoader.DocumentPlainYellow.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("NewAction triggered"); + if (!plugInPort.allowFileAction()) { + return; + } + plugInPort.createNewProject(); + List properties = plugInPort.getProjectProperties(); + PropertyEditorDialog editor = DialogFactory.getInstance().createPropertyEditorDialog( + properties, "Edit Project"); + editor.setVisible(true); + if (ButtonDialog.OK.equals(editor.getSelectedButtonCaption())) { + plugInPort.applyPropertiesToProject(properties); + } + // Save default values. + for (PropertyWrapper property : editor.getDefaultedProperties()) { + if (property.getValue() != null) { + plugInPort.setProjectDefaultPropertyValue(property.getName(), property + .getValue()); + } + } + } + } + + public static class OpenAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + private ISwingUI swingUI; + + public OpenAction(IPlugInPort plugInPort, ISwingUI swingUI) { + super(); + this.plugInPort = plugInPort; + this.swingUI = swingUI; + putValue(AbstractAction.NAME, "Open"); + putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_O, + ActionEvent.CTRL_MASK)); + putValue(AbstractAction.SMALL_ICON, IconLoader.FolderOut.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("OpenAction triggered"); + if (!plugInPort.allowFileAction()) { + return; + } + final File file = DialogFactory.getInstance().showOpenDialog( + FileFilterEnum.DIY.getFilter(), null, FileFilterEnum.DIY.getExtensions()[0], + null); + if (file != null) { + swingUI.executeBackgroundTask(new ITask() { + + @Override + public Void doInBackground() throws Exception { + LOG.debug("Opening from " + file.getAbsolutePath()); + plugInPort.loadProjectFromFile(file.getAbsolutePath()); + return null; + } + + @Override + public void complete(Void result) { + } + + @Override + public void failed(Exception e) { + swingUI.showMessage("Could not open file. " + e.getMessage(), "Error", + ISwingUI.ERROR_MESSAGE); + } + }); + } + } + } + + public static class SaveAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + private ISwingUI swingUI; + + public SaveAction(IPlugInPort plugInPort, ISwingUI swingUI) { + super(); + this.plugInPort = plugInPort; + this.swingUI = swingUI; + putValue(AbstractAction.NAME, "Save"); + putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_S, + ActionEvent.CTRL_MASK)); + putValue(AbstractAction.SMALL_ICON, IconLoader.DiskBlue.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("SaveAction triggered"); + if (plugInPort.getCurrentFileName() == null) { + final File file = DialogFactory.getInstance().showSaveDialog( + FileFilterEnum.DIY.getFilter(), null, + FileFilterEnum.DIY.getExtensions()[0], null); + if (file != null) { + swingUI.executeBackgroundTask(new ITask() { + + @Override + public Void doInBackground() throws Exception { + LOG.debug("Saving to " + file.getAbsolutePath()); + plugInPort.saveProjectToFile(file.getAbsolutePath(), false); + return null; + } + + @Override + public void complete(Void result) { + } + + @Override + public void failed(Exception e) { + swingUI.showMessage("Could not save to file. " + e.getMessage(), + "Error", ISwingUI.ERROR_MESSAGE); + } + }); + } + } else { + swingUI.executeBackgroundTask(new ITask() { + + @Override + public Void doInBackground() throws Exception { + LOG.debug("Saving to " + plugInPort.getCurrentFileName()); + plugInPort.saveProjectToFile(plugInPort.getCurrentFileName(), false); + return null; + } + + @Override + public void complete(Void result) { + } + + @Override + public void failed(Exception e) { + swingUI.showMessage("Could not save to file. " + e.getMessage(), "Error", + ISwingUI.ERROR_MESSAGE); + } + }); + } + } + } + + public static class SaveAsAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + private ISwingUI swingUI; + + public SaveAsAction(IPlugInPort plugInPort, ISwingUI swingUI) { + super(); + this.plugInPort = plugInPort; + this.swingUI = swingUI; + putValue(AbstractAction.NAME, "Save As"); + putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_S, + ActionEvent.CTRL_MASK | ActionEvent.SHIFT_MASK)); + putValue(AbstractAction.SMALL_ICON, IconLoader.DiskBlue.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("SaveAsAction triggered"); + final File file = DialogFactory.getInstance().showSaveDialog( + FileFilterEnum.DIY.getFilter(), null, FileFilterEnum.DIY.getExtensions()[0], + null); + if (file != null) { + swingUI.executeBackgroundTask(new ITask() { + + @Override + public Void doInBackground() throws Exception { + LOG.debug("Saving to " + file.getAbsolutePath()); + plugInPort.saveProjectToFile(file.getAbsolutePath(), false); + return null; + } + + @Override + public void complete(Void result) { + } + + @Override + public void failed(Exception e) { + swingUI.showMessage("Could not save to file. " + e.getMessage(), "Error", + ISwingUI.ERROR_MESSAGE); + } + }); + } + } + } + + public static class CreateBomAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + + public CreateBomAction(IPlugInPort plugInPort) { + super(); + this.plugInPort = plugInPort; + putValue(AbstractAction.NAME, "Create B.O.M."); + putValue(AbstractAction.SMALL_ICON, IconLoader.BOM.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("CreateBomAction triggered"); + List bom = org.diylc.utils.BomMaker.getInstance().createBom( + plugInPort.getCurrentProject().getComponents()); + BomDialog dialog = DialogFactory.getInstance().createBomDialog(bom); + dialog.setVisible(true); + } + } + + public static class ExportPDFAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IDrawingProvider drawingProvider; + private ISwingUI swingUI; + + public ExportPDFAction(IDrawingProvider drawingProvider, ISwingUI swingUI) { + super(); + this.drawingProvider = drawingProvider; + this.swingUI = swingUI; + putValue(AbstractAction.NAME, "Export to PDF"); + putValue(AbstractAction.SMALL_ICON, IconLoader.PDF.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("ExportPDFAction triggered"); + final File file = DialogFactory.getInstance().showSaveDialog( + FileFilterEnum.PDF.getFilter(), null, FileFilterEnum.PDF.getExtensions()[0], + null); + if (file != null) { + swingUI.executeBackgroundTask(new ITask() { + + @Override + public Void doInBackground() throws Exception { + LOG.debug("Exporting to " + file.getAbsolutePath()); + DrawingExporter.getInstance().exportPDF( + ExportPDFAction.this.drawingProvider, file); + return null; + } + + @Override + public void complete(Void result) { + } + + @Override + public void failed(Exception e) { + swingUI.showMessage("Could not export to PDF. " + e.getMessage(), "Error", + ISwingUI.ERROR_MESSAGE); + } + }); + } + } + } + + public static class ExportPNGAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IDrawingProvider drawingProvider; + private ISwingUI swingUI; + + public ExportPNGAction(IDrawingProvider drawingProvider, ISwingUI swingUI) { + super(); + this.drawingProvider = drawingProvider; + this.swingUI = swingUI; + putValue(AbstractAction.NAME, "Export to PNG"); + putValue(AbstractAction.SMALL_ICON, IconLoader.Image.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("ExportPNGAction triggered"); + final File file = DialogFactory.getInstance().showSaveDialog( + FileFilterEnum.PNG.getFilter(), null, FileFilterEnum.PNG.getExtensions()[0], + null); + if (file != null) { + swingUI.executeBackgroundTask(new ITask() { + + @Override + public Void doInBackground() throws Exception { + LOG.debug("Exporting to " + file.getAbsolutePath()); + DrawingExporter.getInstance().exportPNG( + ExportPNGAction.this.drawingProvider, file); + return null; + } + + @Override + public void complete(Void result) { + } + + @Override + public void failed(Exception e) { + swingUI.showMessage("Could not export to PNG. " + e.getMessage(), "Error", + ISwingUI.ERROR_MESSAGE); + } + }); + } + } + } + + public static class PrintAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IDrawingProvider drawingProvider; + + public PrintAction(IDrawingProvider drawingProvider) { + super(); + this.drawingProvider = drawingProvider; + putValue(AbstractAction.NAME, "Print..."); + putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_P, + ActionEvent.CTRL_MASK)); + putValue(AbstractAction.SMALL_ICON, IconLoader.Print.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("ExportPNGAction triggered"); + try { + DrawingExporter.getInstance().print(this.drawingProvider); + } catch (PrinterException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + } + + public static class ExitAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + + public ExitAction(IPlugInPort plugInPort) { + super(); + this.plugInPort = plugInPort; + putValue(AbstractAction.NAME, "Exit"); + putValue(AbstractAction.SMALL_ICON, IconLoader.Exit.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (plugInPort.allowFileAction()) { + System.exit(0); + } + } + } + + // Edit menu actions. + + public static class CutAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + private Clipboard clipboard; + private ClipboardOwner clipboardOwner; + + public CutAction(IPlugInPort plugInPort, Clipboard clipboard, ClipboardOwner clipboardOwner) { + super(); + this.plugInPort = plugInPort; + this.clipboard = clipboard; + this.clipboardOwner = clipboardOwner; + putValue(AbstractAction.NAME, "Cut"); + putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_X, + ActionEvent.CTRL_MASK)); + putValue(AbstractAction.SMALL_ICON, IconLoader.Cut.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("Cut triggered"); + clipboard.setContents(new ComponentTransferable(cloner.deepClone(plugInPort + .getSelectedComponents())), clipboardOwner); + plugInPort.deleteSelectedComponents(); + } + } + + public static class CopyAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + private Clipboard clipboard; + private ClipboardOwner clipboardOwner; + + public CopyAction(IPlugInPort plugInPort, Clipboard clipboard, ClipboardOwner clipboardOwner) { + super(); + this.plugInPort = plugInPort; + this.clipboard = clipboard; + this.clipboardOwner = clipboardOwner; + putValue(AbstractAction.NAME, "Copy"); + putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_C, + ActionEvent.CTRL_MASK)); + putValue(AbstractAction.SMALL_ICON, IconLoader.Copy.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("Copy triggered"); + clipboard.setContents(new ComponentTransferable(cloner.deepClone(plugInPort + .getSelectedComponents())), clipboardOwner); + } + } + + public static class PasteAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + private Clipboard clipboard; + + public PasteAction(IPlugInPort plugInPort, Clipboard clipboard) { + super(); + this.plugInPort = plugInPort; + this.clipboard = clipboard; + putValue(AbstractAction.NAME, "Paste"); + putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_V, + ActionEvent.CTRL_MASK)); + putValue(AbstractAction.SMALL_ICON, IconLoader.Paste.getIcon()); + } + + @SuppressWarnings("unchecked") + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("Paste triggered"); + try { + List> components = (List>) clipboard + .getData(ComponentTransferable.listFlavor); + plugInPort.pasteComponents(cloner.deepClone(components)); + } catch (Exception ex) { + LOG.error("Coule not paste.", ex); + } + } + } + + public static class SelectAllAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + + public SelectAllAction(IPlugInPort plugInPort) { + super(); + this.plugInPort = plugInPort; + putValue(AbstractAction.NAME, "Select All"); + putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_A, + ActionEvent.CTRL_MASK)); + putValue(AbstractAction.SMALL_ICON, IconLoader.Selection.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("Select All triggered"); + plugInPort.selectAll(); + } + } + + public static class GroupAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + + public GroupAction(IPlugInPort plugInPort) { + super(); + this.plugInPort = plugInPort; + putValue(AbstractAction.NAME, "Group Selection"); + putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_G, + ActionEvent.CTRL_MASK)); + putValue(AbstractAction.SMALL_ICON, IconLoader.Group.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("Group Selection triggered"); + plugInPort.groupSelectedComponents(); + } + } + + public static class UngroupAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + + public UngroupAction(IPlugInPort plugInPort) { + super(); + this.plugInPort = plugInPort; + putValue(AbstractAction.NAME, "Ungroup Selection"); + putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_U, + ActionEvent.CTRL_MASK)); + putValue(AbstractAction.SMALL_ICON, IconLoader.Ungroup.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("Ungroup Selection triggered"); + plugInPort.ungroupSelectedComponents(); + } + } + + public static class EditProjectAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + + public EditProjectAction(IPlugInPort plugInPort) { + super(); + this.plugInPort = plugInPort; + putValue(AbstractAction.NAME, "Edit Project"); + putValue(AbstractAction.SMALL_ICON, IconLoader.DocumentEdit.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("Edit Project triggered"); + List properties = plugInPort.getProjectProperties(); + PropertyEditorDialog editor = DialogFactory.getInstance().createPropertyEditorDialog( + properties, "Edit Project"); + editor.setVisible(true); + if (ButtonDialog.OK.equals(editor.getSelectedButtonCaption())) { + plugInPort.applyPropertiesToProject(properties); + } + // Save default values. + for (PropertyWrapper property : editor.getDefaultedProperties()) { + if (property.getValue() != null) { + plugInPort.setProjectDefaultPropertyValue(property.getName(), property + .getValue()); + } + } + } + } + + public static class EditSelectionAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + + public EditSelectionAction(IPlugInPort plugInPort) { + super(); + this.plugInPort = plugInPort; + putValue(AbstractAction.NAME, "Edit Selection"); + putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_E, + ActionEvent.CTRL_MASK)); + putValue(AbstractAction.SMALL_ICON, IconLoader.EditComponent.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("Edit Selection triggered"); + List properties = plugInPort.getMutualSelectionProperties(); + if (properties == null || properties.isEmpty()) { + LOG.info("Nothing to edit"); + return; + } + plugInPort.editSelection(); + } + } + + public static class DeleteSelectionAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + + public DeleteSelectionAction(IPlugInPort plugInPort) { + super(); + this.plugInPort = plugInPort; + putValue(AbstractAction.NAME, "Delete Selection"); + putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0)); + putValue(AbstractAction.SMALL_ICON, IconLoader.Delete.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("Delete Selection triggered"); + plugInPort.deleteSelectedComponents(); + } + } + + public static class ExpandSelectionAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + private ExpansionMode expansionMode; + + public ExpandSelectionAction(IPlugInPort plugInPort, ExpansionMode expansionMode) { + super(); + this.plugInPort = plugInPort; + this.expansionMode = expansionMode; + switch (expansionMode) { + case ALL: + putValue(AbstractAction.NAME, "All Connected"); + break; + case IMMEDIATE: + putValue(AbstractAction.NAME, "Immediate Only"); + break; + case SAME_TYPE: + putValue(AbstractAction.NAME, "Same Type Only"); + break; + + default: + break; + } + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("Expand Selection triggered: " + expansionMode); + plugInPort.expandSelection(expansionMode); + } + } + + public static class SendToBackAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + + public SendToBackAction(IPlugInPort plugInPort) { + super(); + this.plugInPort = plugInPort; + putValue(AbstractAction.NAME, "Send Backward"); + putValue(AbstractAction.SMALL_ICON, IconLoader.Back.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("Send to Back triggered"); + plugInPort.sendSelectionToBack(); + } + } + + public static class BringToFrontAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + + public BringToFrontAction(IPlugInPort plugInPort) { + super(); + this.plugInPort = plugInPort; + putValue(AbstractAction.NAME, "Bring Forward"); + putValue(AbstractAction.SMALL_ICON, IconLoader.Front.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info("Bring to Front triggered"); + plugInPort.bringSelectionToFront(); + } + } + + public static class ConfigAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + private String configKey; + + public ConfigAction(IPlugInPort plugInPort, String title, String configKey, + boolean defaultValue) { + super(); + this.plugInPort = plugInPort; + this.configKey = configKey; + putValue(AbstractAction.NAME, title); + putValue(IView.CHECK_BOX_MENU_ITEM, true); + putValue(AbstractAction.SELECTED_KEY, ConfigurationManager.getInstance().readBoolean( + configKey, defaultValue)); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info(getValue(AbstractAction.NAME) + " triggered"); + ConfigurationManager.getInstance().writeValue(configKey, + getValue(AbstractAction.SELECTED_KEY)); + plugInPort.refresh(); + } + } + + public static class ThemeAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + private Theme theme; + + public ThemeAction(IPlugInPort plugInPort, Theme theme) { + super(); + this.plugInPort = plugInPort; + this.theme = theme; + putValue(AbstractAction.NAME, theme.getName()); + putValue(IView.RADIO_BUTTON_GROUP_KEY, "theme"); + putValue(AbstractAction.SELECTED_KEY, plugInPort.getSelectedTheme().getName().equals( + theme.getName())); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info(getValue(AbstractAction.NAME) + " triggered"); + plugInPort.setSelectedTheme(theme); + } + } + + public static class RenumberAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + private boolean xAxisFirst; + + public RenumberAction(IPlugInPort plugInPort, boolean xAxisFirst) { + super(); + this.plugInPort = plugInPort; + this.xAxisFirst = xAxisFirst; + putValue(AbstractAction.NAME, xAxisFirst ? "X Axis First" : "Y Axis First"); + } + + @Override + public void actionPerformed(ActionEvent e) { + LOG.info(getValue(AbstractAction.NAME) + " triggered"); + plugInPort.renumberSelectedComponents(xAxisFirst); + } + } +} diff --git a/diylc-swing/src/org/diylc/swing/ISwingUI.java b/diylc-swing/src/org/diylc/swing/ISwingUI.java new file mode 100644 index 00000000..b316113f --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/ISwingUI.java @@ -0,0 +1,64 @@ +package org.diylc.swing; + +import javax.swing.Action; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.SwingConstants; +import javax.swing.JPopupMenu.Separator; + +import org.diylc.common.BadPositionException; +import org.diylc.common.ITask; +import org.diylc.core.IView; + +/** + * Interface for plugin access to the swing front end. + * + * @author Branislav Stojkovic + */ +public interface ISwingUI extends IView { + + /** + * Injects a custom GUI panels provided by the plug-in and desired position + * in the window. Application will layout plug-in panels accordingly.
+ * Valid positions are: + *
    + *
  • {@link SwingConstants#TOP}
  • + *
  • {@link SwingConstants#BOTTOM}
  • + *
  • {@link SwingConstants#LEFT}
  • + *
  • {@link SwingConstants#RIGHT}
  • + *
+ * + * Center position is reserved for the main canvas panel and cannot be used. + * + * @param component + * @param position + * @throws BadPositionException + * in case invalid position is specified + */ + void injectGUIComponent(JComponent component, int position) throws BadPositionException; + + /** + * Injects a custom menu action into application's main menu. If + * action is set to null {@link Separator} will be added. If + * the specified menu does not exist it will be automatically created. + * + * @param action + * {@link Action} to inser + * @param menuName + * name of the menu to insert into + */ + void injectMenuAction(Action action, String menuName); + + /** + * Injects a custom submenu into application's main menu. If + * action is set to null {@link Separator} will be added. If + * the specified menu does not exist it will be automatically created. + * + * @param name + * @param icon + * @param parentMenuName + */ + void injectSubmenu(String name, Icon icon, String parentMenuName); + + void executeBackgroundTask(ITask task); +} diff --git a/diylc-swing/src/org/diylc/swing/gui/CustomGlassPane.java b/diylc-swing/src/org/diylc/swing/gui/CustomGlassPane.java new file mode 100644 index 00000000..9852bdcd --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/gui/CustomGlassPane.java @@ -0,0 +1,42 @@ +package org.diylc.swing.gui; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; + +import javax.swing.Icon; +import javax.swing.JComponent; + +public class CustomGlassPane extends JComponent { + + private static final long serialVersionUID = 1L; + private Icon icon; + + public CustomGlassPane() { + super(); + addMouseMotionListener(new MouseMotionAdapter() { + + @Override + public void mouseMoved(MouseEvent e) { + if (icon != null) { + repaint(); + } + } + }); + } + + public void setCursorIcon(Icon icon) { + this.icon = icon; + } + + @Override + public void paint(Graphics g) { + Point cursor = getMousePosition(); + if ((icon != null) && (cursor != null)) { + Graphics2D g2d = (Graphics2D) g; + icon.paintIcon(this, g2d, cursor.x + 10, cursor.y + 10); + } + } +} diff --git a/diylc-swing/src/org/diylc/swing/gui/DialogFactory.java b/diylc-swing/src/org/diylc/swing/gui/DialogFactory.java new file mode 100644 index 00000000..373e0c3f --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/gui/DialogFactory.java @@ -0,0 +1,154 @@ +package org.diylc.swing.gui; + +import java.io.File; +import java.util.List; + +import javax.swing.Icon; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.filechooser.FileFilter; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.PropertyWrapper; +import org.diylc.swing.gui.components.OverwritePromptFileChooser; +import org.diylc.swing.gui.editor.PropertyEditorDialog; +import org.diylc.swing.plugins.file.BomDialog; +import org.diylc.swing.plugins.online.view.LoginDialog; +import org.diylc.swing.plugins.online.view.NewUserDialog; +import org.diylc.swing.plugins.online.view.UploadDialog; +import org.diylc.swingframework.AboutDialog; +import org.diylc.swingframework.IFileChooserAccessory; +import org.diylc.swingframework.ProgressDialog; +import org.diylc.utils.BomEntry; + +public class DialogFactory { + + private static DialogFactory instance; + + private static final String PATH_KEY = "lastPath"; + + public static DialogFactory getInstance() { + if (instance == null) { + instance = new DialogFactory(); + } + return instance; + } + + private JFrame mainFrame; + private File lastDirectory; + + private DialogFactory() { + } + + /** + * Sets the frame to be used as dialog parent. This should be called prior + * to any other methods in this class. + * + * @param mainFrame + */ + public void initialize(JFrame mainFrame) { + this.mainFrame = mainFrame; + String lastDirectoryPath = (String) ConfigurationManager.getInstance() + .readString(PATH_KEY, null); + if (lastDirectoryPath != null) { + lastDirectory = new File(lastDirectoryPath); + } + } + + public PropertyEditorDialog createPropertyEditorDialog(List properties, + String title) { + PropertyEditorDialog editor = new PropertyEditorDialog(mainFrame, properties, title); + return editor; + } + + public BomDialog createBomDialog(List bom) { + BomDialog dialog = new BomDialog(mainFrame, bom); + return dialog; + } + + public File showOpenDialog(FileFilter fileFilter, File initialFile, String defaultExtension, + IFileChooserAccessory accessory) { + JFileChooser openFileChooser = new JFileChooser(); + initializeFileChooser(openFileChooser, fileFilter, initialFile, defaultExtension, accessory); + + int result = openFileChooser.showOpenDialog(mainFrame); + + return processFileChooserResult(result, openFileChooser, defaultExtension); + } + + public File showSaveDialog(FileFilter fileFilter, File initialFile, String defaultExtension, + IFileChooserAccessory accessory) { + JFileChooser saveFileChooser = new OverwritePromptFileChooser(); + initializeFileChooser(saveFileChooser, fileFilter, initialFile, defaultExtension, accessory); + + int result = saveFileChooser.showSaveDialog(mainFrame); + + return processFileChooserResult(result, saveFileChooser, defaultExtension); + } + + private void initializeFileChooser(JFileChooser fileChooser, FileFilter fileFilter, + File initialFile, String defaultExtension, IFileChooserAccessory accessory) { + if (accessory != null) { + accessory.install(fileChooser); + } + for (FileFilter filter : fileChooser.getChoosableFileFilters()) { + fileChooser.removeChoosableFileFilter(filter); + } + if (fileChooser instanceof OverwritePromptFileChooser) { + ((OverwritePromptFileChooser) fileChooser).setFileFilter(fileFilter, defaultExtension); + } else { + fileChooser.setFileFilter(fileFilter); + } + if (lastDirectory != null) { + fileChooser.setCurrentDirectory(lastDirectory); + } + fileChooser.setSelectedFile(initialFile); + } + + private File processFileChooserResult(int result, JFileChooser fileChooser, + String defaultExtension) { + fileChooser.setAccessory(null); + if (result == JFileChooser.APPROVE_OPTION) { + lastDirectory = fileChooser.getCurrentDirectory(); + ConfigurationManager.getInstance().writeValue(PATH_KEY, + lastDirectory.getAbsolutePath()); + if (fileChooser.getSelectedFile().getAbsolutePath().contains(".")) { + return fileChooser.getSelectedFile(); + } else { + return new File(fileChooser.getSelectedFile().getAbsoluteFile() + "." + + defaultExtension); + } + } else { + return null; + } + } + + public AboutDialog createAboutDialog(String appName, Icon icon, String version, String author, + String url, String mail, String htmlContent) { + AboutDialog dialog = new AboutDialog(mainFrame, appName, icon, version, author, url, mail, + htmlContent); + return dialog; + } + + public NewUserDialog createNewUserDialog() { + NewUserDialog dialog = new NewUserDialog(mainFrame); + return dialog; + } + + public LoginDialog createLoginDialog() { + LoginDialog dialog = new LoginDialog(mainFrame); + return dialog; + } + + public UploadDialog createUploadDialog() { + UploadDialog dialog = new UploadDialog(mainFrame); + return dialog; + } + + public ProgressDialog createProgressDialog(String title, String[] buttonCaptions, + String description, boolean useProgress) { + ProgressDialog dialog = new ProgressDialog(mainFrame, title, buttonCaptions, description, + useProgress); + return dialog; + } +} diff --git a/diylc-swing/src/org/diylc/swing/gui/MainFrame.java b/diylc-swing/src/org/diylc/swing/gui/MainFrame.java new file mode 100644 index 00000000..5f1b8516 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/gui/MainFrame.java @@ -0,0 +1,377 @@ +package org.diylc.swing.gui; + +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.swing.Action; +import javax.swing.BoxLayout; +import javax.swing.ButtonGroup; +import javax.swing.Icon; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.SwingConstants; +import javax.swing.SwingWorker; +import javax.swing.Timer; + +import org.apache.log4j.Logger; +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.BadPositionException; +import org.diylc.common.EventType; +import org.diylc.common.IPlugIn; +import org.diylc.common.IPlugInPort; +import org.diylc.common.ITask; +import org.diylc.common.PropertyWrapper; +import org.diylc.core.IView; +import org.diylc.images.IconLoader; +import org.diylc.presenter.Presenter; +import org.diylc.swing.ISwingUI; +import org.diylc.swing.gui.editor.PropertyEditorDialog; +import org.diylc.swing.plugins.autosave.AutoSavePlugin; +import org.diylc.swing.plugins.canvas.CanvasPlugin; +import org.diylc.swing.plugins.config.ConfigPlugin; +import org.diylc.swing.plugins.edit.EditMenuPlugin; +import org.diylc.swing.plugins.file.FileFilterEnum; +import org.diylc.swing.plugins.file.FileMenuPlugin; +import org.diylc.swing.plugins.help.HelpMenuPlugin; +import org.diylc.swing.plugins.layers.LayersMenuPlugin; +import org.diylc.swing.plugins.statusbar.StatusBar; +import org.diylc.swing.plugins.toolbox.ToolBox; +import org.diylc.swingframework.ButtonDialog; + +public class MainFrame extends JFrame implements ISwingUI { + + private static final Logger LOG = Logger.getLogger(MainFrame.class); + + private static final long serialVersionUID = 1L; + + private JPanel centerPanel; + private JPanel leftPanel; + private JPanel rightPanel; + private JPanel topPanel; + private JPanel bottomPanel; + + private Presenter presenter; + + private JMenuBar mainMenuBar; + private Map menuMap; + private Map buttonGroupMap; + + private CanvasPlugin canvasPlugin; + + public MainFrame() { + super("DIYLC 3"); + setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + setPreferredSize(new Dimension(800, 600)); + createBasePanels(); + menuMap = new HashMap(); + buttonGroupMap = new HashMap(); + setIconImages(Arrays.asList(IconLoader.IconSmall.getImage(), IconLoader.IconMedium + .getImage(), IconLoader.IconLarge.getImage())); + DialogFactory.getInstance().initialize(this); + + this.presenter = new Presenter(this); + + presenter.installPlugin(new ToolBox(this)); + presenter.installPlugin(new FileMenuPlugin(this)); + presenter.installPlugin(new EditMenuPlugin(this)); + presenter.installPlugin(new ConfigPlugin(this)); + presenter.installPlugin(new LayersMenuPlugin(this)); + // presenter.installPlugin(new OnlineManager()); + presenter.installPlugin(new HelpMenuPlugin(this)); + + presenter.installPlugin(new StatusBar(this)); + canvasPlugin = new CanvasPlugin(this); + presenter.installPlugin(canvasPlugin); + presenter.installPlugin(new FramePlugin()); + + try { + File testFile = new File("test.tmp"); + Writer out = new OutputStreamWriter(new FileOutputStream(testFile)); + out.write("This is a test"); + out.close(); + testFile.delete(); + presenter.installPlugin(new AutoSavePlugin(this)); + } catch (Exception e) { + showMessage( + "The current user does not have permissions to access folder " + + new File(".").getAbsolutePath() + + ".\nAuto-save feature will not be available, contact your system administrator.", + "Warning", IView.WARNING_MESSAGE); + } + + presenter.createNewProject(); + + addWindowListener(new WindowAdapter() { + + @Override + public void windowClosed(WindowEvent e) { + if (presenter.allowFileAction()) { + ConfigurationManager.getInstance().writeValue(IPlugInPort.ABNORMAL_EXIT_KEY, + false); + dispose(); + presenter.dispose(); + System.exit(0); + } + } + + @Override + public void windowClosing(WindowEvent e) { + if (presenter.allowFileAction()) { + ConfigurationManager.getInstance().writeValue(IPlugInPort.ABNORMAL_EXIT_KEY, + false); + dispose(); + presenter.dispose(); + System.exit(0); + } + } + }); + + // setGlassPane(new CustomGlassPane()); + // getGlassPane().setVisible(true); + } + + public Presenter getPresenter() { + return presenter; + } + + @Override + public void setVisible(boolean b) { + super.setVisible(b); + // TODO: hack to prevent painting issues in the scroll bar rulers. Find + // a better fix if possible. + Timer timer = new Timer(500, new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + canvasPlugin.refresh(); + } + + }); + timer.setRepeats(false); + timer.start(); + // if (b) { + // SwingUtilities.invokeLater(new Runnable() { + // @Override + // public void run() { + // + // } + // }); + // } + } + + private void createBasePanels() { + Container c = new Container(); + c.setLayout(new BorderLayout()); + + centerPanel = new JPanel(new BorderLayout()); + c.add(centerPanel, BorderLayout.CENTER); + + topPanel = new JPanel(); + topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.Y_AXIS)); + c.add(topPanel, BorderLayout.NORTH); + + leftPanel = new JPanel(); + leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.X_AXIS)); + c.add(leftPanel, BorderLayout.WEST); + + bottomPanel = new JPanel(); + bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.Y_AXIS)); + c.add(bottomPanel, BorderLayout.SOUTH); + + rightPanel = new JPanel(); + rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.X_AXIS)); + c.add(rightPanel, BorderLayout.EAST); + + setContentPane(c); + } + + private JMenuBar getMainMenuBar() { + if (mainMenuBar == null) { + mainMenuBar = new JMenuBar(); + setJMenuBar(mainMenuBar); + } + return mainMenuBar; + } + + // IView + + @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); + } + + @Override + public boolean editProperties(List properties, + Set defaultedProperties) { + PropertyEditorDialog editor = DialogFactory.getInstance().createPropertyEditorDialog( + properties, "Edit Selection"); + editor.setVisible(true); + defaultedProperties.addAll(editor.getDefaultedProperties()); + return ButtonDialog.OK.equals(editor.getSelectedButtonCaption()); + } + + private JMenu findOrCreateMenu(String menuName) { + JMenu menu; + if (menuMap.containsKey(menuName)) { + menu = menuMap.get(menuName); + } else { + menu = new JMenu(menuName); + menuMap.put(menuName, menu); + getMainMenuBar().add(menu); + } + return menu; + } + + @Override + public void injectGUIComponent(JComponent component, int position) throws BadPositionException { + LOG.info(String.format("injectGUIComponent(%s, %s)", component.getClass().getName(), + position)); + switch (position) { + case SwingConstants.TOP: + topPanel.add(component); + break; + case SwingConstants.LEFT: + leftPanel.add(component); + break; + case SwingConstants.BOTTOM: + bottomPanel.add(component); + break; + case SwingConstants.RIGHT: + rightPanel.add(component); + break; + case SwingConstants.CENTER: + centerPanel.add(component, BorderLayout.CENTER); + break; + default: + throw new BadPositionException(); + } + pack(); + } + + @Override + public void injectMenuAction(Action action, String menuName) { + LOG.info(String.format("injectMenuAction(%s, %s)", action == null ? "Separator" : action + .getValue(Action.NAME), menuName)); + JMenu menu = findOrCreateMenu(menuName); + if (action == null) { + menu.addSeparator(); + } else { + Boolean isCheckBox = (Boolean) action.getValue(IView.CHECK_BOX_MENU_ITEM); + String groupName = (String) action.getValue(IView.RADIO_BUTTON_GROUP_KEY); + if (isCheckBox != null && isCheckBox) { + menu.add(new JCheckBoxMenuItem(action)); + } else if (groupName != null) { + ButtonGroup group; + if (buttonGroupMap.containsKey(groupName)) { + group = buttonGroupMap.get(groupName); + } else { + group = new ButtonGroup(); + buttonGroupMap.put(groupName, group); + } + JRadioButtonMenuItem item = new JRadioButtonMenuItem(action); + group.add(item); + menu.add(item); + } else { + menu.add(action); + } + } + } + + @Override + public void injectSubmenu(String name, Icon icon, String parentMenuName) { + LOG.info(String.format("injectSubmenu(%s, icon, %s)", name, parentMenuName)); + JMenu menu = findOrCreateMenu(parentMenuName); + JMenu submenu = new JMenu(name); + submenu.setIcon(icon); + menu.add(submenu); + menuMap.put(name, submenu); + } + + @Override + public void executeBackgroundTask(final ITask task) { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + SwingWorker worker = new SwingWorker() { + + @Override + protected T doInBackground() throws Exception { + return task.doInBackground(); + } + + @Override + protected void done() { + try { + T result = get(); + task.complete(result); + } catch (Exception e) { + LOG.error("Task failed", e); + task.failed(e); + } + setCursor(Cursor.getDefaultCursor()); + } + }; + worker.execute(); + } + + @Override + public File promptFileSave() { + return DialogFactory.getInstance().showSaveDialog( + FileFilterEnum.DIY.getFilter(), null, + FileFilterEnum.DIY.getExtensions()[0], null); + } + + class FramePlugin implements IPlugIn { + + private IPlugInPort plugInPort; + + @Override + public void connect(IPlugInPort plugInPort) { + this.plugInPort = plugInPort; + } + + @Override + public EnumSet getSubscribedEventTypes() { + return EnumSet.of(EventType.FILE_STATUS_CHANGED); + } + + @Override + public void processMessage(EventType eventType, Object... params) { + if (eventType == EventType.FILE_STATUS_CHANGED) { + String fileName = (String) params[0]; + if (fileName == null) { + fileName = "Untitled"; + } + String modified = (Boolean) params[1] ? " (modified)" : ""; + setTitle(String.format("DIYLC %s - %s %s", plugInPort + .getCurrentVersionNumber(), fileName, modified)); + } + } + } + +} diff --git a/diylc-swing/src/org/diylc/swing/gui/TemplateDialog.java b/diylc-swing/src/org/diylc/swing/gui/TemplateDialog.java new file mode 100644 index 00000000..7f7160bd --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/gui/TemplateDialog.java @@ -0,0 +1,289 @@ +package org.diylc.swing.gui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + +import javax.swing.BorderFactory; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import org.apache.log4j.Logger; +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.DrawOption; +import org.diylc.common.IPlugInPort; +import org.diylc.common.PropertyWrapper; +import org.diylc.core.IView; +import org.diylc.presenter.Presenter; + +public class TemplateDialog extends JDialog { + + private static final long serialVersionUID = 1L; + + private static final Logger LOG = Logger.getLogger(TemplateDialog.class); + + private static final Dimension panelSize = new Dimension(400, 300); + public static final String SHOW_TEMPLATES_KEY = "showTemplatesAtStartup"; + + private IPlugInPort plugInPort; + + private JList fileList; + private JPanel canvasPanel; + private Presenter presenter; + private List files; + private JCheckBox showTemplatesBox; + private JPanel mainPanel; + private JButton loadButton; + private JPanel infoPanel; + + public TemplateDialog(JFrame owner, IPlugInPort plugInPort) { + super(owner, "Templates"); + setModal(true); + setResizable(false); + this.plugInPort = plugInPort; + this.presenter = new Presenter(new IView() { + + @Override + public int showConfirmDialog(String message, String title, int optionType, + int messageType) { + return JOptionPane.showConfirmDialog(TemplateDialog.this, message, title, + optionType, messageType); + } + + @Override + public void showMessage(String message, String title, int messageType) { + JOptionPane.showMessageDialog(TemplateDialog.this, message, title, messageType); + } + + @Override + public File promptFileSave() { + return null; + } + + @Override + public boolean editProperties(List properties, Set defaultedProperties) { + return false; + } + }); + // this.presenter.installPlugin(new IPlugIn() { + // + // @Override + // public void connect(IPlugInPort plugInPort) { + // } + // + // @Override + // public EnumSet getSubscribedEventTypes() { + // return EnumSet.of(EventType.REPAINT); + // } + // + // @Override + // public void processMessage(EventType eventType, Object... params) { + // if (eventType == EventType.REPAINT) { + // getCanvasPanel().repaint(); + // } + // } + // }); + setContentPane(getMainPanel()); + pack(); + setLocationRelativeTo(owner); + } + + public JPanel getMainPanel() { + if (mainPanel == null) { + mainPanel = new JPanel(new GridBagLayout()); + mainPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); + + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.weightx = 0; + c.weighty = 1; + c.weightx = 1; + c.gridwidth = 2; + c.fill = GridBagConstraints.BOTH; + c.insets = new Insets(0, 0, 4, 0); + mainPanel.add(getInfoPanel(), c); + + c.gridy = 1; + c.weightx = 0; + c.gridwidth = 1; + c.insets = new Insets(0, 0, 0, 0); + JScrollPane scrollPane = new JScrollPane(getFileList()); + mainPanel.add(scrollPane, c); + + c.gridx = 1; + c.weightx = 1; + + JPanel panel = new JPanel(new BorderLayout()); + panel.setBorder(scrollPane.getBorder()); + panel.add(getCanvasPanel(), BorderLayout.CENTER); + mainPanel.add(panel, c); + + c.gridx = 0; + c.gridy = 2; + c.weightx = 0; + c.weighty = 0; + c.anchor = GridBagConstraints.LAST_LINE_START; + c.fill = GridBagConstraints.NONE; + mainPanel.add(getShowTemplatesBox(), c); + + c.gridx = 1; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(4, 0, 0, 0); + mainPanel.add(getLoadButton(), c); + } + return mainPanel; + } + + public JButton getLoadButton() { + if (loadButton == null) { + loadButton = new JButton("Load Template"); + loadButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + plugInPort.loadProject(presenter.getCurrentProject(), true); + dispose(); + } + }); + } + return loadButton; + } + + public JPanel getInfoPanel() { + if (infoPanel == null) { + infoPanel = new JPanel(); + infoPanel.setBackground(Color.decode("#FFFFCC")); + infoPanel.setBorder(new JTextField().getBorder()); + JLabel infoLabel = new JLabel( + "Templates are semi-product layouts that are used as a starting point for your projects.
" + + "Pick a templete in the left list and click \"Load Template\" to load it or close this dialog to continue.
" + + "You can create your own templates by placing a DIY file into diylc/templates directory."); + infoLabel.setOpaque(false); + infoPanel.add(infoLabel); + } + return infoPanel; + } + + public JList getFileList() { + if (fileList == null) { + fileList = new JList(getFiles().toArray()); + fileList.setPreferredSize(new Dimension(128, -1)); + fileList.setCellRenderer(new DefaultListCellRenderer() { + + private static final long serialVersionUID = 1L; + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, + isSelected, cellHasFocus); + if (value instanceof File) { + label.setText(((File) value).getName()); + } + return label; + } + + }); + fileList.addListSelectionListener(new ListSelectionListener() { + + @Override + public void valueChanged(ListSelectionEvent e) { + File file = (File) fileList.getSelectedValue(); + if (file != null) { + presenter.loadProjectFromFile(file.getAbsolutePath()); + Dimension dim = presenter.getCanvasDimensions(true); + double xFactor = panelSize.getWidth() / dim.getWidth(); + double yFactor = panelSize.getHeight() / dim.getHeight(); + presenter.setZoomLevel(Math.min(xFactor, yFactor)); + getCanvasPanel().repaint(); + } + } + }); + fileList.setSelectedIndex(0); + } + return fileList; + } + + public JCheckBox getShowTemplatesBox() { + if (showTemplatesBox == null) { + showTemplatesBox = new JCheckBox("Show this dialog at startup"); + showTemplatesBox.setSelected(true); + showTemplatesBox.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + ConfigurationManager.getInstance().writeValue(SHOW_TEMPLATES_KEY, + showTemplatesBox.isSelected()); + } + }); + } + return showTemplatesBox; + } + + public List getFiles() { + if (files == null) { + files = new ArrayList(); + File dir = new File("templates"); + if (dir.exists()) { + for (File f : dir.listFiles()) { + if (f.isFile() && f.getName().toLowerCase().endsWith(".diy")) { + files.add(f); + } + } + } + LOG.debug("Found " + files.size() + " templates"); + } + return files; + } + + public JPanel getCanvasPanel() { + if (canvasPanel == null) { + canvasPanel = new JPanel() { + + private static final long serialVersionUID = 1L; + + @Override + public void paint(Graphics g) { + super.paint(g); + // Graphics2D g2d = (Graphics2D) g; + // AffineTransform transform = g2d.getTransform(); + presenter.draw((Graphics2D) g, EnumSet.of(DrawOption.ZOOM, + DrawOption.ANTIALIASING), null); + // g2d.setTransform(transform); + // Rectangle rect = canvasPanel.getBounds(); + // BorderFactory.createEtchedBorder().paintBorder(canvasPanel, + // g, 0, 0, + // (int) rect.getWidth(), (int) rect.getHeight()); + } + }; + canvasPanel.setBackground(Color.white); + canvasPanel.setPreferredSize(panelSize); + } + return canvasPanel; + } +} diff --git a/diylc-swing/src/org/diylc/swing/gui/components/OverwritePromptFileChooser.java b/diylc-swing/src/org/diylc/swing/gui/components/OverwritePromptFileChooser.java new file mode 100644 index 00000000..514d47eb --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/gui/components/OverwritePromptFileChooser.java @@ -0,0 +1,38 @@ +package org.diylc.swing.gui.components; + +import java.io.File; + +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import javax.swing.filechooser.FileFilter; + +public class OverwritePromptFileChooser extends JFileChooser { + + private static final long serialVersionUID = 1L; + private String defaultExtension; + + public void approveSelection() { + File lSelectedFile; + if (getSelectedFile().getAbsolutePath().contains(".")) { + lSelectedFile = getSelectedFile(); + } else { + lSelectedFile = new File(getSelectedFile().getAbsoluteFile() + "." + defaultExtension); + } + + if (lSelectedFile != null && lSelectedFile.exists()) { + int lResponse = JOptionPane.showConfirmDialog(this, lSelectedFile.getAbsolutePath() + + " already exists.\nDo you " + "want to replace it?", "Warning", + JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + + if (lResponse != JOptionPane.YES_OPTION) { + return; + } + } + super.approveSelection(); + } + + public void setFileFilter(FileFilter filter, String defaultExtension) { + this.defaultExtension = defaultExtension; + super.setFileFilter(filter); + } +} diff --git a/diylc-swing/src/org/diylc/swing/gui/editor/BooleanEditor.java b/diylc-swing/src/org/diylc/swing/gui/editor/BooleanEditor.java new file mode 100644 index 00000000..c8842b26 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/gui/editor/BooleanEditor.java @@ -0,0 +1,34 @@ +package org.diylc.swing.gui.editor; + +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JCheckBox; + +import org.diylc.common.PropertyWrapper; +import org.diylc.utils.Constants; + +public class BooleanEditor extends JCheckBox { + + private static final long serialVersionUID = 1L; + + private Color oldBg = getBackground(); + + public BooleanEditor(final PropertyWrapper property) { + super(); + setSelected((Boolean) property.getValue()); + addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + property.setChanged(true); + setBackground(oldBg); + property.setValue(isSelected()); + } + }); + if (!property.isUnique()) { + setBackground(Constants.MULTI_VALUE_COLOR); + } + } +} diff --git a/diylc-swing/src/org/diylc/swing/gui/editor/ByteEditor.java b/diylc-swing/src/org/diylc/swing/gui/editor/ByteEditor.java new file mode 100644 index 00000000..05d72207 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/gui/editor/ByteEditor.java @@ -0,0 +1,36 @@ +package org.diylc.swing.gui.editor; + +import java.awt.Color; + +import javax.swing.JSlider; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.diylc.common.PropertyWrapper; +import org.diylc.utils.Constants; + +public class ByteEditor extends JSlider { + + private static final long serialVersionUID = 1L; + + private Color oldBg = getBackground(); + + public ByteEditor(final PropertyWrapper property) { + super(); + setMinimum(0); + setMaximum(127); + setValue((Byte) property.getValue()); + addChangeListener(new ChangeListener() { + + @Override + public void stateChanged(ChangeEvent e) { + property.setChanged(true); + setBackground(oldBg); + property.setValue(new Integer(getValue()).byteValue()); + } + }); + if (!property.isUnique()) { + setBackground(Constants.MULTI_VALUE_COLOR); + } + } +} diff --git a/diylc-swing/src/org/diylc/swing/gui/editor/ColorEditor.java b/diylc-swing/src/org/diylc/swing/gui/editor/ColorEditor.java new file mode 100644 index 00000000..24e16ef2 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/gui/editor/ColorEditor.java @@ -0,0 +1,52 @@ +package org.diylc.swing.gui.editor; + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.BorderFactory; +import javax.swing.JColorChooser; +import javax.swing.JLabel; +import javax.swing.SwingConstants; + +import org.diylc.common.PropertyWrapper; + +public class ColorEditor extends JLabel { + + private static final long serialVersionUID = 1L; + + private static final String title = "Click to edit"; + + public ColorEditor(final PropertyWrapper property) { + super(property.isUnique() ? title : ("(multi value) " + title)); + setOpaque(true); + setHorizontalAlignment(SwingConstants.CENTER); + setBorder(BorderFactory.createEtchedBorder()); + setBackground((Color) property.getValue()); + setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + addMouseListener(new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + Color newColor = JColorChooser.showDialog(ColorEditor.this, "Choose Color", + getBackground()); + if (newColor != null) { + property.setChanged(true); + property.setValue(newColor); + setBackground(newColor); + } + } + }); + } + + @Override + public void setBackground(Color bg) { + if (bg.getRed() < 127 || bg.getBlue() < 127 || bg.getGreen() < 127) { + setForeground(Color.white); + } else { + setForeground(Color.black); + } + super.setBackground(bg); + } +} diff --git a/diylc-swing/src/org/diylc/swing/gui/editor/EnumEditor.java b/diylc-swing/src/org/diylc/swing/gui/editor/EnumEditor.java new file mode 100644 index 00000000..d53bf2c6 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/gui/editor/EnumEditor.java @@ -0,0 +1,41 @@ +package org.diylc.swing.gui.editor; + +import java.awt.Color; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; + +import org.diylc.common.PropertyWrapper; +import org.diylc.utils.Constants; + +public class EnumEditor extends JComboBox { + + private static final long serialVersionUID = 1L; + + private Color oldBg = getBackground(); + + private final PropertyWrapper property; + + public EnumEditor(final PropertyWrapper property) { + this.property = property; + Object[] values = property.getType().getEnumConstants(); + setModel(new DefaultComboBoxModel(values)); + setSelectedItem(property.getValue()); + addItemListener(new ItemListener() { + + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + property.setChanged(true); + setBackground(oldBg); + EnumEditor.this.property.setValue(e.getItem()); + } + } + }); + if (!property.isUnique()) { + setBackground(Constants.MULTI_VALUE_COLOR); + } + } +} diff --git a/diylc-swing/src/org/diylc/swing/gui/editor/FieldEditorFactory.java b/diylc-swing/src/org/diylc/swing/gui/editor/FieldEditorFactory.java new file mode 100644 index 00000000..1eca8238 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/gui/editor/FieldEditorFactory.java @@ -0,0 +1,61 @@ +package org.diylc.swing.gui.editor; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; + +import javax.swing.ImageIcon; +import javax.swing.JLabel; + +import org.apache.log4j.Logger; +import org.diylc.common.PropertyWrapper; +import org.diylc.core.measures.AbstractMeasure; + +public class FieldEditorFactory { + + private static final Logger LOG = Logger.getLogger(FieldEditorFactory.class); + + public static Component createFieldEditor(PropertyWrapper property) { + if (property.getType().equals(String.class)) { + StringEditor editor = new StringEditor(property); + return editor; + } + if (property.getType().equals(Color.class)) { + ColorEditor editor = new ColorEditor(property); + return editor; + } + if (AbstractMeasure.class.isAssignableFrom(property.getType())) { + MeasureEditor editor = new MeasureEditor(property); + return editor; + } + if (ImageIcon.class.isAssignableFrom(property.getType())) { + ImageEditor editor = new ImageEditor(property); + return editor; + } + if (property.getType().isEnum()) { + EnumEditor editor = new EnumEditor(property); + return editor; + } + if (Byte.class.isAssignableFrom(property.getType()) + || byte.class.isAssignableFrom(property.getType())) { + ByteEditor editor = new ByteEditor(property); + return editor; + } + if (Boolean.class.isAssignableFrom(property.getType()) + || boolean.class.isAssignableFrom(property.getType())) { + BooleanEditor editor = new BooleanEditor(property); + return editor; + } + if (Font.class.isAssignableFrom(property.getType())) { + FontEditor editor = new FontEditor(property); + return editor; + } + if (Integer.class.isAssignableFrom(property.getType()) + || int.class.isAssignableFrom(property.getType())) { + IntEditor editor = new IntEditor(property); + return editor; + } + LOG.error("Unrecognized parameter type: " + property.getType().getName()); + return new JLabel("Unrecognized"); + } +} diff --git a/diylc-swing/src/org/diylc/swing/gui/editor/FontEditor.java b/diylc-swing/src/org/diylc/swing/gui/editor/FontEditor.java new file mode 100644 index 00000000..cc37c5b9 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/gui/editor/FontEditor.java @@ -0,0 +1,41 @@ +package org.diylc.swing.gui.editor; + +import java.awt.Color; +import java.awt.Font; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import org.diylc.common.PropertyWrapper; +import org.diylc.swingframework.FontChooserComboBox; +import org.diylc.utils.Constants; + +public class FontEditor extends FontChooserComboBox { + + private static final long serialVersionUID = 1L; + + private Color oldBg = getBackground(); + + private final PropertyWrapper property; + + public FontEditor(final PropertyWrapper property) { + this.property = property; + setSelectedItem(((Font) property.getValue()).getName()); + addItemListener(new ItemListener() { + + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + property.setChanged(true); + setBackground(oldBg); + Font oldFont = (Font) FontEditor.this.property.getValue(); + Font newFont = new Font(getSelectedItem().toString(), oldFont.getStyle(), + oldFont.getSize()); + FontEditor.this.property.setValue(newFont); + } + } + }); + if (!property.isUnique()) { + setBackground(Constants.MULTI_VALUE_COLOR); + } + } +} diff --git a/diylc-swing/src/org/diylc/swing/gui/editor/ImageEditor.java b/diylc-swing/src/org/diylc/swing/gui/editor/ImageEditor.java new file mode 100644 index 00000000..11bdb574 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/gui/editor/ImageEditor.java @@ -0,0 +1,46 @@ +package org.diylc.swing.gui.editor; + +import java.awt.event.ActionListener; +import java.io.File; + +import javax.swing.ImageIcon; +import javax.swing.JButton; + +import org.diylc.common.PropertyWrapper; +import org.diylc.swing.gui.DialogFactory; +import org.diylc.swing.plugins.file.FileFilterEnum; + +public class ImageEditor extends JButton { + + private static final long serialVersionUID = 1L; + + private static final String title = "Click to load image file"; + + public ImageEditor(final PropertyWrapper property) { + super(property.isUnique() ? title : ("(multi value) " + title)); + addActionListener(new ActionListener() { + + @Override + public void actionPerformed(java.awt.event.ActionEvent e) { + File file = DialogFactory.getInstance().showOpenDialog( + FileFilterEnum.IMAGES.getFilter(), null, + FileFilterEnum.IMAGES.getExtensions()[0], null); + if (file != null) { + property.setChanged(true); + ImageIcon image = new ImageIcon(file.getAbsolutePath()); + property.setValue(image); + } + } + }); + } + + // @Override + // public void setBackground(Color bg) { + // if (bg.getRed() < 127 || bg.getBlue() < 127 || bg.getGreen() < 127) { + // setForeground(Color.white); + // } else { + // setForeground(Color.black); + // } + // super.setBackground(bg); + // } +} diff --git a/diylc-swing/src/org/diylc/swing/gui/editor/IntEditor.java b/diylc-swing/src/org/diylc/swing/gui/editor/IntEditor.java new file mode 100644 index 00000000..9c316d87 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/gui/editor/IntEditor.java @@ -0,0 +1,34 @@ +package org.diylc.swing.gui.editor; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import org.diylc.common.PropertyWrapper; +import org.diylc.swingframework.DoubleTextField; +import org.diylc.utils.Constants; + +public class IntEditor extends DoubleTextField { + + private static final long serialVersionUID = 1L; + + private Color oldBg = getBackground(); + + public IntEditor(final PropertyWrapper property) { + setLayout(new BorderLayout()); + setValue((double) (Integer) property.getValue()); + addPropertyChangeListener(DoubleTextField.VALUE_PROPERTY, new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + property.setChanged(true); + setBackground(oldBg); + property.setValue(((Double) evt.getNewValue()).intValue()); + } + }); + if (!property.isUnique()) { + setBackground(Constants.MULTI_VALUE_COLOR); + } + } +} diff --git a/diylc-swing/src/org/diylc/swing/gui/editor/MeasureEditor.java b/diylc-swing/src/org/diylc/swing/gui/editor/MeasureEditor.java new file mode 100644 index 00000000..ab9b1201 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/gui/editor/MeasureEditor.java @@ -0,0 +1,113 @@ +package org.diylc.swing.gui.editor; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Container; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import javax.swing.JComboBox; + +import org.diylc.common.PropertyWrapper; +import org.diylc.core.measures.AbstractMeasure; +import org.diylc.core.measures.Unit; +import org.diylc.swingframework.DoubleTextField; +import org.diylc.utils.Constants; + +public class MeasureEditor extends Container { + + private static final long serialVersionUID = 1L; + + private Color oldBg; + private DoubleTextField valueField; + private JComboBox unitBox; + + @SuppressWarnings("unchecked") + public MeasureEditor(final PropertyWrapper property) { + setLayout(new BorderLayout()); + AbstractMeasure measure = ((AbstractMeasure) property.getValue()); + valueField = new DoubleTextField(measure.getValue()); + oldBg = valueField.getBackground(); + valueField.addPropertyChangeListener(DoubleTextField.VALUE_PROPERTY, + new PropertyChangeListener() { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + try { + AbstractMeasure newMeasure = (AbstractMeasure) ((AbstractMeasure) property + .getValue()).clone(); + newMeasure.setValue((Double) evt.getNewValue()); + property.setValue(newMeasure); + property.setChanged(true); + valueField.setBackground(oldBg); + unitBox.setBackground(oldBg); + } catch (CloneNotSupportedException ex) { + } + } + }); + add(valueField, BorderLayout.CENTER); + try { + Method method = measure.getUnit().getClass().getMethod("values"); + unitBox = new JComboBox((Object[]) method.invoke(measure.getUnit())); + unitBox.setSelectedItem(measure.getUnit()); + unitBox.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + try { + AbstractMeasure> newMeasure = (AbstractMeasure>) ((AbstractMeasure) property + .getValue()).clone(); + newMeasure.setUnit((Enum) unitBox.getSelectedItem()); + property.setValue(newMeasure); + property.setChanged(true); + valueField.setBackground(oldBg); + unitBox.setBackground(oldBg); + } catch (CloneNotSupportedException ex) { + } + } + }); + add(unitBox, BorderLayout.EAST); + + if (!property.isUnique()) { + valueField.setBackground(Constants.MULTI_VALUE_COLOR); + unitBox.setBackground(Constants.MULTI_VALUE_COLOR); + } + } catch (IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (NoSuchMethodException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Override + public void requestFocus() { + this.valueField.requestFocus(); + } + + @Override + public boolean requestFocusInWindow() { + return this.valueField.requestFocusInWindow(); + } + + @Override + public synchronized void addKeyListener(KeyListener l) { + this.valueField.addKeyListener(l); + this.unitBox.addKeyListener(l); + } +} diff --git a/diylc-swing/src/org/diylc/swing/gui/editor/PropertyEditorDialog.java b/diylc-swing/src/org/diylc/swing/gui/editor/PropertyEditorDialog.java new file mode 100644 index 00000000..6717280a --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/gui/editor/PropertyEditorDialog.java @@ -0,0 +1,190 @@ +package org.diylc.swing.gui.editor; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.swing.BorderFactory; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import org.apache.log4j.Logger; +import org.diylc.common.PropertyWrapper; +import org.diylc.core.ValidationException; +import org.diylc.swingframework.ButtonDialog; + +public class PropertyEditorDialog extends ButtonDialog { + + private static final Logger LOG = Logger + .getLogger(PropertyEditorDialog.class); + + private static final long serialVersionUID = 1L; + + private static final String DEFAULT_BOX_TOOLTIP = "If this box is checked application will use the current value as a
default when creating new components of the same type"; + + private List properties; + private Set defaultedProperties; + private Component componentToFocus = null; + + public PropertyEditorDialog(JFrame owner, List properties, + String title) { + super(owner, title, + new String[] { ButtonDialog.OK, ButtonDialog.CANCEL }); + + LOG.debug("Creating property editor for: " + properties); + + this.properties = properties; + this.defaultedProperties = new HashSet(); + + setMinimumSize(new Dimension(240, 40)); + + layoutGui(); + setLocationRelativeTo(owner); + // + // setModal(true); + // + // JPanel holderPanel = new JPanel(); + // holderPanel.setLayout(new BorderLayout()); + // holderPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); + // + // holderPanel.add(createEditorFields(), BorderLayout.CENTER); + // holderPanel.add(createButtonPanel(), BorderLayout.SOUTH); + // + // setContentPane(holderPanel); + // + // + // pack(); + // setLocationRelativeTo(owner); + } + + @Override + protected boolean validateInput(String button) { + if (button.equals(ButtonDialog.OK)) { + for (PropertyWrapper property : properties) { + try { + property.getValidator().validate(property.getValue()); + } catch (ValidationException ve) { + JOptionPane.showMessageDialog(PropertyEditorDialog.this, + "Input error for \"" + property.getName() + "\": " + + ve.getMessage(), "Error", + JOptionPane.ERROR_MESSAGE); + return false; + } + } + } + return true; + } + + private JPanel createEditorFields() { + JPanel editorPanel = new JPanel(new GridBagLayout()); + editorPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); + + GridBagConstraints gbc = new GridBagConstraints(); + + gbc.gridy = 0; + gbc.insets = new Insets(2, 2, 2, 2); + gbc.anchor = GridBagConstraints.LINE_START; + + for (PropertyWrapper property : properties) { + gbc.gridx = 0; + gbc.fill = GridBagConstraints.NONE; + gbc.weightx = 0; + + editorPanel.add(new JLabel(property.getName() + ": "), gbc); + + gbc.gridx = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.weightx = 1; + + Component editor = FieldEditorFactory.createFieldEditor(property); + editor.addKeyListener(new KeyAdapter() { + + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + getButton(OK).doClick(); + } else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { + getButton(CANCEL).doClick(); + } + } + }); + editorPanel.add(editor, gbc); + + if (property.isDefaultable()) { + gbc.gridx = 2; + gbc.fill = GridBagConstraints.NONE; + gbc.weightx = 0; + + editorPanel.add(createDefaultCheckBox(property), gbc); + } + + // Make value field focused + if (property.getName().equalsIgnoreCase("value")) { + componentToFocus = editor; + } + + gbc.gridy++; + } + + return editorPanel; + } + + private JCheckBox createDefaultCheckBox(final PropertyWrapper property) { + final JCheckBox checkBox = new JCheckBox(); + checkBox.setToolTipText(DEFAULT_BOX_TOOLTIP); + checkBox.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (checkBox.isSelected()) { + defaultedProperties.add(property); + } else { + defaultedProperties.remove(property); + } + } + }); + return checkBox; + } + + public Set getDefaultedProperties() { + return defaultedProperties; + } + + public static boolean showFor(JFrame owner, + List properties, String title) { + PropertyEditorDialog editor = new PropertyEditorDialog(owner, + properties, title); + editor.setVisible(true); + if (OK.equals(editor.getSelectedButtonCaption())) { + return true; + } + return false; + } + + @Override + public void setVisible(boolean b) { + if (b && componentToFocus != null) { + componentToFocus.requestFocusInWindow(); + componentToFocus = null; + } + super.setVisible(b); + } + + @Override + protected JComponent getMainComponent() { + return createEditorFields(); + } +} diff --git a/diylc-swing/src/org/diylc/swing/gui/editor/StringEditor.java b/diylc-swing/src/org/diylc/swing/gui/editor/StringEditor.java new file mode 100644 index 00000000..3dbf9e16 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/gui/editor/StringEditor.java @@ -0,0 +1,50 @@ +package org.diylc.swing.gui.editor; + +import java.awt.Color; + +import javax.swing.JTextField; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +import org.diylc.common.PropertyWrapper; +import org.diylc.utils.Constants; + +public class StringEditor extends JTextField { + + private static final long serialVersionUID = 1L; + + private Color oldBg = getBackground(); + + private final PropertyWrapper property; + + public StringEditor(PropertyWrapper property) { + super(property.getValue() == null ? "" : (String) property.getValue()); + this.property = property; + getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void changedUpdate(DocumentEvent e) { + textChanged(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + textChanged(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + textChanged(); + } + }); + if (!property.isUnique()) { + setBackground(Constants.MULTI_VALUE_COLOR); + } + } + + private void textChanged() { + property.setChanged(true); + setBackground(oldBg); + property.setValue(getText()); + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/autosave/AutoSavePlugin.java b/diylc-swing/src/org/diylc/swing/plugins/autosave/AutoSavePlugin.java new file mode 100644 index 00000000..9631373d --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/autosave/AutoSavePlugin.java @@ -0,0 +1,82 @@ +package org.diylc.swing.plugins.autosave; + +import java.io.File; +import java.util.EnumSet; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.swing.SwingUtilities; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.EventType; +import org.diylc.common.IPlugIn; +import org.diylc.common.IPlugInPort; +import org.diylc.core.IView; + +public class AutoSavePlugin implements IPlugIn { + + private static final String AUTO_SAVE_FILE_NAME = "autoSave.diy"; + + protected static final long autoSaveFrequency = 60 * 1000; + + private ExecutorService executor; + + private IPlugInPort plugInPort; + private IView view; + private long lastSave = 0; + + public AutoSavePlugin(IView view) { + this.view = view; + executor = Executors.newSingleThreadExecutor(); + } + + @Override + public void connect(IPlugInPort plugInPort) { + this.plugInPort = plugInPort; + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + boolean wasAbnormal = ConfigurationManager.getInstance() + .readBoolean(IPlugInPort.ABNORMAL_EXIT_KEY, false); + if (wasAbnormal && new File(AUTO_SAVE_FILE_NAME).exists()) { + int decision = view + .showConfirmDialog( + "It appears that aplication was not closed normally in the previous session. Do you want to open the last auto-saved file?", + "Auto-Save", IView.YES_NO_OPTION, + IView.QUESTION_MESSAGE); + if (decision == IView.YES_OPTION) { + AutoSavePlugin.this.plugInPort + .loadProjectFromFile(AUTO_SAVE_FILE_NAME); + } + } + // Set abnormal flag to true, GUI side of the app must flip to + // false when app closes regularly. + ConfigurationManager.getInstance().writeValue( + IPlugInPort.ABNORMAL_EXIT_KEY, true); + } + }); + } + + @Override + public EnumSet getSubscribedEventTypes() { + return EnumSet.of(EventType.PROJECT_MODIFIED); + } + + @Override + public void processMessage(EventType eventType, Object... params) { + if (eventType == EventType.PROJECT_MODIFIED) { + executor.execute(new Runnable() { + + @Override + public void run() { + Thread.currentThread().setPriority(Thread.MIN_PRIORITY); + if (System.currentTimeMillis() - lastSave > autoSaveFrequency) { + lastSave = System.currentTimeMillis(); + plugInPort.saveProjectToFile(AUTO_SAVE_FILE_NAME, true); + } + } + }); + } + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasGestureListener.java b/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasGestureListener.java new file mode 100644 index 00000000..504360a8 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasGestureListener.java @@ -0,0 +1,28 @@ +package org.diylc.swing.plugins.canvas; + +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; + +import org.diylc.common.IPlugInPort; + +/** + * {@link DragGestureListener} for {@link CanvasPanel}. + * + * @author Branislav Stojkovic + */ +class CanvasGestureListener implements DragGestureListener { + + private IPlugInPort presenter; + + public CanvasGestureListener(IPlugInPort presenter) { + super(); + this.presenter = presenter; + } + + @Override + public void dragGestureRecognized(DragGestureEvent dge) { + presenter.dragStarted(dge.getDragOrigin(), dge.getDragAction()); + dge.startDrag(presenter.getCursorAt(dge.getDragOrigin()), new EmptyTransferable(), + new CanvasSourceListener(presenter)); + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasPanel.java b/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasPanel.java new file mode 100644 index 00000000..a4271c7b --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasPanel.java @@ -0,0 +1,219 @@ +package org.diylc.swing.plugins.canvas; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.dnd.Autoscroll; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragSource; +import java.awt.dnd.DropTarget; +import java.awt.event.ActionEvent; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.image.VolatileImage; +import java.util.EnumSet; +import java.util.Set; + +import javax.swing.AbstractAction; +import javax.swing.JComponent; +import javax.swing.KeyStroke; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.DrawOption; +import org.diylc.common.IPlugInPort; + +/** + * GUI class used to draw onto. + * + * @author Branislav Stojkovic + */ +class CanvasPanel extends JComponent implements Autoscroll { + + private static final long serialVersionUID = 1L; + + private IPlugInPort plugInPort; + + private Image bufferImage; + private GraphicsConfiguration screenGraphicsConfiguration; + + public static boolean USE_HARDWARE_ACCELLERATION = false; + + // static final EnumSet DRAW_OPTIONS = + // EnumSet.of(DrawOption.GRID, + // DrawOption.SELECTION, DrawOption.ZOOM, DrawOption.CONTROL_POINTS); + // static final EnumSet DRAW_OPTIONS_ANTI_ALIASING = + // EnumSet.of(DrawOption.GRID, + // DrawOption.SELECTION, DrawOption.ZOOM, DrawOption.ANTIALIASING, + // DrawOption.CONTROL_POINTS); + + public CanvasPanel(IPlugInPort plugInPort) { + super(); + this.plugInPort = plugInPort; + setFocusable(true); + initializeListeners(); + initializeDnD(); + GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment + .getLocalGraphicsEnvironment(); + GraphicsDevice[] devices = graphicsEnvironment.getScreenDevices(); + screenGraphicsConfiguration = devices[0].getDefaultConfiguration(); + + initializeActions(); + } + + public void invalidateCache() { + bufferImage = null; + } + + private void initializeDnD() { + // Initialize drag source recognizer. + DragSource.getDefaultDragSource().createDefaultDragGestureRecognizer( + this, + DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_LINK, + new CanvasGestureListener(plugInPort)); + // Initialize drop target. + new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, + new CanvasTargetListener(plugInPort), true); + } + + private void initializeActions() { + getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "clearSlot"); + getActionMap().put("clearSlot", new AbstractAction() { + + private static final long serialVersionUID = 1L; + + @Override + public void actionPerformed(ActionEvent e) { + CanvasPanel.this.plugInPort.setNewComponentTypeSlot(null); + } + }); + } + + protected void createBufferImage() { + if (USE_HARDWARE_ACCELLERATION) { + bufferImage = screenGraphicsConfiguration + .createCompatibleVolatileImage(getWidth(), getHeight()); + ((VolatileImage) bufferImage).validate(screenGraphicsConfiguration); + } else { + bufferImage = createImage(getWidth(), getHeight()); + } + } + + @Override + public void paint(Graphics g) { + if (plugInPort == null) { + return; + } + if (bufferImage == null) { + createBufferImage(); + } + Graphics2D g2d = (Graphics2D) bufferImage.getGraphics(); + g2d.setClip(getVisibleRect()); + Set drawOptions = EnumSet.of(DrawOption.GRID, + DrawOption.SELECTION, DrawOption.ZOOM, + DrawOption.CONTROL_POINTS); + if (ConfigurationManager.getInstance().readBoolean( + IPlugInPort.ANTI_ALIASING_KEY, true)) { + drawOptions.add(DrawOption.ANTIALIASING); + } + if (ConfigurationManager.getInstance().readBoolean( + IPlugInPort.OUTLINE_KEY, false)) { + drawOptions.add(DrawOption.OUTLINE_MODE); + } + plugInPort.draw(g2d, drawOptions, null); + if (USE_HARDWARE_ACCELLERATION) { + VolatileImage volatileImage = (VolatileImage) bufferImage; + do { + try { + if (volatileImage.contentsLost()) { + createBufferImage(); + } + // int validation = + // volatileImage.validate(screenGraphicsConfiguration); + // if (validation == VolatileImage.IMAGE_INCOMPATIBLE) { + // createBufferImage(); + // } + g.drawImage(bufferImage, 0, 0, this); + } catch (NullPointerException e) { + createBufferImage(); + } + } while (volatileImage == null || volatileImage.contentsLost()); + } else { + g.drawImage(bufferImage, 0, 0, this); + // bufferImage.flush(); + } + g2d.dispose(); + } + + @Override + public void update(Graphics g) { + paint(g); + } + + private void initializeListeners() { + addComponentListener(new ComponentAdapter() { + + @Override + public void componentResized(ComponentEvent e) { + invalidateCache(); + invalidate(); + } + }); + // addKeyListener(new KeyAdapter() { + // + // @Override + // public void keyPressed(KeyEvent e) { + // if (e.getKeyCode() == KeyEvent.VK_DELETE) { + // plugInPort.deleteSelectedComponents(); + // } + // // plugInPort.mouseMoved(getMousePosition(), e.isControlDown(), + // // e.isShiftDown(), e + // // .isAltDown()); + // } + // }); + addMouseMotionListener(new MouseAdapter() { + + @Override + public void mouseMoved(MouseEvent e) { + setCursor(plugInPort.getCursorAt(e.getPoint())); + plugInPort.mouseMoved(e.getPoint(), e.isControlDown(), e + .isShiftDown(), e.isAltDown()); + } + }); + addMouseListener(new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + plugInPort.mouseClicked(e.getPoint(), e.getButton(), e + .isControlDown(), e.isShiftDown(), e.isAltDown(), e + .getClickCount()); + } + } + }); + } + + // Autoscroll + + @Override + public void autoscroll(Point cursorLocn) { + scrollRectToVisible(new Rectangle(cursorLocn.x - 15, cursorLocn.y - 15, + 30, 30)); + } + + @Override + public Insets getAutoscrollInsets() { + Rectangle rect = getVisibleRect(); + return new Insets(rect.y - 15, rect.x - 15, rect.y + rect.height + 15, + rect.x + rect.width + 15); + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasPlugin.java b/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasPlugin.java new file mode 100644 index 00000000..3833ef83 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasPlugin.java @@ -0,0 +1,449 @@ +package org.diylc.swing.plugins.canvas; + +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.ClipboardOwner; +import java.awt.datatransfer.Transferable; +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.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; + +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.SwingConstants; + +import org.apache.log4j.Logger; +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.appframework.miscutils.IConfigListener; +import org.diylc.common.BadPositionException; +import org.diylc.common.EventType; +import org.diylc.common.IPlugIn; +import org.diylc.common.IPlugInPort; +import org.diylc.core.CreationMethod; +import org.diylc.core.ExpansionMode; +import org.diylc.core.IDIYComponent; +import org.diylc.core.measures.Size; +import org.diylc.core.measures.SizeUnit; +import org.diylc.images.IconLoader; +import org.diylc.presenter.Presenter; +import org.diylc.swing.ActionFactory; +import org.diylc.swing.ISwingUI; +import org.diylc.swing.plugins.edit.ComponentTransferable; +import org.diylc.swing.plugins.file.ProjectDrawingProvider; +import org.diylc.swingframework.ruler.IRulerListener; +import org.diylc.swingframework.ruler.RulerScrollPane; + +public class CanvasPlugin implements IPlugIn, ClipboardOwner { + + private static final Logger LOG = Logger.getLogger(CanvasPlugin.class); + + private RulerScrollPane scrollPane; + private CanvasPanel canvasPanel; + private JPopupMenu popupMenu; + private JMenu selectionMenu; + private JMenu expandMenu; + + private ActionFactory.CutAction cutAction; + private ActionFactory.CopyAction copyAction; + private ActionFactory.PasteAction pasteAction; + private ActionFactory.EditSelectionAction editSelectionAction; + private ActionFactory.DeleteSelectionAction deleteSelectionAction; + private ActionFactory.GroupAction groupAction; + private ActionFactory.UngroupAction ungroupAction; + private ActionFactory.SendToBackAction sendToBackAction; + private ActionFactory.BringToFrontAction bringToFrontAction; + private ActionFactory.ExpandSelectionAction expandSelectionAllAction; + private ActionFactory.ExpandSelectionAction expandSelectionImmediateAction; + private ActionFactory.ExpandSelectionAction expandSelectionSameTypeAction; + + private IPlugInPort plugInPort; + private ISwingUI swingUI; + + private Clipboard clipboard; + + private double zoomLevel = 1; + + public CanvasPlugin(ISwingUI swingUI) { + this.swingUI = swingUI; + clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + } + + @Override + public void connect(IPlugInPort plugInPort) { + this.plugInPort = plugInPort; + try { + swingUI.injectGUIComponent(getScrollPane(), SwingConstants.CENTER); + } catch (BadPositionException e) { + LOG.error("Could not install canvas plugin", e); + } + } + + public CanvasPanel getCanvasPanel() { + if (canvasPanel == null) { + canvasPanel = new CanvasPanel(plugInPort); + canvasPanel.addMouseListener(new MouseAdapter() { + + @Override + public void mousePressed(MouseEvent e) { + canvasPanel.requestFocus(); + } + + @Override + public void mouseReleased(MouseEvent e) { + if (plugInPort.getNewComponentTypeSlot() != null && plugInPort.getNewComponentTypeSlot().getCreationMethod() == CreationMethod.SINGLE_CLICK) { + plugInPort.mouseClicked(e.getPoint(), e.getButton(), + false, false, false, e.getClickCount()); + } else if (e.isPopupTrigger()) { + // Enable actions. + boolean enabled = !plugInPort.getSelectedComponents() + .isEmpty(); + getCutAction().setEnabled(enabled); + getCopyAction().setEnabled(enabled); + try { + getPasteAction() + .setEnabled( + clipboard + .isDataFlavorAvailable(ComponentTransferable.listFlavor)); + } catch (Exception ex) { + getPasteAction().setEnabled(false); + } + getEditSelectionAction().setEnabled(enabled); + getDeleteSelectionAction().setEnabled(enabled); + getExpandSelectionAllAction().setEnabled(enabled); + getExpandSelectionImmediateAction().setEnabled(enabled); + getExpandSelectionSameTypeAction().setEnabled(enabled); + getGroupAction().setEnabled(enabled); + getUngroupAction().setEnabled(enabled); + getSendToBackAction().setEnabled(enabled); + getBringToFrontAction().setEnabled(enabled); + + showPopupAt(e.getX(), e.getY()); + } + } + }); + + canvasPanel.addKeyListener(new KeyAdapter() { + + @Override + public void keyPressed(KeyEvent e) { + if (plugInPort.keyPressed(e.getKeyCode(), + e.isControlDown(), e.isShiftDown(), e.isAltDown())) { + e.consume(); + } + } + }); + } + return canvasPanel; + } + + private RulerScrollPane getScrollPane() { + if (scrollPane == null) { + scrollPane = new RulerScrollPane(getCanvasPanel(), + new ProjectDrawingProvider(plugInPort, true, false), + new Size(1d, SizeUnit.cm).convertToPixels(), new Size(1d, + SizeUnit.in).convertToPixels()); + boolean metric = ConfigurationManager.getInstance().readBoolean( + Presenter.METRIC_KEY, true); + boolean wheelZoom = ConfigurationManager.getInstance().readBoolean( + IPlugInPort.WHEEL_ZOOM_KEY, false); + ConfigurationManager.getInstance().addConfigListener( + IPlugInPort.WHEEL_ZOOM_KEY, new IConfigListener() { + + @Override + public void valueChanged(String key, Object value) { + scrollPane + .setWheelScrollingEnabled(!(Boolean) value); + } + }); + scrollPane.setMetric(metric); + scrollPane.setWheelScrollingEnabled(!wheelZoom); + scrollPane.addUnitListener(new IRulerListener() { + + @Override + public void unitsChanged(boolean isMetric) { + plugInPort.setMetric(isMetric); + } + }); + scrollPane.addMouseWheelListener(new MouseWheelListener() { + + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + boolean wheelZoom = ConfigurationManager.getInstance() + .readBoolean(IPlugInPort.WHEEL_ZOOM_KEY, false); + if (!wheelZoom) { + return; + } + double d = plugInPort.getZoomLevel(); + Double[] availableZoomLevels = plugInPort + .getAvailableZoomLevels(); + if (e.getWheelRotation() > 0) { + int i = availableZoomLevels.length - 1; + while (i > 0 && availableZoomLevels[i] >= d) { + i--; + } + plugInPort.setZoomLevel(availableZoomLevels[i]); + } else { + int i = 0; + while (i < availableZoomLevels.length - 1 + && availableZoomLevels[i] <= d) { + i++; + } + plugInPort.setZoomLevel(availableZoomLevels[i]); + } + } + }); + } + return scrollPane; + } + + private void showPopupAt(int x, int y) { + updateSelectionMenu(x, y); + getPopupMenu().show(canvasPanel, x, y); + } + + public JPopupMenu getPopupMenu() { + if (popupMenu == null) { + popupMenu = new JPopupMenu(); + popupMenu.add(getSelectionMenu()); + popupMenu.addSeparator(); + popupMenu.add(getCutAction()); + popupMenu.add(getCopyAction()); + popupMenu.add(getPasteAction()); + popupMenu.addSeparator(); + popupMenu.add(getEditSelectionAction()); + popupMenu.add(getDeleteSelectionAction()); + popupMenu.add(getGroupAction()); + popupMenu.add(getUngroupAction()); + popupMenu.add(getSendToBackAction()); + popupMenu.add(getBringToFrontAction()); + popupMenu.add(getExpandMenu()); + popupMenu.addSeparator(); + popupMenu.add(ActionFactory.getInstance().createEditProjectAction( + plugInPort)); + } + return popupMenu; + } + + public JMenu getSelectionMenu() { + if (selectionMenu == null) { + selectionMenu = new JMenu("Select"); + selectionMenu.setIcon(IconLoader.ElementsSelection.getIcon()); + } + return selectionMenu; + } + + public JMenu getExpandMenu() { + if (expandMenu == null) { + expandMenu = new JMenu("Expand Selection"); + expandMenu.setIcon(IconLoader.BranchAdd.getIcon()); + expandMenu.add(getExpandSelectionAllAction()); + expandMenu.add(getExpandSelectionImmediateAction()); + expandMenu.add(getExpandSelectionSameTypeAction()); + } + return expandMenu; + } + + private void updateSelectionMenu(int x, int y) { + getSelectionMenu().removeAll(); + for (IDIYComponent component : plugInPort + .findComponentsAt(new Point(x, y))) { + JMenuItem item = new JMenuItem(component.getName()); + final IDIYComponent finalComponent = component; + item.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + List> newSelection = new ArrayList>(); + newSelection.add(finalComponent); + plugInPort.updateSelection(newSelection); + plugInPort.refresh(); + } + }); + getSelectionMenu().add(item); + } + } + + public ActionFactory.CutAction getCutAction() { + if (cutAction == null) { + cutAction = ActionFactory.getInstance().createCutAction(plugInPort, + clipboard, this); + } + return cutAction; + } + + public ActionFactory.CopyAction getCopyAction() { + if (copyAction == null) { + copyAction = ActionFactory.getInstance().createCopyAction( + plugInPort, clipboard, this); + } + return copyAction; + } + + public ActionFactory.PasteAction getPasteAction() { + if (pasteAction == null) { + pasteAction = ActionFactory.getInstance().createPasteAction( + plugInPort, clipboard); + } + return pasteAction; + } + + public ActionFactory.EditSelectionAction getEditSelectionAction() { + if (editSelectionAction == null) { + editSelectionAction = ActionFactory.getInstance() + .createEditSelectionAction(plugInPort); + } + return editSelectionAction; + } + + public ActionFactory.DeleteSelectionAction getDeleteSelectionAction() { + if (deleteSelectionAction == null) { + deleteSelectionAction = ActionFactory.getInstance() + .createDeleteSelectionAction(plugInPort); + } + return deleteSelectionAction; + } + + public ActionFactory.GroupAction getGroupAction() { + if (groupAction == null) { + groupAction = ActionFactory.getInstance().createGroupAction( + plugInPort); + } + return groupAction; + } + + public ActionFactory.UngroupAction getUngroupAction() { + if (ungroupAction == null) { + ungroupAction = ActionFactory.getInstance().createUngroupAction( + plugInPort); + } + return ungroupAction; + } + + public ActionFactory.SendToBackAction getSendToBackAction() { + if (sendToBackAction == null) { + sendToBackAction = ActionFactory.getInstance() + .createSendToBackAction(plugInPort); + } + return sendToBackAction; + } + + public ActionFactory.BringToFrontAction getBringToFrontAction() { + if (bringToFrontAction == null) { + bringToFrontAction = ActionFactory.getInstance() + .createBringToFrontAction(plugInPort); + } + return bringToFrontAction; + } + + public ActionFactory.ExpandSelectionAction getExpandSelectionAllAction() { + if (expandSelectionAllAction == null) { + expandSelectionAllAction = ActionFactory.getInstance() + .createExpandSelectionAction(plugInPort, ExpansionMode.ALL); + } + return expandSelectionAllAction; + } + + public ActionFactory.ExpandSelectionAction getExpandSelectionImmediateAction() { + if (expandSelectionImmediateAction == null) { + expandSelectionImmediateAction = ActionFactory.getInstance() + .createExpandSelectionAction(plugInPort, + ExpansionMode.IMMEDIATE); + } + return expandSelectionImmediateAction; + } + + public ActionFactory.ExpandSelectionAction getExpandSelectionSameTypeAction() { + if (expandSelectionSameTypeAction == null) { + expandSelectionSameTypeAction = ActionFactory.getInstance() + .createExpandSelectionAction(plugInPort, + ExpansionMode.SAME_TYPE); + } + return expandSelectionSameTypeAction; + } + + @Override + public EnumSet getSubscribedEventTypes() { + return EnumSet.of(EventType.PROJECT_LOADED, EventType.ZOOM_CHANGED, + EventType.REPAINT); + } + + @Override + public void processMessage(final EventType eventType, Object... params) { + // SwingUtilities.invokeLater(new Runnable() { + // + // @Override + // public void run() { + // LOG.debug("event: " + eventType); + switch (eventType) { + case PROJECT_LOADED: + refreshSize(); + if ((Boolean) params[1]) { + // Scroll to the center. + Rectangle visibleRect = canvasPanel.getVisibleRect(); + visibleRect.setLocation( + (canvasPanel.getWidth() - visibleRect.width) / 2, + (canvasPanel.getHeight() - visibleRect.height) / 2); + canvasPanel.scrollRectToVisible(visibleRect); + canvasPanel.revalidate(); + } + break; + case ZOOM_CHANGED: + Rectangle visibleRect = canvasPanel.getVisibleRect(); + refreshSize(); + // Try to set the visible area to be centered with the previous + // one. + double zoomFactor = (Double) params[0] / zoomLevel; + visibleRect.setBounds((int) (visibleRect.x * zoomFactor), + (int) (visibleRect.y * zoomFactor), visibleRect.width, + visibleRect.height); + canvasPanel.scrollRectToVisible(visibleRect); + canvasPanel.revalidate(); + + zoomLevel = (Double) params[0]; + break; + case REPAINT: + canvasPanel.repaint(); + break; + } + // } + // }); + } + + private void refreshSize() { + Dimension d = plugInPort.getCanvasDimensions(true); + canvasPanel.setSize(d); + canvasPanel.setPreferredSize(d); + getScrollPane().setZoomLevel(plugInPort.getZoomLevel()); + } + + /** + * Causes ruler scroll pane to refresh by sending a fake mouse moved message + * to the canvasPanel. + */ + public void refresh() { + MouseEvent event = new MouseEvent(canvasPanel, MouseEvent.MOUSE_MOVED, + System.currentTimeMillis(), 0, 1, 1,// canvasPanel.getWidth() / + // 2, + // canvasPanel.getHeight() / 2, + 0, false); + canvasPanel.dispatchEvent(event); + } + + @Override + public void lostOwnership(Clipboard clipboard, Transferable contents) { + // TODO Auto-generated method stub + + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasSourceListener.java b/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasSourceListener.java new file mode 100644 index 00000000..61a98185 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasSourceListener.java @@ -0,0 +1,50 @@ +package org.diylc.swing.plugins.canvas; + +import java.awt.Point; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; + +import org.diylc.common.IPlugInPort; + + +/** + * {@link DragSourceListener} for {@link CanvasPanel}. + * + * @author Branislav Stojkovic + */ +class CanvasSourceListener implements DragSourceListener { + + private IPlugInPort presenter; + + public CanvasSourceListener(IPlugInPort presenter) { + super(); + this.presenter = presenter; + } + + @Override + public void dragDropEnd(DragSourceDropEvent dsde) { + presenter.dragEnded(null); + } + + @Override + public void dragEnter(DragSourceDragEvent dsde) { + } + + @Override + public void dragExit(DragSourceEvent dse) { + } + + @Override + public void dragOver(DragSourceDragEvent dsde) { + Point p = dsde.getDragSourceContext().getComponent().getMousePosition(); + if (p != null) { + dsde.getDragSourceContext().getComponent().firePropertyChange("dragPoint", p.x, p.y); + } + } + + @Override + public void dropActionChanged(DragSourceDragEvent dsde) { + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasTargetListener.java b/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasTargetListener.java new file mode 100644 index 00000000..41c2c46a --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/canvas/CanvasTargetListener.java @@ -0,0 +1,96 @@ +package org.diylc.swing.plugins.canvas; + +import java.awt.Point; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; + +import org.diylc.common.IPlugInPort; + + +/** + * {@link DropTargetListener} for {@link CanvasPanel}. + * + * @author Branislav Stojkovic + */ +class CanvasTargetListener implements DropTargetListener { + + private IPlugInPort presenter; + + // Cached values + private Point currentPoint = null; + private boolean lastAccept; + + public CanvasTargetListener(IPlugInPort presenter) { + super(); + this.presenter = presenter; + } + + @Override + public void dragEnter(DropTargetDragEvent dtde) { + } + + @Override + public void dragExit(DropTargetEvent dte) { + } + + @Override + public void dragOver(DropTargetDragEvent dtde) { + // If dragOver was previously called for this location use cached value. + if (dtde.getLocation().equals(currentPoint)) { + if (lastAccept) { + dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE); + } else { + dtde.rejectDrag(); + } + return; + } + try { + // Transferable t = dtde.getTransferable(); + // if + // (t.isDataFlavorSupported(SelectionTransferable.selectionFlavor)) + // { + // if (currentPoint != null) { + // List selection = (List) t + // .getTransferData(SelectionTransferable.selectionFlavor); + // Point startPoint = (Point) t + // .getTransferData(PointTransferable.pointFlavor); + // presenter.selectionMoved(dtde.getLocation().x + // - currentPoint.x, dtde.getLocation().y + // - currentPoint.y); + // } + // } else if + // (t.isDataFlavorSupported(PointTransferable.pointFlavor)) { + // Point startPoint = (Point) t + // .getTransferData(PointTransferable.pointFlavor); + // Point endPoint = dtde.getLocation(); + // presenter.setSelectionRect(Utils.createRectangle(startPoint, + // endPoint)); + // } + currentPoint = dtde.getLocation(); + if (presenter.dragOver(currentPoint)) { + dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE); + lastAccept = true; + } else { + dtde.rejectDrag(); + lastAccept = false; + } + } catch (Exception e) { + e.printStackTrace(); + dtde.rejectDrag(); + lastAccept = false; + } + } + + @Override + public void drop(DropTargetDropEvent dtde) { + presenter.dragEnded(dtde.getLocation()); + } + + @Override + public void dropActionChanged(DropTargetDragEvent dtde) { + presenter.dragActionChanged(dtde.getDropAction()); + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/canvas/EmptyTransferable.java b/diylc-swing/src/org/diylc/swing/plugins/canvas/EmptyTransferable.java new file mode 100644 index 00000000..ccddb7b1 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/canvas/EmptyTransferable.java @@ -0,0 +1,24 @@ +package org.diylc.swing.plugins.canvas; + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.io.IOException; + +public class EmptyTransferable implements Transferable { + + @Override + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { + throw new UnsupportedFlavorException(flavor); + } + + @Override + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] {}; + } + + @Override + public boolean isDataFlavorSupported(DataFlavor flavor) { + return false; + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/canvas/PointTransferable.java b/diylc-swing/src/org/diylc/swing/plugins/canvas/PointTransferable.java new file mode 100644 index 00000000..7c854f82 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/canvas/PointTransferable.java @@ -0,0 +1,38 @@ +package org.diylc.swing.plugins.canvas; + +import java.awt.Point; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.io.IOException; + +public class PointTransferable implements Transferable { + + public static final DataFlavor pointFlavor = new DataFlavor(Point.class, "Java Point"); + + private Point startPoint; + + public PointTransferable(Point startPoint) { + super(); + this.startPoint = startPoint; + } + + @Override + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { + if (flavor.equals(pointFlavor)) { + return startPoint; + } + throw new UnsupportedFlavorException(flavor); + } + + @Override + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { pointFlavor }; + } + + @Override + public boolean isDataFlavorSupported(DataFlavor flavor) { + return flavor.equals(pointFlavor); + } + +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/canvas/SelectionTransferable.java b/diylc-swing/src/org/diylc/swing/plugins/canvas/SelectionTransferable.java new file mode 100644 index 00000000..5901d2fc --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/canvas/SelectionTransferable.java @@ -0,0 +1,47 @@ +package org.diylc.swing.plugins.canvas; + +import java.awt.Point; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.io.IOException; +import java.util.List; + +import org.diylc.core.IDIYComponent; + + +public class SelectionTransferable implements Transferable { + + public static final DataFlavor selectionFlavor = new DataFlavor(List.class, + "Component Selection"); + + private Point startPoint; + private List> selection; + + public SelectionTransferable(List> selection, Point startPoint) { + super(); + this.selection = selection; + this.startPoint = startPoint; + } + + @Override + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { + if (flavor.equals(selectionFlavor)) { + return selection; + } + if (flavor.equals(PointTransferable.pointFlavor)) { + return startPoint; + } + throw new UnsupportedFlavorException(flavor); + } + + @Override + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { selectionFlavor, PointTransferable.pointFlavor }; + } + + @Override + public boolean isDataFlavorSupported(DataFlavor flavor) { + return flavor.equals(selectionFlavor) || flavor.equals(selectionFlavor); + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/config/ConfigPlugin.java b/diylc-swing/src/org/diylc/swing/plugins/config/ConfigPlugin.java new file mode 100644 index 00000000..d12360df --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/config/ConfigPlugin.java @@ -0,0 +1,90 @@ +package org.diylc.swing.plugins.config; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.EnumSet; + +import org.apache.log4j.Logger; +import org.diylc.common.EventType; +import org.diylc.common.IPlugIn; +import org.diylc.common.IPlugInPort; +import org.diylc.core.Theme; +import org.diylc.images.IconLoader; +import org.diylc.swing.ActionFactory; +import org.diylc.swing.ISwingUI; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.xml.DomDriver; + +/** + * Controls configuration menu. + * + * @author Branislav Stojkovic + */ +public class ConfigPlugin implements IPlugIn { + + private static final Logger LOG = Logger.getLogger(ConfigPlugin.class); + + private static final String CONFIG_MENU = "Config"; + private static final String THEME_MENU = "Theme"; + + private ISwingUI swingUI; + + public ConfigPlugin(ISwingUI swingUI) { + super(); + this.swingUI = swingUI; + } + + @Override + public void connect(IPlugInPort plugInPort) { + swingUI.injectMenuAction(ActionFactory.getInstance().createConfigAction(plugInPort, + "Anti-Aliasing", IPlugInPort.ANTI_ALIASING_KEY, true), CONFIG_MENU); + swingUI.injectMenuAction(ActionFactory.getInstance().createConfigAction(plugInPort, + "Auto-Create Pads", IPlugInPort.AUTO_PADS_KEY, false), CONFIG_MENU); + swingUI.injectMenuAction(ActionFactory.getInstance().createConfigAction(plugInPort, + "Auto-Edit Mode", IPlugInPort.AUTO_EDIT_KEY, false), CONFIG_MENU); + swingUI.injectMenuAction(ActionFactory.getInstance().createConfigAction(plugInPort, + "Continuous Creation", IPlugInPort.CONTINUOUS_CREATION_KEY, false), CONFIG_MENU); + swingUI.injectMenuAction(ActionFactory.getInstance().createConfigAction(plugInPort, + "Export Grid", IPlugInPort.EXPORT_GRID_KEY, false), CONFIG_MENU); + swingUI.injectMenuAction(ActionFactory.getInstance().createConfigAction(plugInPort, + "Hi-Quality Rendering", IPlugInPort.HI_QUALITY_RENDER_KEY, false), CONFIG_MENU); + swingUI.injectMenuAction(ActionFactory.getInstance().createConfigAction(plugInPort, + "Mouse Wheel Zoom", IPlugInPort.WHEEL_ZOOM_KEY, false), CONFIG_MENU); + swingUI.injectMenuAction(ActionFactory.getInstance().createConfigAction(plugInPort, + "Outline Mode", IPlugInPort.OUTLINE_KEY, false), CONFIG_MENU); + swingUI.injectMenuAction(ActionFactory.getInstance().createConfigAction(plugInPort, + "Snap to Grid", IPlugInPort.SNAP_TO_GRID_KEY, true), CONFIG_MENU); + swingUI.injectMenuAction(ActionFactory.getInstance().createConfigAction(plugInPort, + "Sticky Points", IPlugInPort.STICKY_POINTS_KEY, true), CONFIG_MENU); + + File themeDir = new File("themes"); + if (themeDir.exists()) { + XStream xStream = new XStream(new DomDriver()); + swingUI.injectSubmenu(THEME_MENU, IconLoader.Pens.getIcon(), CONFIG_MENU); + for (File file : themeDir.listFiles()) { + if (file.getName().toLowerCase().endsWith(".xml")) { + try { + InputStream in = new FileInputStream(file); + Theme theme = (Theme) xStream.fromXML(in); + LOG.debug("Found theme: " + theme.getName()); + swingUI.injectMenuAction(ActionFactory.getInstance().createThemeAction( + plugInPort, theme), THEME_MENU); + } catch (Exception e) { + LOG.error("Could not load theme file " + file.getName(), e); + } + } + } + } + } + + @Override + public EnumSet getSubscribedEventTypes() { + return EnumSet.noneOf(EventType.class); + } + + @Override + public void processMessage(EventType eventType, Object... params) { + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/edit/ComponentTransferable.java b/diylc-swing/src/org/diylc/swing/plugins/edit/ComponentTransferable.java new file mode 100644 index 00000000..e5506739 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/edit/ComponentTransferable.java @@ -0,0 +1,51 @@ +package org.diylc.swing.plugins.edit; + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.diylc.core.IDIYComponent; + +/** + * Represents component selection as a {@link List} of {@link IDIYComponent} + * objects. Implements {@link Transferable}, so it is suitable for clipboard + * usage. + * + * @author Branislav Stojkovic + */ +public class ComponentTransferable extends ArrayList> implements Transferable { + + private static final long serialVersionUID = 1L; + + public static final DataFlavor listFlavor = new DataFlavor(ComponentTransferable.class, "application/diylc"); + + public ComponentTransferable() { + super(); + } + + public ComponentTransferable(Collection> selectedComponents) { + super(selectedComponents); + } + + @Override + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { + if (flavor.equals(listFlavor)) { + return this; + } + throw new UnsupportedFlavorException(flavor); + } + + @Override + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { listFlavor }; + } + + @Override + public boolean isDataFlavorSupported(DataFlavor flavor) { + return flavor.equals(listFlavor); + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/edit/EditMenuPlugin.java b/diylc-swing/src/org/diylc/swing/plugins/edit/EditMenuPlugin.java new file mode 100644 index 00000000..3f06e6ca --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/edit/EditMenuPlugin.java @@ -0,0 +1,259 @@ +package org.diylc.swing.plugins.edit; + +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.ClipboardOwner; +import java.awt.datatransfer.FlavorEvent; +import java.awt.datatransfer.FlavorListener; +import java.awt.datatransfer.Transferable; +import java.util.EnumSet; + +import org.diylc.appframework.undo.IUndoListener; +import org.diylc.appframework.undo.UndoHandler; +import org.diylc.common.EventType; +import org.diylc.common.IPlugIn; +import org.diylc.common.IPlugInPort; +import org.diylc.core.ExpansionMode; +import org.diylc.core.Project; +import org.diylc.images.IconLoader; +import org.diylc.swing.ActionFactory; +import org.diylc.swing.ISwingUI; + +public class EditMenuPlugin implements IPlugIn, ClipboardOwner { + + private static final String EDIT_TITLE = "Edit"; + private static final String RENUMBER_TITLE = "Renumber Selection"; + private static final String EXPAND_TITLE = "Expand Selection"; + + private IPlugInPort plugInPort; + private ISwingUI swingUI; + + private Clipboard clipboard; + + private ActionFactory.CutAction cutAction; + private ActionFactory.CopyAction copyAction; + private ActionFactory.PasteAction pasteAction; + private ActionFactory.EditSelectionAction editSelectionAction; + private ActionFactory.DeleteSelectionAction deleteSelectionAction; + private ActionFactory.GroupAction groupAction; + private ActionFactory.UngroupAction ungroupAction; + private ActionFactory.SendToBackAction sendToBackAction; + private ActionFactory.BringToFrontAction bringToFrontAction; + private ActionFactory.RenumberAction renumberXAxisAction; + private ActionFactory.RenumberAction renumberYAxisAction; + private ActionFactory.ExpandSelectionAction expandSelectionAllAction; + private ActionFactory.ExpandSelectionAction expandSelectionImmediateAction; + private ActionFactory.ExpandSelectionAction expandSelectionSameTypeAction; + + private UndoHandler undoHandler; + + public EditMenuPlugin(ISwingUI swingUI) { + this.swingUI = swingUI; + // SecurityManager securityManager = System.getSecurityManager(); + // if (securityManager != null) { + // try { + // securityManager.checkSystemClipboardAccess(); + // } catch (Exception e) { + // e.printStackTrace(); + // } + // } + clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + undoHandler = new UndoHandler(new IUndoListener() { + + @Override + public void actionPerformed(Project currentState) { + plugInPort.loadProject(currentState, false); + } + }); + clipboard.addFlavorListener(new FlavorListener() { + + @Override + public void flavorsChanged(FlavorEvent e) { + refreshActions(); + } + }); + } + + public ActionFactory.CutAction getCutAction() { + if (cutAction == null) { + cutAction = ActionFactory.getInstance().createCutAction(plugInPort, clipboard, this); + } + return cutAction; + } + + public ActionFactory.CopyAction getCopyAction() { + if (copyAction == null) { + copyAction = ActionFactory.getInstance().createCopyAction(plugInPort, clipboard, this); + } + return copyAction; + } + + public ActionFactory.PasteAction getPasteAction() { + if (pasteAction == null) { + pasteAction = ActionFactory.getInstance().createPasteAction(plugInPort, clipboard); + } + return pasteAction; + } + + public ActionFactory.EditSelectionAction getEditSelectionAction() { + if (editSelectionAction == null) { + editSelectionAction = ActionFactory.getInstance().createEditSelectionAction(plugInPort); + } + return editSelectionAction; + } + + public ActionFactory.DeleteSelectionAction getDeleteSelectionAction() { + if (deleteSelectionAction == null) { + deleteSelectionAction = ActionFactory.getInstance().createDeleteSelectionAction( + plugInPort); + } + return deleteSelectionAction; + } + + public ActionFactory.GroupAction getGroupAction() { + if (groupAction == null) { + groupAction = ActionFactory.getInstance().createGroupAction(plugInPort); + } + return groupAction; + } + + public ActionFactory.UngroupAction getUngroupAction() { + if (ungroupAction == null) { + ungroupAction = ActionFactory.getInstance().createUngroupAction(plugInPort); + } + return ungroupAction; + } + + public ActionFactory.SendToBackAction getSendToBackAction() { + if (sendToBackAction == null) { + sendToBackAction = ActionFactory.getInstance().createSendToBackAction(plugInPort); + } + return sendToBackAction; + } + + public ActionFactory.BringToFrontAction getBringToFrontAction() { + if (bringToFrontAction == null) { + bringToFrontAction = ActionFactory.getInstance().createBringToFrontAction(plugInPort); + } + return bringToFrontAction; + } + + public ActionFactory.RenumberAction getRenumberXAxisAction() { + if (renumberXAxisAction == null) { + renumberXAxisAction = ActionFactory.getInstance() + .createRenumberAction(plugInPort, true); + } + return renumberXAxisAction; + } + + public ActionFactory.RenumberAction getRenumberYAxisAction() { + if (renumberYAxisAction == null) { + renumberYAxisAction = ActionFactory.getInstance().createRenumberAction(plugInPort, + false); + } + return renumberYAxisAction; + } + + public ActionFactory.ExpandSelectionAction getExpandSelectionAllAction() { + if (expandSelectionAllAction == null) { + expandSelectionAllAction = ActionFactory.getInstance().createExpandSelectionAction( + plugInPort, ExpansionMode.ALL); + } + return expandSelectionAllAction; + } + + public ActionFactory.ExpandSelectionAction getExpandSelectionImmediateAction() { + if (expandSelectionImmediateAction == null) { + expandSelectionImmediateAction = ActionFactory.getInstance().createExpandSelectionAction( + plugInPort, ExpansionMode.IMMEDIATE); + } + return expandSelectionImmediateAction; + } + + public ActionFactory.ExpandSelectionAction getExpandSelectionSameTypeAction() { + if (expandSelectionSameTypeAction == null) { + expandSelectionSameTypeAction = ActionFactory.getInstance().createExpandSelectionAction( + plugInPort, ExpansionMode.SAME_TYPE); + } + return expandSelectionSameTypeAction; + } + + @Override + public void connect(IPlugInPort plugInPort) { + this.plugInPort = plugInPort; + + ActionFactory actionFactory = ActionFactory.getInstance(); + + swingUI.injectMenuAction(undoHandler.getUndoAction(), EDIT_TITLE); + swingUI.injectMenuAction(undoHandler.getRedoAction(), EDIT_TITLE); + swingUI.injectMenuAction(null, EDIT_TITLE); + swingUI.injectMenuAction(getCutAction(), EDIT_TITLE); + swingUI.injectMenuAction(getCopyAction(), EDIT_TITLE); + swingUI.injectMenuAction(getPasteAction(), EDIT_TITLE); + swingUI.injectMenuAction(null, EDIT_TITLE); + swingUI.injectMenuAction(actionFactory.createSelectAllAction(plugInPort), EDIT_TITLE); + swingUI.injectMenuAction(getEditSelectionAction(), EDIT_TITLE); + swingUI.injectMenuAction(getDeleteSelectionAction(), EDIT_TITLE); + swingUI.injectMenuAction(getGroupAction(), EDIT_TITLE); + swingUI.injectMenuAction(getUngroupAction(), EDIT_TITLE); + swingUI.injectMenuAction(getSendToBackAction(), EDIT_TITLE); + swingUI.injectMenuAction(getBringToFrontAction(), EDIT_TITLE); + swingUI.injectMenuAction(null, EDIT_TITLE); + swingUI.injectSubmenu(RENUMBER_TITLE, IconLoader.Sort.getIcon(), EDIT_TITLE); + swingUI.injectMenuAction(getRenumberXAxisAction(), RENUMBER_TITLE); + swingUI.injectMenuAction(getRenumberYAxisAction(), RENUMBER_TITLE); + swingUI.injectSubmenu(EXPAND_TITLE, IconLoader.BranchAdd.getIcon(), EDIT_TITLE); + swingUI.injectMenuAction(getExpandSelectionAllAction(), EXPAND_TITLE); + swingUI.injectMenuAction(getExpandSelectionImmediateAction(), EXPAND_TITLE); + swingUI.injectMenuAction(getExpandSelectionSameTypeAction(), EXPAND_TITLE); + swingUI.injectMenuAction(null, EDIT_TITLE); + swingUI.injectMenuAction(actionFactory.createEditProjectAction(plugInPort), EDIT_TITLE); + + refreshActions(); + } + + @Override + public EnumSet getSubscribedEventTypes() { + return EnumSet.of(EventType.SELECTION_CHANGED, EventType.PROJECT_MODIFIED); + } + + @Override + public void processMessage(EventType eventType, Object... params) { + switch (eventType) { + case SELECTION_CHANGED: + refreshActions(); + break; + case PROJECT_MODIFIED: + undoHandler.stateChanged((Project) params[0], (Project) params[1], (String) params[2]); + break; + } + } + + private void refreshActions() { + boolean enabled = !plugInPort.getSelectedComponents().isEmpty(); + getCutAction().setEnabled(enabled); + getCopyAction().setEnabled(enabled); + try { + getPasteAction().setEnabled( + clipboard.isDataFlavorAvailable(ComponentTransferable.listFlavor)); + } catch (Exception e) { + getPasteAction().setEnabled(false); + } + getEditSelectionAction().setEnabled(enabled); + getDeleteSelectionAction().setEnabled(enabled); + getGroupAction().setEnabled(enabled); + getExpandSelectionAllAction().setEnabled(enabled); + getExpandSelectionImmediateAction().setEnabled(enabled); + getExpandSelectionSameTypeAction().setEnabled(enabled); + getUngroupAction().setEnabled(enabled); + getSendToBackAction().setEnabled(enabled); + getBringToFrontAction().setEnabled(enabled); + } + + // ClipboardOwner + + @Override + public void lostOwnership(Clipboard clipboard, Transferable contents) { + refreshActions(); + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/file/BomDialog.java b/diylc-swing/src/org/diylc/swing/plugins/file/BomDialog.java new file mode 100644 index 00000000..1d8c4921 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/file/BomDialog.java @@ -0,0 +1,180 @@ +package org.diylc.swing.plugins.file; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; + +import org.diylc.images.IconLoader; +import org.diylc.swing.gui.DialogFactory; +import org.diylc.swingframework.export.TableExporter; +import org.diylc.swingframework.objecttable.ObjectListTable; +import org.diylc.utils.BomEntry; + +public class BomDialog extends JDialog { + + private static final long serialVersionUID = 1L; + + private ObjectListTable table; + private JPanel toolbar; + + public BomDialog(JFrame parent, List bom) { + super(parent, "Bill of Materials"); + setContentPane(createMainPanel()); + getTable().setData(bom); + pack(); + setLocationRelativeTo(parent); + } + + @Override + public void setVisible(boolean b) { + super.setVisible(b); + if (b) { + getTable().autoFit(Arrays.asList(3)); + } + } + + private JPanel createMainPanel() { + JPanel mainPanel = new JPanel(); + mainPanel.setLayout(new BorderLayout()); + mainPanel.add(getToolbar(), BorderLayout.NORTH); + mainPanel.add(new JScrollPane(getTable()), BorderLayout.CENTER); + return mainPanel; + } + + private ObjectListTable getTable() { + if (table == null) { + try { + table = new ObjectListTable(BomEntry.class, new String[] { "getName", + "getValue", "getQuantity", "getNotes/setNotes" }, null); + } catch (SecurityException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + } + return table; + } + + private JPanel getToolbar() { + if (toolbar == null) { + toolbar = new JPanel(); + toolbar.add(new JButton(new SaveToExcelAction())); + toolbar.add(new JButton(new SaveToCSVAction())); + toolbar.add(new JButton(new SaveToPNGAction())); + toolbar.add(new JButton(new SaveToHTMLAction())); + } + return toolbar; + } + + class SaveToExcelAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + public SaveToExcelAction() { + super(); + putValue(Action.NAME, "Save to Excel"); + putValue(Action.SMALL_ICON, IconLoader.Excel.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + File file = DialogFactory.getInstance().showSaveDialog( + FileFilterEnum.EXCEL.getFilter(), null, + FileFilterEnum.EXCEL.getExtensions()[0], null); + if (file != null) { + try { + TableExporter.getInstance().exportToExcel(getTable(), file); + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + } + } + + class SaveToCSVAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + public SaveToCSVAction() { + super(); + putValue(Action.NAME, "Save to CSV"); + putValue(Action.SMALL_ICON, IconLoader.CSV.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + File file = DialogFactory.getInstance().showSaveDialog(FileFilterEnum.CSV.getFilter(), + null, FileFilterEnum.CSV.getExtensions()[0], null); + if (file != null) { + try { + TableExporter.getInstance().exportToCSV(getTable(), file); + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + } + } + + class SaveToHTMLAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + public SaveToHTMLAction() { + super(); + putValue(Action.NAME, "Save to HTML"); + putValue(Action.SMALL_ICON, IconLoader.HTML.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + File file = DialogFactory.getInstance().showSaveDialog(FileFilterEnum.HTML.getFilter(), + null, FileFilterEnum.HTML.getExtensions()[0], null); + if (file != null) { + try { + TableExporter.getInstance().exportToHTML(getTable(), file); + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + } + } + + class SaveToPNGAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + public SaveToPNGAction() { + super(); + putValue(Action.NAME, "Save to PNG"); + putValue(Action.SMALL_ICON, IconLoader.Image.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + File file = DialogFactory.getInstance().showSaveDialog(FileFilterEnum.PNG.getFilter(), + null, FileFilterEnum.PNG.getExtensions()[0], null); + if (file != null) { + try { + TableExporter.getInstance().exportToPNG(getTable(), file); + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + } + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/file/FileFilterEnum.java b/diylc-swing/src/org/diylc/swing/plugins/file/FileFilterEnum.java new file mode 100644 index 00000000..508ad906 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/file/FileFilterEnum.java @@ -0,0 +1,50 @@ +package org.diylc.swing.plugins.file; + +import java.io.File; + +import javax.swing.filechooser.FileFilter; + +public enum FileFilterEnum { + + PNG("PNG Images (*.png)", "png"), PDF("PDF Files (*.pdf)", "pdf"), DIY( + "DIY Project Files (*.diy)", "diy"), EXCEL("Excel Workbooks (*.xls)", "xls"), CSV( + "Comma Separated Files (*.csv)", "csv"), HTML("HTML Files (*.html)", "html"), IMAGES( + "Image Files (*.png, *.jpg, *.gif)", "png", "jpg", "gif"); + + FileFilter filter; + String[] extensions; + + private FileFilterEnum(final String description, final String... extensions) { + this.extensions = extensions; + filter = new FileFilter() { + + @Override + public boolean accept(File f) { + if (f.isDirectory()) { + return true; + } + String fileExt = f.getName(); + fileExt = fileExt.substring(fileExt.lastIndexOf('.') + 1).toLowerCase(); + for (String ext : extensions) { + if (ext.equals(fileExt)) { + return true; + } + } + return false; + } + + @Override + public String getDescription() { + return description; + } + }; + } + + public FileFilter getFilter() { + return filter; + } + + public String[] getExtensions() { + return extensions; + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/file/FileMenuPlugin.java b/diylc-swing/src/org/diylc/swing/plugins/file/FileMenuPlugin.java new file mode 100644 index 00000000..aacd1d81 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/file/FileMenuPlugin.java @@ -0,0 +1,69 @@ +package org.diylc.swing.plugins.file; + +import java.util.EnumSet; + +import org.diylc.common.EventType; +import org.diylc.common.IPlugIn; +import org.diylc.common.IPlugInPort; +import org.diylc.images.IconLoader; +import org.diylc.swing.ActionFactory; +import org.diylc.swing.ISwingUI; + +/** + * Entry point class for File management utilities. + * + * @author Branislav Stojkovic + */ +public class FileMenuPlugin implements IPlugIn { + + private static final String FILE_TITLE = "File"; + private static final String TRACE_MASK_TITLE = "Trace Mask"; + + private ProjectDrawingProvider drawingProvider; + private TraceMaskDrawingProvider traceMaskDrawingProvider; + + private ISwingUI swingUI; + + public FileMenuPlugin(ISwingUI swingUI) { + super(); + this.swingUI = swingUI; + } + + @Override + public void connect(IPlugInPort plugInPort) { + this.drawingProvider = new ProjectDrawingProvider(plugInPort, false, true); + this.traceMaskDrawingProvider = new TraceMaskDrawingProvider(plugInPort); + + ActionFactory actionFactory = ActionFactory.getInstance(); + swingUI.injectMenuAction(actionFactory.createNewAction(plugInPort), FILE_TITLE); + swingUI.injectMenuAction(actionFactory.createOpenAction(plugInPort, swingUI), FILE_TITLE); + swingUI.injectMenuAction(actionFactory.createSaveAction(plugInPort, swingUI), FILE_TITLE); + swingUI.injectMenuAction(actionFactory.createSaveAsAction(plugInPort, swingUI), FILE_TITLE); + swingUI.injectMenuAction(null, FILE_TITLE); + swingUI.injectMenuAction(actionFactory.createExportPDFAction(drawingProvider, swingUI), + FILE_TITLE); + swingUI.injectMenuAction(actionFactory.createExportPNGAction(drawingProvider, swingUI), + FILE_TITLE); + swingUI.injectMenuAction(actionFactory.createPrintAction(drawingProvider), FILE_TITLE); + swingUI.injectSubmenu(TRACE_MASK_TITLE, IconLoader.TraceMask.getIcon(), FILE_TITLE); + swingUI.injectMenuAction(actionFactory.createExportPDFAction(traceMaskDrawingProvider, + swingUI), TRACE_MASK_TITLE); + swingUI.injectMenuAction(actionFactory.createExportPNGAction(traceMaskDrawingProvider, + swingUI), TRACE_MASK_TITLE); + swingUI.injectMenuAction(actionFactory.createPrintAction(traceMaskDrawingProvider), + TRACE_MASK_TITLE); + swingUI.injectMenuAction(actionFactory.createBomAction(plugInPort), FILE_TITLE); + swingUI.injectMenuAction(null, FILE_TITLE); + swingUI.injectMenuAction(actionFactory.createExitAction(plugInPort), FILE_TITLE); + } + + @Override + public EnumSet getSubscribedEventTypes() { + return null; + } + + @Override + public void processMessage(EventType eventType, Object... params) { + // Do nothing. + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/file/ProjectDrawingProvider.java b/diylc-swing/src/org/diylc/swing/plugins/file/ProjectDrawingProvider.java new file mode 100644 index 00000000..6b30cd42 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/file/ProjectDrawingProvider.java @@ -0,0 +1,54 @@ +package org.diylc.swing.plugins.file; + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.util.EnumSet; + +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.common.DrawOption; +import org.diylc.common.IPlugInPort; +import org.diylc.swingframework.IDrawingProvider; + +/** + * {@link IDrawingProvider} implementation that uses {@link IPlugInPort} to draw + * a project onto the canvas. + * + * @author Branislav Stojkovic + */ +public class ProjectDrawingProvider implements IDrawingProvider { + + private IPlugInPort plugInPort; + private boolean useZoom; + private boolean showGridWhenNeeded; + + public ProjectDrawingProvider(IPlugInPort plugInPort, boolean useZoom, + boolean showGridWhenNeeded) { + super(); + this.plugInPort = plugInPort; + this.useZoom = useZoom; + this.showGridWhenNeeded = showGridWhenNeeded; + } + + @Override + public void draw(Graphics g) { + EnumSet drawOptions = EnumSet.of(DrawOption.ANTIALIASING); + if (useZoom) { + drawOptions.add(DrawOption.ZOOM); + } + if (showGridWhenNeeded + && ConfigurationManager.getInstance().readBoolean(IPlugInPort.EXPORT_GRID_KEY, + false)) { + drawOptions.add(DrawOption.GRID); + } + if (ConfigurationManager.getInstance().readBoolean(IPlugInPort.OUTLINE_KEY, false)) { + drawOptions.add(DrawOption.OUTLINE_MODE); + } + plugInPort.draw((Graphics2D) g, drawOptions, null); + } + + @Override + public Dimension getSize() { + return plugInPort.getCanvasDimensions(useZoom); + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/file/ProjectPreview.java b/diylc-swing/src/org/diylc/swing/plugins/file/ProjectPreview.java new file mode 100644 index 00000000..c97d5c7c --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/file/ProjectPreview.java @@ -0,0 +1,168 @@ +package org.diylc.swing.plugins.file; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.FileInputStream; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + +import javax.swing.JComponent; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import org.diylc.common.DrawOption; +import org.diylc.common.IPlugInPort; +import org.diylc.common.PropertyWrapper; +import org.diylc.core.IView; +import org.diylc.core.Project; +import org.diylc.presenter.Presenter; +import org.diylc.swingframework.IFileChooserAccessory; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.xml.DomDriver; + +/** + * {@link JComponent} that shows preview of the selected project in + * {@link JFileChooser}. It's hooked onto {@link JFileChooser} as + * {@link PropertyChangeListener} and refreshes when file is selected. + * + * @author Branislav Stojkovic + */ +public class ProjectPreview extends JPanel implements PropertyChangeListener, IFileChooserAccessory { + + private static final long serialVersionUID = 1L; + + private IPlugInPort presenter; + private XStream xStream; + private Project emptyProject; + private RenderComponent renderComponent; + private JLabel nameLabel; + + public ProjectPreview() { + super(); + + setPreferredSize(new Dimension(140, 128)); + presenter = new Presenter(new IView() { + + @Override + public int showConfirmDialog(String message, String title, int optionType, + int messageType) { + return 0; + } + + @Override + public void showMessage(String message, String title, int messageType) { + } + + @Override + public File promptFileSave() { + return null; + } + + @Override + public boolean editProperties(List properties, Set defaultedProperties) { + return false; + } + }); + xStream = new XStream(new DomDriver()); + + emptyProject = new Project(); + emptyProject.setTitle(""); + + renderComponent = new RenderComponent(); + nameLabel = new JLabel(); + + // setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + add(renderComponent); + add(nameLabel); + } + + // PropertyChangeListener + + @Override + public void propertyChange(PropertyChangeEvent evt) { + boolean update = false; + String prop = evt.getPropertyName(); + + Project selectedProject = emptyProject; + if (JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals(prop)) { + update = true; + } else if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(prop)) { + File selectedFile = (File) evt.getNewValue(); + try { + FileInputStream in = new FileInputStream(selectedFile); + selectedProject = (Project) xStream.fromXML(in); + in.close(); + } catch (Exception e) { + } + update = true; + } + + nameLabel.setText(selectedProject.getTitle()); + presenter.loadProject(selectedProject, true); + + if (update) { + if (renderComponent.isShowing()) { + renderComponent.repaint(); + } + } + } + + class RenderComponent extends JComponent { + + private static final long serialVersionUID = 1L; + + public RenderComponent() { + setPreferredSize(new Dimension(128, 96)); + // setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 4)); + } + + @Override + public void paint(Graphics g) { + super.paint(g); + + Graphics2D g2d = (Graphics2D) g; + Dimension d = presenter.getCanvasDimensions(false); + // System.out.println(d); + Rectangle rect = getBounds(); + // System.out.println(rect); + + double projectRatio = d.getWidth() / d.getHeight(); + double actualRatio = rect.getWidth() / rect.getHeight(); + double zoomRatio; + if (projectRatio > actualRatio) { + zoomRatio = rect.getWidth() / d.getWidth(); + } else { + zoomRatio = rect.getHeight() / d.getHeight(); + } + // d.setSize(d.getWidth() * zoomRatio, d.getHeight() * zoomRatio); + // int x = (int) (rect.getWidth() - d.getWidth() * zoomRatio) / 2; + // int y = (int) (rect.getHeight() - d.getHeight() * zoomRatio) / 2; + + // System.out.println(x + "," + y); + + // g2d.translate(x, y); + g2d.scale(zoomRatio, zoomRatio); + presenter.draw(g2d, EnumSet.noneOf(DrawOption.class), null); + + g2d.setColor(Color.black); + g2d.drawRect(0, 0, d.width - (int) (1 / zoomRatio), d.height - (int) (1 / zoomRatio)); + } + } + + // IFileChooserAccessory + + @Override + public void install(JFileChooser fileChooser) { + fileChooser.setAccessory(this); + fileChooser.addPropertyChangeListener(this); + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/file/TraceMaskDrawingProvider.java b/diylc-swing/src/org/diylc/swing/plugins/file/TraceMaskDrawingProvider.java new file mode 100644 index 00000000..ebc737d0 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/file/TraceMaskDrawingProvider.java @@ -0,0 +1,42 @@ +package org.diylc.swing.plugins.file; + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.util.EnumSet; + +import org.diylc.common.DrawOption; +import org.diylc.common.IComponentFiler; +import org.diylc.common.IPlugInPort; +import org.diylc.core.IDIYComponent; +import org.diylc.presenter.ComponentZOrderFiler; +import org.diylc.swingframework.IDrawingProvider; + +/** + * {@link IDrawingProvider} implementation that uses {@link IPlugInPort} to draw + * a project onto the canvas. + * + * @author Branislav Stojkovic + */ +public class TraceMaskDrawingProvider implements IDrawingProvider { + + private IPlugInPort plugInPort; + private IComponentFiler filter; + + public TraceMaskDrawingProvider(IPlugInPort plugInPort) { + super(); + this.plugInPort = plugInPort; + this.filter = new ComponentZOrderFiler(IDIYComponent.TRACE); + } + + @Override + public void draw(Graphics g) { + plugInPort.draw((Graphics2D) g, EnumSet.of(DrawOption.ANTIALIASING), + this.filter); + } + + @Override + public Dimension getSize() { + return plugInPort.getCanvasDimensions(false); + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/help/HelpMenuPlugin.java b/diylc-swing/src/org/diylc/swing/plugins/help/HelpMenuPlugin.java new file mode 100644 index 00000000..3f203299 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/help/HelpMenuPlugin.java @@ -0,0 +1,118 @@ +package org.diylc.swing.plugins.help; + +import java.awt.event.ActionEvent; +import java.util.EnumSet; + +import javax.swing.AbstractAction; +import javax.swing.Icon; + +import org.apache.log4j.Logger; +import org.diylc.appframework.miscutils.Utils; +import org.diylc.common.EventType; +import org.diylc.common.IPlugIn; +import org.diylc.common.IPlugInPort; +import org.diylc.images.IconLoader; +import org.diylc.swing.ISwingUI; +import org.diylc.swing.gui.DialogFactory; +import org.diylc.swingframework.AboutDialog; +import org.diylc.swingframework.LinkLabel; + +/** + * Entry point class for help-related utilities. + * + * @author Branislav Stojkovic + */ +public class HelpMenuPlugin implements IPlugIn { + + private static final String HELP_TITLE = "Help"; + + public static String MANUAL_URL = "http://code.google.com/p/diy-layout-creator/wiki/Manual"; + public static String FAQ_URL = "http://code.google.com/p/diy-layout-creator/wiki/FAQ"; + public static String COMPONENT_URL = "http://code.google.com/p/diy-layout-creator/wiki/ComponentAPI"; + public static String PLUGIN_URL = "http://code.google.com/p/diy-layout-creator/wiki/PluginAPI"; + public static String BUG_URL = "http://code.google.com/p/diy-layout-creator/issues/entry"; + public static String DONATE_URL = "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=25161"; + + private IPlugInPort plugInPort; + private AboutDialog aboutDialog; + + public HelpMenuPlugin(ISwingUI swingUI) { + swingUI.injectMenuAction(new NavigateURLAction("User Manual", IconLoader.Manual.getIcon(), + MANUAL_URL), HELP_TITLE); + swingUI.injectMenuAction(new NavigateURLAction("FAQ", IconLoader.Faq.getIcon(), FAQ_URL), + HELP_TITLE); + swingUI.injectMenuAction(new NavigateURLAction("Component API", IconLoader.Component + .getIcon(), COMPONENT_URL), HELP_TITLE); + swingUI.injectMenuAction(new NavigateURLAction("Plugin API", IconLoader.Plugin.getIcon(), + PLUGIN_URL), HELP_TITLE); + swingUI.injectMenuAction(new NavigateURLAction("Submit a Bug", IconLoader.Bug.getIcon(), + BUG_URL), HELP_TITLE); + swingUI.injectMenuAction(null, HELP_TITLE); + swingUI.injectMenuAction(new NavigateURLAction("Donate", IconLoader.Donate.getIcon(), + DONATE_URL), HELP_TITLE); + swingUI.injectMenuAction(new AboutAction(), HELP_TITLE); + } + + @Override + public void connect(IPlugInPort plugInPort) { + this.plugInPort = plugInPort; + } + + @Override + public EnumSet getSubscribedEventTypes() { + return null; + } + + @Override + public void processMessage(EventType eventType, Object... params) { + } + + private AboutDialog getAboutDialog() { + if (aboutDialog == null) { + aboutDialog = DialogFactory.getInstance().createAboutDialog("DIY Layout Creator", + IconLoader.IconLarge.getIcon(), + plugInPort.getCurrentVersionNumber().toString(), "Branislav Stojkovic", + "diylc.org", "bancika@gmail.com", ""); + } + return aboutDialog; + } + + class AboutAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + public AboutAction() { + super(); + putValue(AbstractAction.NAME, "About"); + putValue(AbstractAction.SMALL_ICON, IconLoader.About.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + getAboutDialog().setVisible(true); + } + } + + class NavigateURLAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private String url; + + public NavigateURLAction(String name, Icon icon, String url) { + super(); + this.url = url; + putValue(AbstractAction.NAME, name); + putValue(AbstractAction.SMALL_ICON, icon); + } + + @Override + public void actionPerformed(ActionEvent e) { + try { + Utils.openURL(url); + } catch (Exception e1) { + Logger.getLogger(LinkLabel.class).error("Could not launch default browser", e1); + } + } + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/layers/LayersMenuPlugin.java b/diylc-swing/src/org/diylc/swing/plugins/layers/LayersMenuPlugin.java new file mode 100644 index 00000000..bf9b314a --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/layers/LayersMenuPlugin.java @@ -0,0 +1,89 @@ +package org.diylc.swing.plugins.layers; + +import java.awt.event.ActionEvent; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.swing.AbstractAction; +import javax.swing.Action; + +import org.diylc.common.EventType; +import org.diylc.common.IPlugIn; +import org.diylc.common.IPlugInPort; +import org.diylc.core.IDIYComponent; +import org.diylc.core.IView; +import org.diylc.swing.ISwingUI; + +public class LayersMenuPlugin implements IPlugIn { + + private static final String LOCK_LAYERS_TITLE = "Lock Layers"; + + private IPlugInPort plugInPort; + private Map lockActionMap; + + public LayersMenuPlugin(ISwingUI swingUI) { + lockActionMap = new HashMap(); + for (Layer layer : Layer.values()) { + final int zOrder = layer.getZOrder(); + AbstractAction action = new AbstractAction(layer.getTitle()) { + + private static final long serialVersionUID = 1L; + + @Override + public void actionPerformed(ActionEvent e) { + LayersMenuPlugin.this.plugInPort.setLayerLocked(zOrder, + (Boolean) getValue(Action.SELECTED_KEY)); + } + }; + action.putValue(IView.CHECK_BOX_MENU_ITEM, true); + lockActionMap.put(layer, action); + swingUI.injectMenuAction(action, LOCK_LAYERS_TITLE); + } + } + + @Override + public void connect(IPlugInPort plugInPort) { + this.plugInPort = plugInPort; + } + + @Override + public EnumSet getSubscribedEventTypes() { + return EnumSet.of(EventType.LAYER_STATE_CHANGED); + } + + @SuppressWarnings("unchecked") + @Override + public void processMessage(EventType eventType, Object... params) { + if (eventType == EventType.LAYER_STATE_CHANGED) { + Set lockedLayers = (Set) params[0]; + for (Layer layer : Layer.values()) { + lockActionMap.get(layer).putValue(Action.SELECTED_KEY, + lockedLayers.contains(layer.getZOrder())); + } + } + } + + static enum Layer { + CHASSIS("Chassis", IDIYComponent.CHASSIS), BOARD("Board", IDIYComponent.BOARD), TRACE( + "Trace", IDIYComponent.TRACE), COMPONENT("Component", IDIYComponent.COMPONENT), TEXT( + "Text", IDIYComponent.TEXT); + + String title; + int zOrder; + + private Layer(String title, int order) { + this.title = title; + zOrder = order; + } + + public String getTitle() { + return title; + } + + public int getZOrder() { + return zOrder; + } + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/online/OnlineManager.java b/diylc-swing/src/org/diylc/swing/plugins/online/OnlineManager.java new file mode 100644 index 00000000..c40512b2 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/online/OnlineManager.java @@ -0,0 +1,154 @@ +package org.diylc.swing.plugins.online; + +import java.awt.event.ActionEvent; +import java.util.EnumSet; + +import javax.swing.AbstractAction; +import javax.swing.SwingWorker; + +import org.diylc.common.EventType; +import org.diylc.common.IPlugIn; +import org.diylc.common.IPlugInPort; +import org.diylc.images.IconLoader; +import org.diylc.swing.gui.DialogFactory; +import org.diylc.swing.plugins.online.presenter.LibraryPresenter; +import org.diylc.swing.plugins.online.view.LoginDialog; +import org.diylc.swing.plugins.online.view.NewUserDialog; +import org.diylc.swing.plugins.online.view.UploadDialog; +import org.diylc.swingframework.ProgressDialog; + +public class OnlineManager implements IPlugIn { + + private static final String ONLINE_TITLE = "Online"; + + private IPlugInPort plugInPort; + private LibraryPresenter libraryPresenter; + + @Override + public void connect(IPlugInPort plugInPort) { + this.plugInPort = plugInPort; + this.libraryPresenter = new LibraryPresenter(); + + initialize(); + +// plugInPort.injectMenuAction(new LibraryAction(), ONLINE_TITLE); +// plugInPort.injectMenuAction(null, ONLINE_TITLE); +// plugInPort.injectMenuAction(new LoginAction(), ONLINE_TITLE); +// plugInPort.injectMenuAction(new CreateAccountAction(), ONLINE_TITLE); +// plugInPort.injectMenuAction(null, ONLINE_TITLE); +// plugInPort.injectMenuAction(new UploadAction(), ONLINE_TITLE); +// plugInPort.injectMenuAction(new ManageProjectsAction(), ONLINE_TITLE); + } + + private void initialize() { + SwingWorker worker = new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + libraryPresenter.connectDb(); + return null; + } + + @Override + protected void done() { + if (libraryPresenter.isLoggedIn()) { + + } + } + }; + worker.execute(); + } + + @Override + public EnumSet getSubscribedEventTypes() { + return null; + } + + @Override + public void processMessage(EventType eventType, Object... params) { + } + + class LibraryAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + public LibraryAction() { + super(); + putValue(AbstractAction.NAME, "Browse Library"); + putValue(AbstractAction.SMALL_ICON, IconLoader.Chest.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + } + } + + class LoginAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + public LoginAction() { + super(); + putValue(AbstractAction.NAME, "Log in"); + putValue(AbstractAction.SMALL_ICON, IconLoader.IdCard.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + LoginDialog dialog = DialogFactory.getInstance().createLoginDialog(); + dialog.setVisible(true); + } + } + + class CreateAccountAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + public CreateAccountAction() { + super(); + putValue(AbstractAction.NAME, "Create New Account"); + putValue(AbstractAction.SMALL_ICON, IconLoader.IdCardAdd.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + NewUserDialog dialog = DialogFactory.getInstance().createNewUserDialog(); + dialog.setVisible(true); + } + } + + class UploadAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + public UploadAction() { + super(); + putValue(AbstractAction.NAME, "Upload Project"); + putValue(AbstractAction.SMALL_ICON, IconLoader.Upload.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + UploadDialog dialog = DialogFactory.getInstance().createUploadDialog(); + dialog.setVisible(true); + } + } + + class ManageProjectsAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + public ManageProjectsAction() { + super(); + putValue(AbstractAction.NAME, "Manage Projects"); + putValue(AbstractAction.SMALL_ICON, IconLoader.Wrench.getIcon()); + } + + @Override + public void actionPerformed(ActionEvent e) { + ProgressDialog dialog = DialogFactory.getInstance().createProgressDialog("Test", + new String[] {}, "Some text", false); + dialog.setVisible(true); + } + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/online/Test.java b/diylc-swing/src/org/diylc/swing/plugins/online/Test.java new file mode 100644 index 00000000..aee1e52b --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/online/Test.java @@ -0,0 +1,28 @@ +package org.diylc.swing.plugins.online; + +import org.apache.log4j.BasicConfigurator; +import org.diylc.swing.plugins.online.presenter.LibraryPresenter; + + +public class Test { + + /** + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + BasicConfigurator.configure(); + LibraryPresenter pres = new LibraryPresenter(); + // pres.createUser("bancika", "pwd", "bancika@gmail.com"); + System.out.println(pres.fetchCategories()); + pres.login("bancika", "pwd"); + int id = pres.fetchMyProjectRows().get(0).getId(); + // InputStream stream = pres.downloadProjectContent(id); + // byte[] buf = new byte[100]; + // int len = stream.read(buf); + System.out.println(pres.downloadProjectContent(id)); + // System.out.println(pres.hashPassword("bancikabancikabancikabancikabancika")); + pres.dispose(); + } + +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/online/model/ProjectEntity.java b/diylc-swing/src/org/diylc/swing/plugins/online/model/ProjectEntity.java new file mode 100644 index 00000000..228307fa --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/online/model/ProjectEntity.java @@ -0,0 +1,136 @@ +package org.diylc.swing.plugins.online.model; + +import java.awt.event.ActionEvent; +import java.io.Serializable; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JOptionPane; + +public class ProjectEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + private int id; + private String name; + private String description; + private String owner; + private String category; + + public ProjectEntity() { + super(); + } + + public ProjectEntity(int id, String name, String description, String owner, String category) { + super(); + this.id = id; + this.name = name; + this.description = description; + this.owner = owner; + this.category = category; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public Action getDownload() { + + Action a = new AbstractAction() { + + @Override + public void actionPerformed(ActionEvent e) { + JOptionPane.showMessageDialog(null, name); + } + }; + a.putValue(AbstractAction.NAME, "Download"); + return a; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((category == null) ? 0 : category.hashCode()); + result = prime * result + ((description == null) ? 0 : description.hashCode()); + result = prime * result + id; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((owner == null) ? 0 : owner.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ProjectEntity other = (ProjectEntity) obj; + if (category == null) { + if (other.category != null) + return false; + } else if (!category.equals(other.category)) + return false; + if (description == null) { + if (other.description != null) + return false; + } else if (!description.equals(other.description)) + return false; + if (id != other.id) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (owner == null) { + if (other.owner != null) + return false; + } else if (!owner.equals(other.owner)) + return false; + return true; + } + + @Override + public String toString() { + return name; + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/online/presenter/AlreadyExistsException.java b/diylc-swing/src/org/diylc/swing/plugins/online/presenter/AlreadyExistsException.java new file mode 100644 index 00000000..412fabea --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/online/presenter/AlreadyExistsException.java @@ -0,0 +1,7 @@ +package org.diylc.swing.plugins.online.presenter; + +public class AlreadyExistsException extends Exception { + + private static final long serialVersionUID = 1L; + +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/online/presenter/LibraryPresenter.java b/diylc-swing/src/org/diylc/swing/plugins/online/presenter/LibraryPresenter.java new file mode 100644 index 00000000..e6acd8a4 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/online/presenter/LibraryPresenter.java @@ -0,0 +1,177 @@ +package org.diylc.swing.plugins.online.presenter; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.diylc.swing.plugins.online.model.ProjectEntity; + + +public class LibraryPresenter { + + private final static Logger LOG = Logger.getLogger(LibraryPresenter.class); + + private static final String DB_HOST = "diy-fever.com"; + private static final String DB_PORT = "3306"; + private static final String DB_USER = "diylc-app"; + private static final String DB_PASS = "zuf7RuS8"; + + private static final String CATEGORY_SQL = "SELECT * FROM diylc.category WHERE 1=1"; + private static final String USER_SQL = "SELECT * FROM diylc.user WHERE name = \"%s\""; + private static final String CREATE_USER_SQL = "INSERT INTO diylc.user (name, password, email) VALUES (\"%s\", \"%s\", \"%s\")"; + private static final String MY_PROJECTS_SQL = "SELECT project_id, name, category_id, description FROM diylc.project WHERE owner_user_id = %s"; + private static final String PROJECT_SQL = "SELECT content FROM diylc.project WHERE project_id = %s"; + private static final String UPLOAD_PROJECT_SQL = "INSERT INTO diylc.project (name, description, content, category_id, owner_user_id) VALUES (\"%s\", \"%s\", \"%s\", %s, %s)"; + private static final String UPDATE_PROJECT_SQL = "UPDATE diylc.project SET name = \"%s\", description = \"%s\", content = \"%s\", category_id = %s WHERE project_id = %s"; + + private MySqlDBManager dbManager; + private MessageDigest messageDigest; + private Integer currentUserId; + + public LibraryPresenter() { + dbManager = new MySqlDBManager(DB_HOST, DB_PORT, DB_USER, DB_PASS); + try { + messageDigest = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + LOG.error("Could not initialize MD5, algorithm not found."); + } + } + + public boolean connectDb() { + try { + dbManager.connectDB(); + return true; + } catch (Exception e) { + LOG.error("Could not connect to the database: " + e.getMessage()); + return false; + } + } + + public void createUser(String userName, String password, String email) throws SQLException, + NotConnectedException, AlreadyExistsException { + LOG.info("Creating user: " + userName); + if (dbManager.isConnected()) { + ResultSet resultSet = dbManager.getResultSet(String.format(USER_SQL, userName)); + if (resultSet.next()) { + throw new AlreadyExistsException(); + } + dbManager.updateDB(String.format(CREATE_USER_SQL, userName, hashPassword(password), + email)); + resultSet = dbManager.getResultSet(String.format(USER_SQL, userName)); + if (resultSet.next()) { + LOG.info("Logged in as \"" + userName + "\""); + currentUserId = resultSet.getInt("user_id"); + } + } else { + LOG.error("Not connected"); + throw new NotConnectedException(); + } + } + + public boolean login(String userName, String password) throws SQLException, + NotConnectedException { + LOG.info("Logging in as: " + userName); + if (dbManager.isConnected()) { + ResultSet resultSet = dbManager.getResultSet(String.format(USER_SQL, userName)); + if (resultSet.next()) { + String dbPassword = resultSet.getString("password"); + String hashPassword = hashPassword(password); + if (dbPassword.equals(hashPassword)) { + LOG.info("Logged in as \"" + userName + "\""); + currentUserId = resultSet.getInt("user_id"); + } else { + LOG.info("User name and password do not match."); + } + } + return false; + } else { + LOG.error("Not connected"); + throw new NotConnectedException(); + } + } + + public Map fetchCategories() throws SQLException, NotConnectedException { + LOG.info("Fetching categories"); + if (dbManager.isConnected()) { + Map categories = new HashMap(); + ResultSet resultSet = dbManager.getResultSet(CATEGORY_SQL); + while (resultSet.next()) { + categories.put(resultSet.getInt("category_id"), resultSet.getString("name")); + } + return categories; + } else { + LOG.error("Not connected"); + throw new NotConnectedException(); + } + } + + public List fetchMyProjectRows() throws NotLoggedInException, + NotConnectedException, SQLException { + if (dbManager.isConnected()) { + if (isLoggedIn()) { + Map categories = fetchCategories(); + List projects = new ArrayList(); + ResultSet resultSet = dbManager.getResultSet(String.format(MY_PROJECTS_SQL, + currentUserId)); + while (resultSet.next()) { + projects.add(new ProjectEntity(resultSet.getInt("project_id"), resultSet + .getString("name"), resultSet.getString("description"), "", categories + .get(resultSet.getInt("category_id")))); + } + return projects; + } else { + LOG.error("Not logged in"); + throw new NotLoggedInException(); + } + } else { + LOG.error("Not connected"); + throw new NotConnectedException(); + } + } + + public String downloadProjectContent(int projectId) throws NotConnectedException, + NotExistsException, SQLException { + if (dbManager.isConnected()) { + ResultSet resultSet = dbManager.getResultSet(String.format(PROJECT_SQL, projectId)); + if (resultSet.next()) { + return resultSet.getString("content"); + } + throw new NotExistsException("Project with id = " + projectId + " does not exist."); + } else { + LOG.error("Not connected"); + throw new NotConnectedException(); + } + } + + public List fetchProjectRows(String searchCriteria) { + return null; + } + + public boolean isLoggedIn() { + return currentUserId != null; + } + + public String hashPassword(String password) { + messageDigest.reset(); + byte[] bytes = messageDigest.digest(password.getBytes()); + String md5 = ""; + for (byte b : bytes) { + String str = Integer.toHexString(b); + if (str.length() == 1) { + str = "0" + str; + } + md5 += str.substring(str.length() - 2); + } + return md5; + } + + public void dispose() { + dbManager.closeConnection(); + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/online/presenter/MySqlDBManager.java b/diylc-swing/src/org/diylc/swing/plugins/online/presenter/MySqlDBManager.java new file mode 100644 index 00000000..186ba407 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/online/presenter/MySqlDBManager.java @@ -0,0 +1,86 @@ +package org.diylc.swing.plugins.online.presenter; + +import java.sql.Connection; +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import org.apache.log4j.Logger; + +public class MySqlDBManager { + + private final static Logger LOG = Logger.getLogger(MySqlDBManager.class); + + protected Connection connection; + protected Statement statement; + protected ResultSet resultSet; + protected String url; + protected String user; + protected String pass; + protected boolean connected; + + public MySqlDBManager(String url, String user, String pass) { + this.url = url; + this.user = user; + this.pass = pass; + this.connected = false; + } + + public MySqlDBManager(String host, String port, String userName, String password) { + this(String.format("jdbc:mysql://%s%s", host, port.trim().equals("") ? "" : (":" + port)), + userName, password); + } + + public void connectDB() throws Exception { + if (!connected) { + Driver driver = (Driver) Class.forName("com.mysql.jdbc.Driver").newInstance(); + DriverManager.registerDriver(driver); + String finalUrl = String.format("%s?user=%s&password=%s", url, user, pass); + LOG.info("Trying to connect to: " + url); + connection = DriverManager.getConnection(finalUrl); + statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_READ_ONLY); + connected = true; + } + } + + public boolean isConnected() { + return connected; + } + + public void closeConnection() { + LOG.info("Closing connection."); + try { + if (resultSet != null) { + resultSet.close(); + } + if (statement != null) { + statement.close(); + } + if (connection != null) { + connection.close(); + } + connected = false; + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public ResultSet getResultSet(String query) throws SQLException { + LOG.info("Executing query: " + query); + resultSet = statement.executeQuery(query); + return resultSet; + } + + public Connection getConnection() { + return connection; + } + + public int updateDB(String query) throws SQLException { + LOG.info("Executing query: " + query); + statement.execute(query); + return statement.getUpdateCount(); + } +} \ No newline at end of file diff --git a/diylc-swing/src/org/diylc/swing/plugins/online/presenter/NotConnectedException.java b/diylc-swing/src/org/diylc/swing/plugins/online/presenter/NotConnectedException.java new file mode 100644 index 00000000..4752625e --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/online/presenter/NotConnectedException.java @@ -0,0 +1,7 @@ +package org.diylc.swing.plugins.online.presenter; + +public class NotConnectedException extends Exception { + + private static final long serialVersionUID = 1L; + +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/online/presenter/NotExistsException.java b/diylc-swing/src/org/diylc/swing/plugins/online/presenter/NotExistsException.java new file mode 100644 index 00000000..169dcc37 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/online/presenter/NotExistsException.java @@ -0,0 +1,10 @@ +package org.diylc.swing.plugins.online.presenter; + +public class NotExistsException extends Exception { + + private static final long serialVersionUID = 1L; + + public NotExistsException(String message) { + super(message); + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/online/presenter/NotLoggedInException.java b/diylc-swing/src/org/diylc/swing/plugins/online/presenter/NotLoggedInException.java new file mode 100644 index 00000000..aba9b870 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/online/presenter/NotLoggedInException.java @@ -0,0 +1,7 @@ +package org.diylc.swing.plugins.online.presenter; + +public class NotLoggedInException extends Exception { + + private static final long serialVersionUID = 1L; + +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/online/view/LibraryFrame.java b/diylc-swing/src/org/diylc/swing/plugins/online/view/LibraryFrame.java new file mode 100644 index 00000000..89f2b839 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/online/view/LibraryFrame.java @@ -0,0 +1,12 @@ +package org.diylc.swing.plugins.online.view; + +import javax.swing.JFrame; + +public class LibraryFrame extends JFrame { + + private static final long serialVersionUID = 1L; + + public LibraryFrame() { + super("Online Library"); + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/online/view/LoginDialog.java b/diylc-swing/src/org/diylc/swing/plugins/online/view/LoginDialog.java new file mode 100644 index 00000000..820bb0e9 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/online/view/LoginDialog.java @@ -0,0 +1,135 @@ +package org.diylc.swing.plugins.online.view; + +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JPasswordField; +import javax.swing.JTextField; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +import org.diylc.swingframework.ButtonDialog; + +public class LoginDialog extends ButtonDialog { + + private static final long serialVersionUID = 1L; + + private JPanel mainPanel; + + private JTextField userNameField; + private JPasswordField passwordField; + + private String userName; + private String password; + + public LoginDialog(JFrame owner) { + super(owner, "Login", new String[] { OK, CANCEL }); + setMinimumSize(new Dimension(240, 32)); + layoutGui(); + refreshState(); + } + + public String getUserName() { + return userName; + } + + public String getPassword() { + return password; + } + + @Override + protected JComponent getMainComponent() { + if (mainPanel == null) { + mainPanel = new JPanel(new GridBagLayout()); + mainPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.anchor = GridBagConstraints.LINE_START; + gbc.fill = GridBagConstraints.NONE; + gbc.insets = new Insets(2, 2, 2, 2); + + gbc.gridx = 0; + + gbc.gridy = 0; + mainPanel.add(new JLabel("User Name:"), gbc); + + gbc.gridy = 1; + mainPanel.add(new JLabel("Password:"), gbc); + + gbc.gridx = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.weightx = 1; + + gbc.gridy = 0; + mainPanel.add(getUserNameField(), gbc); + + gbc.gridy = 1; + mainPanel.add(getPasswordField(), gbc); + } + return mainPanel; + } + + private void refreshState() { + this.userName = getUserNameField().getText(); + this.password = new String(getPasswordField().getPassword()); + + JButton okButton = getButton(OK); + okButton.setEnabled((this.userName.length() > 0) && (this.password.length() > 0)); + } + + private JTextField getUserNameField() { + if (userNameField == null) { + userNameField = new JTextField(); + userNameField.getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent e) { + refreshState(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + refreshState(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + refreshState(); + } + }); + } + return userNameField; + } + + private JPasswordField getPasswordField() { + if (passwordField == null) { + passwordField = new JPasswordField(); + passwordField.getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent e) { + refreshState(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + refreshState(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + refreshState(); + } + }); + } + return passwordField; + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/online/view/NewUserDialog.java b/diylc-swing/src/org/diylc/swing/plugins/online/view/NewUserDialog.java new file mode 100644 index 00000000..752b6c70 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/online/view/NewUserDialog.java @@ -0,0 +1,210 @@ +package org.diylc.swing.plugins.online.view; + +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JPasswordField; +import javax.swing.JTextField; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +import org.diylc.swingframework.ButtonDialog; + +public class NewUserDialog extends ButtonDialog { + + private static final long serialVersionUID = 1L; + + private JPanel mainPanel; + + private JTextField userNameField; + private JPasswordField passwordField; + private JPasswordField confirmPasswordField; + private JTextField emailField; + + private String userName; + private String password; + private String email; + + public NewUserDialog(JFrame owner) { + super(owner, "New Account", new String[] { OK, CANCEL }); + setMinimumSize(new Dimension(240, 32)); + layoutGui(); + refreshState(); + userNameField.setText(System.getProperty("user.name")); + } + + public String getUserName() { + return userName; + } + + public String getPassword() { + return password; + } + + public String getEmail() { + return email; + } + + @Override + protected JComponent getMainComponent() { + if (mainPanel == null) { + mainPanel = new JPanel(new GridBagLayout()); + mainPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.anchor = GridBagConstraints.LINE_START; + gbc.fill = GridBagConstraints.NONE; + gbc.insets = new Insets(2, 2, 2, 2); + + gbc.gridx = 0; + + gbc.gridy = 0; + mainPanel.add(new JLabel("User Name:"), gbc); + + gbc.gridy = 1; + mainPanel.add(new JLabel("Password:"), gbc); + + gbc.gridy = 2; + mainPanel.add(new JLabel("Confirm Password:"), gbc); + + gbc.gridy = 3; + mainPanel.add(new JLabel("eMail:"), gbc); + + gbc.gridx = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.weightx = 1; + + gbc.gridy = 0; + mainPanel.add(getUserNameField(), gbc); + + gbc.gridy = 1; + mainPanel.add(getPasswordField(), gbc); + + gbc.gridy = 2; + mainPanel.add(getConfirmPasswordField(), gbc); + + gbc.gridy = 3; + mainPanel.add(getEmailField(), gbc); + } + return mainPanel; + } + + private void refreshState() { + this.userName = getUserNameField().getText(); + String password = new String(getPasswordField().getPassword()); + String confirmPassword = new String(getConfirmPasswordField().getPassword()); + if (password.equals(confirmPassword)) { + this.password = password; + } else { + this.password = null; + } + this.email = getEmailField().getText(); + JButton okButton = getButton(OK); + okButton.setEnabled((this.userName.length() > 0) && (this.password != null) + && (this.password.length() > 0)); + } + + private JTextField getUserNameField() { + if (userNameField == null) { + userNameField = new JTextField(); + userNameField.getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent e) { + refreshState(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + refreshState(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + refreshState(); + } + }); + } + return userNameField; + } + + private JPasswordField getPasswordField() { + if (passwordField == null) { + passwordField = new JPasswordField(); + passwordField.getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent e) { + refreshState(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + refreshState(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + refreshState(); + } + }); + } + return passwordField; + } + + private JPasswordField getConfirmPasswordField() { + if (confirmPasswordField == null) { + confirmPasswordField = new JPasswordField(); + confirmPasswordField.getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent e) { + refreshState(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + refreshState(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + refreshState(); + } + }); + } + return confirmPasswordField; + } + + private JTextField getEmailField() { + if (emailField == null) { + emailField = new JTextField(); + emailField.getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent e) { + refreshState(); + } + + @Override + public void insertUpdate(DocumentEvent e) { + refreshState(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + refreshState(); + } + }); + } + return emailField; + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/online/view/UploadDialog.java b/diylc-swing/src/org/diylc/swing/plugins/online/view/UploadDialog.java new file mode 100644 index 00000000..15624506 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/online/view/UploadDialog.java @@ -0,0 +1,105 @@ +package org.diylc.swing.plugins.online.view; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; + +import javax.swing.BorderFactory; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.UIManager; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.diylc.swingframework.ButtonDialog; + +public class UploadDialog extends ButtonDialog { + + private static final long serialVersionUID = 1L; + + private static final String BULLET = "   • "; + private static final String TERMS_HTML = "Terms of Service

" + + BULLET + + "Online Library is provided free of charge for DIY Layout Creator users.
" + + BULLET + + "Only finished and verified projects may be uploaded to the library. Online Library is not a repository for unfinished projects and temprary work.
" + + BULLET + + "Projects uploaded to the library may be reviewed, modified or deleted by the administrator without notice.
" + + BULLET + + "Once uploaded, project becomes avaialble to all other users. Anyone may use the project, modify it and upload modified version. When modifying an existing projects credit for the original author must be left.
" + + BULLET + + "You can not use Online Library to advertise products or services.
" + + BULLET + + "Users that do not follow these terms may be banned from the server, with or without notice.
" + + BULLET + "Administrator is not responsible for library contents.
" + ""; + + private JPanel mainPanel; + private JLabel termsLabel; + private JCheckBox agreeBox; + + public UploadDialog(JFrame owner) { + super(owner, "Upload", new String[] { OK, CANCEL }); + layoutGui(); + refreshState(); + } + + @Override + protected JComponent getMainComponent() { + if (mainPanel == null) { + mainPanel = new JPanel(new GridBagLayout()); + mainPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.anchor = GridBagConstraints.LINE_START; + gbc.fill = GridBagConstraints.BOTH; + gbc.weightx = 1; + gbc.weighty = 1; + gbc.insets = new Insets(2, 2, 2, 2); + + gbc.gridx = 0; + gbc.gridy = 0; + mainPanel.add(getTermsLabel(), gbc); + + gbc.gridy = 1; + gbc.anchor = GridBagConstraints.CENTER; + gbc.fill = GridBagConstraints.NONE; + gbc.weightx = 0; + gbc.weighty = 0; + mainPanel.add(getAgreeBox(), gbc); + } + return mainPanel; + } + + private void refreshState() { + getButton(OK).setEnabled(getAgreeBox().isSelected()); + } + + private JCheckBox getAgreeBox() { + if (agreeBox == null) { + agreeBox = new JCheckBox("I agree to these terms"); + agreeBox.addChangeListener(new ChangeListener() { + + @Override + public void stateChanged(ChangeEvent e) { + refreshState(); + } + }); + } + return agreeBox; + } + + private JLabel getTermsLabel() { + if (termsLabel == null) { + termsLabel = new JLabel(); + termsLabel.setOpaque(true); + termsLabel.setBackground(UIManager.getColor("ToolTip.background")); + termsLabel.setBorder(BorderFactory.createCompoundBorder(BorderFactory + .createEtchedBorder(), BorderFactory.createEmptyBorder(2, 2, 2, 2))); + termsLabel.setText(TERMS_HTML); + } + return termsLabel; + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/statusbar/StatusBar.java b/diylc-swing/src/org/diylc/swing/plugins/statusbar/StatusBar.java new file mode 100644 index 00000000..b17542dc --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/statusbar/StatusBar.java @@ -0,0 +1,308 @@ +package org.diylc.swing.plugins.statusbar; + +import java.awt.BorderLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.geom.Point2D; +import java.text.DecimalFormat; +import java.text.Format; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import javax.swing.BorderFactory; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +import org.apache.log4j.Logger; +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.appframework.miscutils.Utils; +import org.diylc.common.BadPositionException; +import org.diylc.common.ComponentType; +import org.diylc.common.EventType; +import org.diylc.common.IPlugIn; +import org.diylc.common.IPlugInPort; +import org.diylc.core.IDIYComponent; +import org.diylc.images.IconLoader; +import org.diylc.presenter.Presenter; +import org.diylc.swing.ISwingUI; +import org.diylc.swingframework.MemoryBar; +import org.diylc.swingframework.miscutils.PercentageListCellRenderer; +import org.diylc.swingframework.update.UpdateLabel; + +public class StatusBar extends JPanel implements IPlugIn { + + private static final long serialVersionUID = 1L; + + private static final Logger LOG = Logger.getLogger(StatusBar.class); + + public static String UPDATE_URL = "http://www.diy-fever.com/update.xml"; + private static final Format sizeFormat = new DecimalFormat("0.##"); + + private JComboBox zoomBox; + private UpdateLabel updateLabel; + private MemoryBar memoryPanel; + private JLabel statusLabel; + private JLabel sizeLabel; + + private IPlugInPort plugInPort; + + // State variables + private ComponentType componentSlot; + private Point controlPointSlot; + private List componentNamesUnderCursor; + private List selectedComponentNames; + private List stuckComponentNames; + private String statusMessage; + + public StatusBar(ISwingUI swingUI) { + super(); + + setLayout(new GridBagLayout()); + + try { + swingUI.injectGUIComponent(this, SwingUtilities.BOTTOM); + } catch (BadPositionException e) { + LOG.error("Could not install status bar", e); + } + } + + private JComboBox getZoomBox() { + if (zoomBox == null) { + zoomBox = new JComboBox(plugInPort.getAvailableZoomLevels()); + zoomBox.setSelectedItem(plugInPort.getZoomLevel()); + zoomBox.setFocusable(false); + zoomBox.setRenderer(new PercentageListCellRenderer()); + zoomBox.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + plugInPort.setZoomLevel((Double) zoomBox.getSelectedItem()); + } + }); + } + return zoomBox; + } + + private UpdateLabel getUpdateLabel() { + if (updateLabel == null) { + updateLabel = new UpdateLabel(plugInPort.getCurrentVersionNumber(), UPDATE_URL); + // updateLabel.setBorder(BorderFactory.createCompoundBorder( + // BorderFactory.createEtchedBorder(), BorderFactory + // .createEmptyBorder(2, 4, 2, 4))); + updateLabel.setBorder(BorderFactory.createEmptyBorder(2, 4, 2, 4)); + } + return updateLabel; + } + + private MemoryBar getMemoryPanel() { + if (memoryPanel == null) { + memoryPanel = new MemoryBar(false); + } + return memoryPanel; + } + + private JLabel getStatusLabel() { + if (statusLabel == null) { + statusLabel = new JLabel(); + statusLabel.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 0)); + } + return statusLabel; + } + + public JLabel getSizeLabel() { + if (sizeLabel == null) { + sizeLabel = new JLabel(IconLoader.Size.getIcon()); + sizeLabel.setFocusable(true); + sizeLabel.setToolTipText("Click to calculate selection size"); + sizeLabel.addMouseListener(new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { + Point2D size = plugInPort.calculateSelectionDimension(); + boolean metric = ConfigurationManager.getInstance().readBoolean( + Presenter.METRIC_KEY, true); + String text; + if (size == null) { + text = "Selection is empty."; + } else { + text = "Selection size: " + sizeFormat.format(size.getX()) + " x " + + sizeFormat.format(size.getY()) + (metric ? " cm" : " in"); + } + JOptionPane.showMessageDialog(SwingUtilities.getRootPane(StatusBar.this), text, + "Information", JOptionPane.INFORMATION_MESSAGE); + } + }); + } + return sizeLabel; + } + + private void layoutComponents() { + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.weightx = 1; + add(getStatusLabel(), gbc); + + JPanel zoomPanel = new JPanel(new BorderLayout()); + zoomPanel.add(new JLabel("Zoom: "), BorderLayout.WEST); + zoomPanel.add(getZoomBox(), BorderLayout.CENTER); + // zoomPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory + // .createEtchedBorder(), BorderFactory.createEmptyBorder(2, 4, 2, + // 4))); + zoomPanel.setBorder(BorderFactory.createEmptyBorder(2, 4, 2, 4)); + + gbc.gridx = 1; + gbc.fill = GridBagConstraints.BOTH; + gbc.weightx = 0; + add(zoomPanel, gbc); + + gbc.gridx = 2; + add(getSizeLabel(), gbc); + + gbc.gridx = 3; + add(getUpdateLabel(), gbc); + + gbc.gridx = 4; + gbc.fill = GridBagConstraints.NONE; + add(getMemoryPanel(), gbc); + + gbc.gridx = 5; + add(new JPanel(), gbc); + } + + // IPlugIn + + @Override + public void connect(IPlugInPort plugInPort) { + this.plugInPort = plugInPort; + + layoutComponents(); + } + + @Override + public EnumSet getSubscribedEventTypes() { + return EnumSet.of(EventType.ZOOM_CHANGED, EventType.SLOT_CHANGED, + EventType.AVAILABLE_CTRL_POINTS_CHANGED, EventType.SELECTION_CHANGED, + EventType.STATUS_MESSAGE_CHANGED); + } + + @SuppressWarnings("unchecked") + @Override + public void processMessage(EventType eventType, Object... params) { + switch (eventType) { + case ZOOM_CHANGED: + if (!params[0].equals(getZoomBox().getSelectedItem())) { + final Double zoom = (Double) params[0]; + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + getZoomBox().setSelectedItem(zoom); + } + }); + } + break; + case SELECTION_CHANGED: + List> selection = (List>) params[0]; + Collection> stuckComponents = (Collection>) params[1]; + Collection componentNames = new HashSet(); + for (IDIYComponent component : selection) { + componentNames.add("" + component.getName() + ""); + } + this.selectedComponentNames = new ArrayList(componentNames); + Collections.sort(this.selectedComponentNames); + this.stuckComponentNames = new ArrayList(); + for (IDIYComponent component : stuckComponents) { + this.stuckComponentNames.add("" + component.getName() + + ""); + } + this.stuckComponentNames.removeAll(this.selectedComponentNames); + Collections.sort(this.stuckComponentNames); + refreshStatusText(); + break; + case SLOT_CHANGED: + componentSlot = (ComponentType) params[0]; + controlPointSlot = (Point) params[1]; + refreshStatusText(); + break; + case AVAILABLE_CTRL_POINTS_CHANGED: + componentNamesUnderCursor = new ArrayList(); + for (IDIYComponent component : ((Map, Integer>) params[0]).keySet()) { + componentNamesUnderCursor.add("" + component.getName() + + ""); + } + Collections.sort(componentNamesUnderCursor); + refreshStatusText(); + break; + case STATUS_MESSAGE_CHANGED: + statusMessage = (String) params[0]; + } + } + + private void refreshStatusText() { + String statusText = this.statusMessage; + if (componentSlot == null) { + if (componentNamesUnderCursor != null && !componentNamesUnderCursor.isEmpty()) { + String formattedNames = Utils.toCommaString(componentNamesUnderCursor); + statusText = "Drag control point(s) of " + formattedNames + ""; + } else if (selectedComponentNames != null && !selectedComponentNames.isEmpty()) { + StringBuilder builder = new StringBuilder(); + builder.append(Utils.toCommaString(selectedComponentNames.subList(0, Math.min(20, + selectedComponentNames.size())))); + if (selectedComponentNames.size() > 15) { + builder.append(" and " + (selectedComponentNames.size() - 15) + " more"); + } + if (!stuckComponentNames.isEmpty()) { + builder.append(" (hold Ctrl and drag to unstuck from "); + builder.append(Utils.toCommaString(stuckComponentNames.subList(0, Math.min(5, + stuckComponentNames.size())))); + if (stuckComponentNames.size() > 5) { + builder.append(" and " + (stuckComponentNames.size() - 5) + " more"); + } + builder.append(")"); + } + statusText = "Selection: " + builder.toString() + ""; + } + } else { + switch (componentSlot.getCreationMethod()) { + case POINT_BY_POINT: + String count; + if (controlPointSlot == null) { + count = "first"; + } else { + count = "second"; + } + statusText = "Click on the canvas to set the " + count + + " control point of a new " + componentSlot.getName() + + " or press Esc to cancel"; + break; + case SINGLE_CLICK: + statusText = "Click on the canvas to create a new " + + componentSlot.getName() + " or press Esc to cancel"; + break; + } + } + final String finalStatus = statusText; + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + getStatusLabel().setText(finalStatus); + } + }); + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/toolbox/ComponentButton.java b/diylc-swing/src/org/diylc/swing/plugins/toolbox/ComponentButton.java new file mode 100644 index 00000000..0aeba1a6 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/toolbox/ComponentButton.java @@ -0,0 +1,106 @@ +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("" + componentType.getName() + "
" + + componentType.getDescription() + "
Author: " + componentType.getAuthor() + + "

Double click to select all components of this type" + + ""); + // initializeDnD(); + addMouseListener(new MouseAdapter() { + + @Override + public void mousePressed(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + plugInPort.setNewComponentTypeSlot(componentType); + } else { + List> components = plugInPort.getCurrentProject().getComponents(); + List> newSelection = new ArrayList>(); + 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())); + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/toolbox/ComponentTabbedPane.java b/diylc-swing/src/org/diylc/swing/plugins/toolbox/ComponentTabbedPane.java new file mode 100644 index 00000000..66c73d24 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/toolbox/ComponentTabbedPane.java @@ -0,0 +1,182 @@ +package org.diylc.swing.plugins.toolbox; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Container; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.apache.log4j.Logger; +import org.diylc.appframework.miscutils.ConfigurationManager; +import org.diylc.appframework.miscutils.IConfigListener; +import org.diylc.common.ComponentType; +import org.diylc.common.IPlugInPort; +import org.diylc.core.IDIYComponent; +import org.diylc.presenter.ComparatorFactory; +import org.diylc.presenter.ComponentProcessor; +import org.diylc.presenter.Presenter; + +/** + * Tabbed pane that shows all available components categorized into tabs. + * + * @author Branislav Stojkovic + */ +class ComponentTabbedPane extends JTabbedPane { + + private static final long serialVersionUID = 1L; + + private static final Logger LOG = Logger.getLogger(ComponentTabbedPane.class); + + public static int SCROLL_STEP = Presenter.ICON_SIZE + ComponentButton.MARGIN * 2 + 2; + + private final IPlugInPort plugInPort; + private Container recentToolbar; + private List pendingRecentComponents = null; + + public ComponentTabbedPane(IPlugInPort plugInPort) { + super(); + this.plugInPort = plugInPort; + addTab("Recently Used", createRecentComponentsPanel()); + Map> componentTypes = plugInPort.getComponentTypes(); + List categories = new ArrayList(componentTypes.keySet()); + Collections.sort(categories); + for (String category : categories) { + JPanel panel = createTab((componentTypes.get(category))); + addTab(category, panel); + } + addChangeListener(new ChangeListener() { + + @Override + public void stateChanged(ChangeEvent e) { + ComponentTabbedPane.this.plugInPort.setNewComponentTypeSlot(null); + // Refresh recent components if needed + if (pendingRecentComponents != null) { + refreshRecentComponentsToolbar(getRecentToolbar(), pendingRecentComponents); + getRecentToolbar().invalidate(); + pendingRecentComponents = null; + } + } + }); + } + + private JPanel createTab(List componentTypes) { + JPanel panel = new JPanel(new BorderLayout()); + // final JScrollPane scrollPane = + // createComponentScrollBar(componentTypes); + panel.setOpaque(false); + panel.add(createComponentPanel(componentTypes), BorderLayout.CENTER); + // JButton leftButton = new JButton("<"); + // leftButton.addActionListener(new ActionListener() { + // + // @Override + // public void actionPerformed(ActionEvent e) { + // Rectangle rect = scrollPane.getVisibleRect(); + // if (rect.x > SCROLL_STEP) { + // rect.translate(-SCROLL_STEP, 0); + // } else { + // rect.translate(-rect.x, 0); + // } + // } + // }); + // leftButton.setMargin(new Insets(0, 2, 0, 2)); + // JButton rightButton = new JButton(">"); + // rightButton.addActionListener(new ActionListener() { + // + // @Override + // public void actionPerformed(ActionEvent e) { + // Rectangle rect = scrollPane.getVisibleRect(); + // if (rect.x + rect.width < scrollPane.getViewport().getSize().width - + // SCROLL_STEP) { + // rect.translate(SCROLL_STEP, 0); + // } else { + // rect.translate(scrollPane.getViewport().getSize().width - rect.x - + // rect.width, + // 0); + // } + // } + // }); + // rightButton.setMargin(new Insets(0, 2, 0, 2)); + // panel.add(leftButton, BorderLayout.WEST); + // panel.add(scrollPane); + // panel.add(rightButton, BorderLayout.EAST); + return panel; + } + + // private JScrollPane createComponentScrollBar(List + // componentTypes) { + // JScrollPane scrollPane = new + // JScrollPane(createComponentPanel(componentTypes)); + // scrollPane.setOpaque(false); + // scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + // scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); + // return scrollPane; + // } + + public Container getRecentToolbar() { + if (recentToolbar == null) { + recentToolbar = new Container(); + recentToolbar.setLayout(new BoxLayout(recentToolbar, BoxLayout.X_AXIS)); + } + return recentToolbar; + } + + private Component createComponentPanel(List componentTypes) { + Container toolbar = new Container(); + Collections.sort(componentTypes, ComparatorFactory.getInstance() + .getComponentTypeComparator()); + toolbar.setLayout(new BoxLayout(toolbar, BoxLayout.X_AXIS)); + for (ComponentType componentType : componentTypes) { + JButton button = new ComponentButton(plugInPort, componentType); + toolbar.add(button); + } + + return toolbar; + } + + private Component createRecentComponentsPanel() { + JPanel panel = new JPanel(new BorderLayout()); + panel.setOpaque(false); + + final Container toolbar = getRecentToolbar(); + refreshRecentComponentsToolbar(toolbar, (List) ConfigurationManager.getInstance() + .readObject(IPlugInPort.RECENT_COMPONENTS_KEY, new ArrayList())); + ConfigurationManager.getInstance().addConfigListener(IPlugInPort.RECENT_COMPONENTS_KEY, + new IConfigListener() { + + @Override + public void valueChanged(String key, Object value) { + // Cache the new list, we'll refresh when there's a chance + pendingRecentComponents = (List) value; + } + }); + + panel.add(toolbar, BorderLayout.CENTER); + + return panel; + } + + private void refreshRecentComponentsToolbar(Container toolbar, + List recentComponentClassList) { + toolbar.removeAll(); + for (String componentClassName : recentComponentClassList) { + ComponentType componentType; + try { + componentType = ComponentProcessor.getInstance().extractComponentTypeFrom( + (Class>) Class.forName(componentClassName)); + JButton button = new ComponentButton(plugInPort, componentType); + toolbar.add(button); + } catch (ClassNotFoundException e) { + LOG.error("Could not create recent component button for " + componentClassName, e); + } + } + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/toolbox/ToolBox.java b/diylc-swing/src/org/diylc/swing/plugins/toolbox/ToolBox.java new file mode 100644 index 00000000..e8c02b59 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/toolbox/ToolBox.java @@ -0,0 +1,57 @@ +package org.diylc.swing.plugins.toolbox; + +import java.util.EnumSet; + +import javax.swing.SwingConstants; + +import org.apache.log4j.Logger; +import org.diylc.common.BadPositionException; +import org.diylc.common.EventType; +import org.diylc.common.IPlugIn; +import org.diylc.common.IPlugInPort; +import org.diylc.swing.ISwingUI; +import org.diylc.swing.plugins.statusbar.StatusBar; + + +public class ToolBox implements IPlugIn { + + private static final Logger LOG = Logger.getLogger(StatusBar.class); + + private ISwingUI swingUI; + private IPlugInPort plugInPort; + + private ComponentTabbedPane componentTabbedPane; + + public ToolBox(ISwingUI swingUI) { + this.swingUI = swingUI; + } + + @Override + public void connect(IPlugInPort plugInPort) { + this.plugInPort = plugInPort; + try { + swingUI.injectGUIComponent(getComponentTabbedPane(), SwingConstants.TOP); + } catch (BadPositionException e) { + LOG.error("Could not install the toolbox", e); + } + } + + public ComponentTabbedPane getComponentTabbedPane() { + if (componentTabbedPane == null) { + componentTabbedPane = new ComponentTabbedPane(plugInPort); + } + return componentTabbedPane; + } + + @Override + public EnumSet getSubscribedEventTypes() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void processMessage(EventType eventType, Object... params) { + // TODO Auto-generated method stub + + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/toolbox/ToolboxGestureListener.java b/diylc-swing/src/org/diylc/swing/plugins/toolbox/ToolboxGestureListener.java new file mode 100644 index 00000000..35e08a1d --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/toolbox/ToolboxGestureListener.java @@ -0,0 +1,33 @@ +package org.diylc.swing.plugins.toolbox; + +import java.awt.Cursor; +import java.awt.datatransfer.StringSelection; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; + +import org.diylc.common.IPlugInPort; + + +/** + * {@link DragGestureListener} for {@link CanvasPanel}. + * + * @author Branislav Stojkovic + */ +class ToolboxGestureListener implements DragGestureListener { + + private IPlugInPort presenter; + private String className; + + public ToolboxGestureListener(IPlugInPort presenter, String className) { + super(); + this.presenter = presenter; + this.className = className; + } + + @Override + public void dragGestureRecognized(DragGestureEvent dge) { +// presenter.dragStarted(dge.getDragOrigin()); + dge.startDrag(Cursor.getDefaultCursor(), new StringSelection(className), + new ToolboxSourceListener(presenter)); + } +} diff --git a/diylc-swing/src/org/diylc/swing/plugins/toolbox/ToolboxSourceListener.java b/diylc-swing/src/org/diylc/swing/plugins/toolbox/ToolboxSourceListener.java new file mode 100644 index 00000000..2dd25419 --- /dev/null +++ b/diylc-swing/src/org/diylc/swing/plugins/toolbox/ToolboxSourceListener.java @@ -0,0 +1,47 @@ +package org.diylc.swing.plugins.toolbox; + +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; + +import javax.swing.JComponent; + +import org.diylc.common.IPlugInPort; + + +/** + * {@link DragSourceListener} for {@link CanvasPanel}. + * + * @author Branislav Stojkovic + */ +class ToolboxSourceListener implements DragSourceListener { + + private IPlugInPort presenter; + + public ToolboxSourceListener(IPlugInPort presenter) { + super(); + this.presenter = presenter; + } + + @Override + public void dragDropEnd(DragSourceDropEvent dsde) { + ((JComponent) dsde.getDragSourceContext().getComponent()).revalidate(); + } + + @Override + public void dragEnter(DragSourceDragEvent dsde) { + } + + @Override + public void dragExit(DragSourceEvent dse) { + } + + @Override + public void dragOver(DragSourceDragEvent dsde) { + } + + @Override + public void dropActionChanged(DragSourceDragEvent dsde) { + } +} diff --git a/diylc-swing/templates/eyelet.diy b/diylc-swing/templates/eyelet.diy new file mode 100644 index 00000000..27fb5933 --- /dev/null +++ b/diylc-swing/templates/eyelet.diy @@ -0,0 +1,65 @@ + + New Project + Branislav Stojkovic + + 29.0 + cm + + + 21.0 + cm + + + 0.1 + in + + + + Board1 + 127 + + + + 555 + 450 + + + 1140 + 795 + + + + 555 + 450 + + + 1140 + 795 + + + 248 + 235 + 179 + 255 + + + 173 + 164 + 125 + 255 + + + 0.3 + in + + + 195 + 228 + 237 + 255 + + + + + + \ No newline at end of file diff --git a/diylc-swing/templates/perf.diy b/diylc-swing/templates/perf.diy new file mode 100644 index 00000000..0abb50f5 --- /dev/null +++ b/diylc-swing/templates/perf.diy @@ -0,0 +1,65 @@ + + New Project + Branislav Stojkovic + + 29.0 + cm + + + 21.0 + cm + + + 0.1 + in + + + + Board1 + 127 + + + + 585 + 450 + + + 1050 + 690 + + + + 585 + 450 + + + 1050 + 690 + + + 248 + 235 + 179 + 255 + + + 173 + 164 + 125 + 255 + + + 0.1 + in + + + 218 + 138 + 103 + 255 + + + + + + \ No newline at end of file diff --git a/diylc-swing/test/org/diylc/TableTest.java b/diylc-swing/test/org/diylc/TableTest.java new file mode 100644 index 00000000..21578424 --- /dev/null +++ b/diylc-swing/test/org/diylc/TableTest.java @@ -0,0 +1,55 @@ +package org.diylc; + +import java.util.ArrayList; +import java.util.List; + +import javax.swing.Icon; +import javax.swing.JFrame; +import javax.swing.JScrollPane; + +import org.apache.log4j.BasicConfigurator; +import org.diylc.swing.plugins.online.model.ProjectEntity; +import org.diylc.swingframework.objecttable.IActionProcessor; +import org.diylc.swingframework.objecttable.ObjectListTable; + +public class TableTest { + + /** + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + BasicConfigurator.configure(); + + List projects = new ArrayList(); + projects.add(new ProjectEntity(1, "first", "some text", "bane", "none")); + projects.add(new ProjectEntity(2, "second", "anoter text", "bisera", "none")); + + ObjectListTable t = new ObjectListTable(ProjectEntity.class, + new String[] { "getName", "getDescription", "getCategory", "getOwner", + "action:Download" }, new IActionProcessor() { + + @Override + public void actionExecuted(ProjectEntity value, String actionColumnName) { + System.out.println("row clicked: " + actionColumnName + " - " + value); + } + + @Override + public Icon getActionIcon(String actionColumnName) { + return null; + } + + @Override + public String getActionLabel(String actionColumnName) { + return "get me"; + } + }); + t.setData(projects); + JFrame f = new JFrame(); + f.add(new JScrollPane(t)); + f.pack(); + f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + f.setVisible(true); + } + +} diff --git a/diylc-swing/themes/Blueprint.xml b/diylc-swing/themes/Blueprint.xml new file mode 100644 index 00000000..bd5af8ab --- /dev/null +++ b/diylc-swing/themes/Blueprint.xml @@ -0,0 +1,21 @@ + + Blueprint + + 3 + 122 + 198 + 255 + + + 29 + 140 + 193 + 255 + + + 255 + 255 + 255 + 255 + + \ No newline at end of file diff --git a/diylc-swing/themes/Dark.xml b/diylc-swing/themes/Dark.xml new file mode 100644 index 00000000..ef5b0634 --- /dev/null +++ b/diylc-swing/themes/Dark.xml @@ -0,0 +1,21 @@ + + Dark + + 0 + 0 + 0 + 255 + + + 40 + 40 + 40 + 255 + + + 255 + 255 + 255 + 255 + + \ No newline at end of file diff --git a/diylc-swing/themes/Light.xml b/diylc-swing/themes/Light.xml new file mode 100644 index 00000000..d2841ca7 --- /dev/null +++ b/diylc-swing/themes/Light.xml @@ -0,0 +1,21 @@ + + Light + + 255 + 255 + 255 + 255 + + + 240 + 240 + 240 + 240 + + + 0 + 0 + 0 + 255 + + \ No newline at end of file diff --git a/diylc-swing/update.xml b/diylc-swing/update.xml new file mode 100644 index 00000000..8c0848eb --- /dev/null +++ b/diylc-swing/update.xml @@ -0,0 +1,681 @@ + + + + + 3 + 0 + 4 + + 2011-01-27 21:00:00.000 CET + + + + BUG_FIX + Copy/paste between two instances of the application + + + BUG_FIX + Parsing numerical values in countries that use comma as decimal separator + + + BUG_FIX + Dragging sticky points affects selectability of objects + + + BUG_FIX + Click is sometimes not registered while adding a new component + + + BUG_FIX + Fixed NPE when using default values + + + IMPROVEMENT + Allow shape control points of curves to overlap + + + IMPROVEMENT + Added DIL IC first pin indentation + + + IMPROVEMENT + Added transparency to the potentiometer + + + IMPROVEMENT + Reduced number of layers + + + IMPROVEMENT + Import from v1 files can now read label and electrolytic capacitor components and trace/pad colors + + + IMPROVEMENT + Added worker thread for longer file operation, so GUI doesn't freeze + + + NEW_FEATURE + Added right click menu on the canvas + + + NEW_FEATURE + Added "send to back" and "bring to front" options + + + NEW_FEATURE + Added label component + + + NEW_FEATURE + Added image component + + + http://code.google.com/p/diy-layout-creator/downloads/list + + + + + 3 + 0 + 5 + + 2011-01-30 20:00:00.000 CET + + + + BUG_FIX + Curved trace does not show control points + + + BUG_FIX + Potentiometer draws wrong at 180 degrees + + + IMPROVEMENT + Reset component selection when tab is changed + + + IMPROVEMENT + Resistor can show color bands + + + IMPROVEMENT + Electrolytic capacitor has a new icon and new looks + + + IMPROVEMENT + Solder pad can be square + + + IMPROVEMENT + Added keyboard shortcuts to some menu options + + + IMPROVEMENT + V1 file importer can recognize hookup wire and transistors + + + NEW_FEATURE + Added support for creating and loading templates + + + NEW_FEATURE + Added TO-92 transistor + + + NEW_FEATURE + Added TO-220 transistor + + + NEW_FEATURE + Added LED + + + NEW_FEATURE + Added axial electrolytic capacitor + + + http://code.google.com/p/diy-layout-creator/downloads/list + + + + 3 + 0 + 6 + + 2011-02-07 20:00:00.000 CET + + + + BUG_FIX + Copy/paste doesn't work for some components (potentiometer, transistor, etc) + + + BUG_FIX + Resistor color codes are sometimes wrong + + + IMPROVEMENT + Resistors can specify power handling + + + IMPROVEMENT + Capacitors can specify voltage handling + + + IMPROVEMENT + Fixed lead alignment issue + + + IMPROVEMENT + Better scaling, grid lines are more precise + + + IMPROVEMENT + Improved performance + + + NEW_FEATURE + Added resistor schematic symbol + + + NEW_FEATURE + Added capacitor schematic symbol + + + NEW_FEATURE + Added eyelet/turret component + + + NEW_FEATURE + Added Marshall/Trainwreck style boards + + + NEW_FEATURE + Added few types of trimmers + + + NEW_FEATURE + Configurable rendering quality to improve speed + + + http://code.google.com/p/diy-layout-creator/downloads/list + + + + 3 + 0 + 7 + + 2011-02-27 20:00:00.000 CET + + + + BUG_FIX + Resistor and capacitor symbols are not clickable + + + BUG_FIX + Boards sometimes render holes/pads on the edge + + + BUG_FIX + Download link doesn't work on Mac + + + BUG_FIX + Ruler ticks don't always match with the grid + + + BUG_FIX + Micro symbol doesn't get exported to PDF + + + IMPROVEMENT + DIL IC now has more pin options + + + IMPROVEMENT + Send to Back/Bring to Front are more flexible and renamed to match what they do + + + NEW_FEATURE + Auto-save project and restore if app crashes + + + NEW_FEATURE + Added support for themes + + + NEW_FEATURE + Added tube socket + + + NEW_FEATURE + Sticky points may be turned off + + + NEW_FEATURE + Snap to Grid may be turned off + + + NEW_FEATURE + Auto-create solder pads + + + NEW_FEATURE + Auto-edit mode + + + NEW_FEATURE + Continuous component creation + + + http://code.google.com/p/diy-layout-creator/downloads/list + + + + 3 + 0 + 8 + + 2011-03-03 20:00:00.000 CET + + + + BUG_FIX + Sometimes it's not possible to click on a component, especially when layout is large + + + IMPROVEMENT + Curved traces and wires can have 2, 3 and 4 control points + + + NEW_FEATURE + Switchable wheel zoom + + + NEW_FEATURE + Automatic standing resistors, capacitors and diodes + + + NEW_FEATURE + Vertical vero board + + + NEW_FEATURE + Label has editable font + + + http://code.google.com/p/diy-layout-creator/downloads/list + + + + 3 + 0 + 9 + + 2011-08-28 20:00:00.000 CET + + + + BUG_FIX + Auto-created solder pads aren't assigned with default settings and name + + + IMPROVEMENT + Component edit dialog allows changing property values even when they are not the same. Boxes are marked yellow to designate multi-valued state. + + + IMPROVEMENT + Component edit dialog should show mutual properties when components of different types are selected (e.g. curved trace and straight trace width) + + + IMPROVEMENT + Ctrl+click should not clear selection when clicked on the canvas + + + IMPROVEMENT + Increased PNG export resolution + + + IMPROVEMENT + Auto-increment component names when copy-pasting + + + IMPROVEMENT + Do not attempt to write auto-save files if user does not have permissions to create files + + + IMPROVEMENT + Allow zero ohm resistors + + + NEW_FEATURE + Outline mode that resembles PCB silkscreen + + + NEW_FEATURE + Double click on a component button in the toolbar selects all components of that type + + + NEW_FEATURE + Renumber selected components by X or Y axis + + + NEW_FEATURE + Recently used components in the toolbar for easy navigation + + + http://code.google.com/p/diy-layout-creator/downloads/list + + + + 3 + 1 + 0 + + 2012-02-01 20:00:00.000 CET + + + + BUG_FIX + Selection sometimes highlights wrong component(s) + + + BUG_FIX + Renumber function sometimes doesn't work as expected + + + IMPROVEMENT + Increased PNG export resolution to 300dpi + + + IMPROVEMENT + Select All should not include locked components + + + IMPROVEMENT + Better lead and label rendering when lead spacing is smaller than component body + + + IMPROVEMENT + Allow more than 32 pins for IC + + + NEW_FEATURE + Adjustable solder pad hole size + + + http://code.google.com/p/diy-layout-creator/downloads/list + + + + 3 + 2 + 0 + + 2012-02-19 20:00:00.000 CET + + + + NEW_FEATURE + Select components from context menu even when they are under other components + + + NEW_FEATURE + Ctrl+Shift toggles "Snap to Grid" option + + + NEW_FEATURE + Perfboards can show hole coordinates + + + IMPROVEMENT + Smarter resistor labels; try not to overlap label with color code bands + + + IMPROVEMENT + Improved import from v1 file format + + + IMPROVEMENT + Imperial ruler is divided to .1" instead of 1/4" + + + IMPROVEMENT + Allow finer grid spacing up to 0.5mm (0.02") + + + IMPROVEMENT + Do not hard-code voltage and power ratings + + + http://code.google.com/p/diy-layout-creator/downloads/list + + + + 3 + 3 + 0 + + 2012-02-25 20:00:00.000 CET + + + + NEW_FEATURE + Expand selection feature, useful for debugging + + + IMPROVEMENT + Limit length of text in the status bar using "and X more" suffix + + + http://code.google.com/p/diy-layout-creator/downloads/list + + + + 3 + 4 + 0 + + 2012-03-09 20:00:00.000 CET + + + + NEW_FEATURE + IC Symbol + + + NEW_FEATURE + BJT Symbol + + + NEW_FEATURE + MOSFET Symbol + + + NEW_FEATURE + JFET Symbol + + + NEW_FEATURE + Line connector + + + IMPROVEMENT + IC component can display name or value + + + BUG_FIX + "Index out of bounds" exception logs when selecting components + + + BUG_FIX + Loading files fails because encoding is not recognized + + + BUG_FIX + Application breaks when resistance is set to 0 ohms + + + http://code.google.com/p/diy-layout-creator/downloads/list + + + + 3 + 5 + 0 + + 2012-03-15 20:00:00.000 CET + + + + NEW_FEATURE + Generic closed 1/4" jack + + + NEW_FEATURE + Cliff-style closed 1/4" jack + + + NEW_FEATURE + Ground Symbol + + + http://code.google.com/p/diy-layout-creator/downloads/list + + + + 3 + 6 + 0 + + 2012-03-21 20:00:00.000 CET + + + + IMPROVEMENT + Fonts are exported to PDF + + + NEW_FEATURE + Plastic DC jack + + + NEW_FEATURE + Humbucker pickup + + + NEW_FEATURE + Single coil pickup + + + http://code.google.com/p/diy-layout-creator/downloads/list + + + + 3 + 7 + 0 + + 2012-03-27 20:00:00.000 CET + + + + NEW_FEATURE + Lever guitar switch + + + NEW_FEATURE + 9V battery snap + + + http://code.google.com/p/diy-layout-creator/downloads/list + + + + 3 + 8 + 0 + + 2012-08-16 20:00:00.000 CET + + + + NEW_FEATURE + Right click rotates component while laying out on the canvas + + + NEW_FEATURE + Added DIY file association for Windows (run associations.bat) + + + IMPROVEMENT + More usable "Bring to Forward" and "Send to Backward" + + + IMPROVEMENT + Faster copy-paste functionality + + + IMPROVEMENT + Improved auto-save not to slow down the app + + + http://code.google.com/p/diy-layout-creator/downloads/list + + + + 3 + 9 + 0 + + 2012-08-20 20:00:00.000 CET + + + + NEW_FEATURE + Move selected components with arrow keys (and ctrl/shift) + + + IMPROVEMENT + Right-click in the toolbar to select all components of the same type + + + IMPROVEMENT + Click on a component in the toolbar sometimes doesn't register + + + IMPROVEMENT + Remove junk from BOM (eyelets, wires, traces) + + + IMPROVEMENT + Improved "Recently Used" toolbox, doesn't jump as you click + + + IMPROVEMENT + Control number of "Recently Used" items from config.properties + + + IMPROVEMENT + Faster component placement, auto-focus on "Value" box + + + IMPROVEMENT + Transistors can show name or value + + + IMPROVEMENT + UNICODE font export to PDF files + + + IMPROVEMENT + More intuitive unsaved file warning message + + + http://code.google.com/p/diy-layout-creator/downloads/list + + + \ No newline at end of file