/* * Copyright (c) 2005-2016 Substance Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Substance Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package tools.jitterbug; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsEnvironment; import java.awt.RenderingHints; import java.awt.Transparency; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetAdapter; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.io.InputStream; import javax.swing.Box; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; import org.pushingpixels.substance.api.SubstanceColorScheme; import org.pushingpixels.substance.api.SubstanceLookAndFeel; import org.pushingpixels.substance.api.skin.BusinessSkin; import org.pushingpixels.substance.internal.utils.SubstanceColorSchemeUtilities; import com.jgoodies.forms.builder.DefaultFormBuilder; import com.jgoodies.forms.layout.FormLayout; import tools.common.JImageComponent; import tools.jitterbug.StateChangeEvent.StateChangeType; public class JitterbugEditor extends JFrame implements ClipboardOwner { private static final String APP_TITLE = "Jitterbug color scheme editor"; private JColorSchemeList colorSchemeList; private JColorSchemeComponent colorSchemeComp; private JHsvGraph hsvGraph; private class JitterbugLogo implements Icon { @Override public int getIconHeight() { return 16; } @Override public int getIconWidth() { return 16; } @Override public void paintIcon(Component c, Graphics g, int x, int y) { Graphics2D g2d = (Graphics2D) g.create(); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.translate(x, y); double coef1 = (double) getIconWidth() / (double) substance.getOrigWidth(); double coef2 = (double) getIconHeight() / (double) substance.getOrigHeight(); double coef = Math.min(coef1, coef2); g2d.scale(coef, coef); g2d.translate(substance.getOrigX(), substance.getOrigY()); substance.paint(g2d); g2d.dispose(); } } protected class JitterbugDropHandler extends DropTargetAdapter { @Override public void drop(DropTargetDropEvent dtde) { Transferable t = dtde.getTransferable(); if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { try { dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); java.util.List files = (java.util.List) t .getTransferData(DataFlavor.javaFileListFlavor); File f = (File) files.get(0); System.out.println("Reading from " + f.getAbsolutePath()); colorSchemeList.setColorSchemeList(f); colorSchemeComp.clearContent(); dtde.dropComplete(true); JitterbugEditor.this.setTitle(APP_TITLE + " - " + f.getAbsolutePath()); return; } catch (Exception exc) { exc.printStackTrace(); } } // if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) { // try { // dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); // String content = (String) t // .getTransferData(DataFlavor.stringFlavor); // colorSchemeComp.setContent(new ByteArrayInputStream(content // .getBytes())); // dtde.dropComplete(true); // return; // } catch (Exception exc) { // exc.printStackTrace(); // } // } } @Override public void dragEnter(DropTargetDragEvent dtde) { for (DataFlavor df : dtde.getCurrentDataFlavors()) { Class<?> repClass = df.getDefaultRepresentationClass(); boolean canDrop = InputStream.class.isAssignableFrom(repClass); if (canDrop) { dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE); return; } } } } public JitterbugEditor() { super(); BufferedImage iconImage = GraphicsEnvironment .getLocalGraphicsEnvironment().getDefaultScreenDevice() .getDefaultConfiguration().createCompatibleImage(16, 16, Transparency.TRANSLUCENT); new JitterbugLogo().paintIcon(this, iconImage.getGraphics(), 0, 0); this.setIconImage(iconImage); FormLayout leftPanelLayout = new FormLayout("fill:pref", "fill:pref, fill:pref, fill:pref:grow, fill:pref"); DefaultFormBuilder leftPanelBuilder = new DefaultFormBuilder( leftPanelLayout); this.colorSchemeList = new JColorSchemeList(); this.colorSchemeList.setDropTarget(new DropTarget(this, new JitterbugDropHandler())); leftPanelBuilder.append(this.colorSchemeList); this.colorSchemeComp = new JColorSchemeComponent(); this.colorSchemeComp.setEnabled(false); this.colorSchemeComp.setDropTarget(new DropTarget(this, new JitterbugDropHandler())); leftPanelBuilder.append(this.colorSchemeComp); this.hsvGraph = new JHsvGraph(); this.hsvGraph.setDropTarget(new DropTarget(this, new JitterbugDropHandler())); leftPanelBuilder.append(this.hsvGraph); JPanel controlsPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING)); final JButton saveButton = new JButton("save"); saveButton.setIcon(new ImageIcon(JitterbugEditor.class.getClassLoader() .getResource("tools/jitterbug/page_save.png"))); saveButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { colorSchemeList.save(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { saveButton.setEnabled(false); } }); } }); saveButton.setEnabled(false); controlsPanel.add(saveButton); JButton saveAsButton = new JButton("save as..."); saveAsButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { colorSchemeList.saveAs(); updateMainWindowTitle(colorSchemeList.isModified()); } }); controlsPanel.add(saveAsButton); JButton newButton = new JButton("new"); newButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { colorSchemeList.setColorSchemeList(null); colorSchemeComp.clearContent(); updateMainWindowTitle(colorSchemeList.isModified()); } }); controlsPanel.add(Box.createHorizontalStrut(20)); controlsPanel.add(newButton); leftPanelBuilder.append(controlsPanel); JPanel leftPanel = leftPanelBuilder.getPanel(); // wire drag and drop wireDragAndDrop(leftPanel); // wire color scheme selection in the list to the // color scheme component this.colorSchemeList.addPropertyChangeListener("selectedColorScheme", new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { SubstanceColorScheme newSelection = (SubstanceColorScheme) evt .getNewValue(); if (newSelection != null) colorSchemeComp.setContent(newSelection); else colorSchemeComp.clearContent(); } }); // track color modifications of the currently selected // color scheme this.colorSchemeComp.addStateChangeListener(new StateChangeListener() { @Override public void stateChanged(StateChangeEvent event) { if (event.getStateChangeType() == StateChangeType.MODIFIED) { // let the color scheme list know that there was change colorSchemeList.setModified(true); } // update the HSV graph component if (colorSchemeComp.isDefined()) { Color[] colors = new Color[] { colorSchemeComp.getUltraLightColor(), colorSchemeComp.getExtraLightColor(), colorSchemeComp.getLightColor(), colorSchemeComp.getMidColor(), colorSchemeComp.getDarkColor(), colorSchemeComp.getUltraDarkColor() }; hsvGraph.setColors(colors); } else { hsvGraph.setColors(null); } if (event.getStateChangeType() == StateChangeType.MODIFIED) { if (colorSchemeComp.isDefined()) { boolean isLight = colorSchemeComp.isLight(); Color ultraDark = colorSchemeComp.getUltraDarkColor(); Color dark = colorSchemeComp.getDarkColor(); Color mid = colorSchemeComp.getMidColor(); Color light = colorSchemeComp.getLightColor(); Color extraLight = colorSchemeComp.getExtraLightColor(); Color ultraLight = colorSchemeComp.getUltraLightColor(); Color foreground = colorSchemeComp.getForegroundColor(); String name = colorSchemeComp.getDisplayName(); Color[] colors = new Color[] { ultraLight, extraLight, light, mid, dark, ultraDark, foreground }; SubstanceColorScheme scheme = isLight ? SubstanceColorSchemeUtilities .getLightColorScheme(name, colors) : SubstanceColorSchemeUtilities .getDarkColorScheme(name, colors); colorSchemeList.updateColorScheme(scheme); } } } }); // track modification changes on the scheme list and any scheme in it this.colorSchemeList.addPropertyChangeListener("modified", new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { boolean isModified = (Boolean) evt.getNewValue(); getRootPane().putClientProperty( SubstanceLookAndFeel.WINDOW_MODIFIED, Boolean.valueOf(isModified)); // update the main frame title updateMainWindowTitle(isModified); File currFile = colorSchemeList.getCurrentFile(); saveButton.setEnabled(currFile != null); } }); this.add(leftPanel, BorderLayout.WEST); JPanel mainPanel = new JPanel(new BorderLayout()); JImageComponent imageComp = new JImageComponent(true); imageComp .setLegend(new String[] { "Image panel. Use one of the following to show an image:", "\t* Right-click to paste an image from the clipboard", "\t* Drag and drop an image file from local disk or another app", "\t* Drag and drop a URL pointing to an image" }); imageComp.addPropertyChangeListener("selectedColor", new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { Color selectedImageColor = (Color) evt.getNewValue(); JColorComponent selectedColorComp = colorSchemeComp .getSelectedColorComponent(); if (selectedColorComp != null) { selectedColorComp .setColor(selectedImageColor, true); } } }); mainPanel.add(imageComp, BorderLayout.CENTER); this.add(mainPanel, BorderLayout.CENTER); this.setSize(800, 700); this.setExtendedState(JFrame.MAXIMIZED_BOTH); this.setLocationRelativeTo(null); this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { // do we need to save the modified scheme list? if (colorSchemeList.checkModifiedStateAndSaveIfNecessary()) { dispose(); } } }); this.updateMainWindowTitle(false); } private void wireDragAndDrop(Component comp) { comp.setDropTarget(new DropTarget(this, new JitterbugDropHandler())); if (comp instanceof Container) { Container cont = (Container) comp; for (int i = 0; i < cont.getComponentCount(); i++) { wireDragAndDrop(cont.getComponent(i)); } } } @Override public void lostOwnership(Clipboard clipboard, Transferable contents) { } private void updateMainWindowTitle(boolean isModified) { File schemesFile = colorSchemeList.getCurrentFile(); String title = APP_TITLE + " - "; if (isModified) { title += "* "; } if (schemesFile != null) { title += schemesFile.getAbsolutePath(); } else { title += "Unsaved"; } setTitle(title); } public static void main(String[] args) { JDialog.setDefaultLookAndFeelDecorated(true); JFrame.setDefaultLookAndFeelDecorated(true); SwingUtilities.invokeLater(new Runnable() { public void run() { SubstanceLookAndFeel.setSkin(new BusinessSkin()); new JitterbugEditor().setVisible(true); } }); } }