freehep-swing-2.0.3/0000755012010301201030000000000011275634131015250 5ustar mascellanimascellanifreehep-swing-2.0.3/src/0000755012010301201030000000000011275634131016037 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/0000755012010301201030000000000011275634131017016 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/java/0000755012010301201030000000000011275634131017737 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/java/org/0000755012010301201030000000000011275634131020526 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/java/org/freehep/0000755012010301201030000000000011275634131022144 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/java/org/freehep/swing/0000755012010301201030000000000011275634131023273 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/java/org/freehep/swing/treetable/0000755012010301201030000000000011275634131025242 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/java/org/freehep/swing/treetable/test/0000755012010301201030000000000011275634131026221 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/java/org/freehep/swing/treetable/test/TreeTableExample2.java0000644012010301201030000003673010466735775032363 0ustar mascellanimascellanipackage org.freehep.swing.treetable.test; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.text.NumberFormat; import javax.swing.ButtonGroup; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JRadioButtonMenuItem; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.border.BevelBorder; import javax.swing.event.TableModelEvent; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.tree.TreePath; import org.freehep.swing.treetable.JTreeTable; /** * Assembles the UI. The UI consists of a JTreeTable and a status label. * As nodes are loaded by the FileSystemModel2, in a background thread, * the status label updates as well as the renderer to draw the node that * is being loaded differently. * * @author Scott Violet * @author Philip Milne */ public class TreeTableExample2 { /** Number of instances of TreeTableExample2. */ protected static int ttCount; /** Model for the JTreeTable. */ protected FileSystemModel2 model; /** Used to represent the model. */ protected JTreeTable treeTable; /** Row the is being reloaded. */ protected int reloadRow; /** TreePath being reloaded. */ protected TreePath reloadPath; /** A counter increment as the Timer fies and the same path is * being reloaded. */ protected int reloadCounter; /** Timer used to update reload state. */ protected Timer timer; /** Used to indicate status. */ protected JLabel statusLabel; /** Frame containing everything. */ protected JFrame frame; /** Path created with. */ protected String path; public TreeTableExample2(String path) { this.path = path; ttCount++; frame = createFrame(); Container cPane = frame.getContentPane(); JMenuBar mb = createMenuBar(); model = createModel(path); treeTable = createTreeTable(); statusLabel = createStatusLabel(); cPane.add(new JScrollPane(treeTable)); cPane.add(statusLabel, BorderLayout.SOUTH); reloadRow = -1; frame.setJMenuBar(mb); frame.pack(); frame.setVisible(true); SwingUtilities.invokeLater(new Runnable() { public void run() { reload(model.getRoot()); } }); } /** * Creates and return a JLabel that is used to indicate the status * of loading. */ protected JLabel createStatusLabel() { JLabel retLabel = new JLabel(" "); retLabel.setHorizontalAlignment(JLabel.RIGHT); retLabel.setBorder(new BevelBorder(BevelBorder.LOWERED)); return retLabel; } /** * Creates and returns the instanceof JTreeTable that will be used. * This also creates, but does not start, the Timer that is used to * update the display as files are loaded. */ protected JTreeTable createTreeTable() { JTreeTable treeTable = new JTreeTable(model); treeTable.getColumnModel().getColumn(1).setCellRenderer (new IndicatorRenderer()); Reloader rl = new Reloader(); timer = new Timer(700, rl); timer.setRepeats(true); treeTable.getTree().addTreeExpansionListener(rl); return treeTable; } /** * Creates the FileSystemModel2 that will be used. */ protected FileSystemModel2 createModel(String path) { return new FileSystemModel2(path); } /** * Creates the JFrame that will contain everything. */ protected JFrame createFrame() { JFrame retFrame = new JFrame("TreeTable II"); retFrame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { if (--ttCount == 0) { System.exit(0); } } }); return retFrame; } /** * Creates a menu bar. */ protected JMenuBar createMenuBar() { JMenu fileMenu = new JMenu("File"); JMenuItem menuItem; menuItem = new JMenuItem("Open"); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { JFileChooser fc = new JFileChooser(path); fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int result = fc.showOpenDialog(frame); if (result == JFileChooser.APPROVE_OPTION) { String newPath = fc.getSelectedFile().getPath(); new TreeTableExample2(newPath); } } }); fileMenu.add(menuItem); fileMenu.addSeparator(); menuItem = new JMenuItem("Reload"); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { TreePath path = treeTable.getTree().getSelectionPath(); if (path != null) { model.stopLoading(); reload(path.getLastPathComponent()); } } }); fileMenu.add(menuItem); menuItem = new JMenuItem("Stop"); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { model.stopLoading(); } }); fileMenu.add(menuItem); fileMenu.addSeparator(); menuItem = new JMenuItem("Exit"); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { System.exit(0); } }); fileMenu.add(menuItem); // Create a menu bar JMenuBar menuBar = new JMenuBar(); menuBar.add(fileMenu); // Menu for the look and feels (lafs). UIManager.LookAndFeelInfo[] lafs = UIManager. getInstalledLookAndFeels(); ButtonGroup lafGroup = new ButtonGroup(); JMenu optionsMenu = new JMenu("Options"); menuBar.add(optionsMenu); for(int i = 0; i < lafs.length; i++) { JRadioButtonMenuItem rb = new JRadioButtonMenuItem(lafs[i]. getName()); optionsMenu.add(rb); rb.setSelected(UIManager.getLookAndFeel().getName().equals (lafs[i].getName())); rb.putClientProperty("UIKey", lafs[i]); rb.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent ae) { JRadioButtonMenuItem rb2 = (JRadioButtonMenuItem)ae. getSource(); if(rb2.isSelected()) { UIManager.LookAndFeelInfo info = (UIManager.LookAndFeelInfo) rb2.getClientProperty("UIKey"); try { UIManager.setLookAndFeel(info.getClassName()); SwingUtilities.updateComponentTreeUI(frame); } catch (Exception e) { System.err.println("unable to set UI " + e.getMessage()); } } } }); lafGroup.add(rb); } return menuBar; } /** * Invoked to reload the children of a particular node. This will * also restart the timer. */ protected void reload(Object node) { model.reloadChildren(node); if (!timer.isRunning()) { timer.start(); } } /** * Updates the status label based on reloadRow. */ protected void updateStatusLabel() { if (reloadPath != null) { statusLabel.setText("Reloading: " + model.getPath (reloadPath.getLastPathComponent())); if ((reloadCounter % 4) < 2) { statusLabel.setForeground(Color.red); } else { statusLabel.setForeground(Color.blue); } } else if (!model.isReloading()) { statusLabel.setText("Total Size: " + NumberFormat.getInstance(). format(model.getTotalSize(model.getRoot()))); statusLabel.setForeground(Color.black); } } /** * Reloader is the ActionListener used in the Timer. In response to * the timer updating it will reset the reloadRow/reloadPath and * generate the necessary event so that the display will update. It * also implements the TreeExpansionListener so that if the tree is * altered while loading the reloadRow is updated accordingly. */ class Reloader implements ActionListener, TreeExpansionListener { public void actionPerformed(ActionEvent ae) { if (!model.isReloading()) { // No longer loading. timer.stop(); if (reloadRow != -1) { generateChangeEvent(reloadRow); } reloadRow = -1; reloadPath = null; } else { // Still loading, see if paths changed. TreePath newPath = model.getPathLoading(); if (newPath == null) { // Hmm... Will usually indicate the reload thread // completed between time we asked if reloading. if (reloadRow != -1) { generateChangeEvent(reloadRow); } reloadRow = -1; reloadPath = null; } else { // Ok, valid path, see if matches last path. int newRow = treeTable.getTree().getRowForPath (newPath); if (newPath.equals(reloadPath)) { reloadCounter = (reloadCounter + 1) % 8; if (newRow != reloadRow) { int lastRow = reloadRow; reloadRow = newRow; generateChangeEvent(lastRow); } generateChangeEvent(reloadRow); } else { int lastRow = reloadRow; reloadCounter = 0; reloadRow = newRow; reloadPath = newPath; if (lastRow != reloadRow) { generateChangeEvent(lastRow); } generateChangeEvent(reloadRow); } } } updateStatusLabel(); } /** * Generates and update event for the specified row. FileSystemModel2 * could do this, but it would not know when the row has changed * as a result of expanding/collapsing nodes in the tree. */ protected void generateChangeEvent(int row) { if (row != -1) { AbstractTableModel tModel = (AbstractTableModel)treeTable. getModel(); tModel.fireTableChanged(new TableModelEvent (tModel, row, row, 1)); } } // // TreeExpansionListener // /** * Invoked when the tree has expanded. */ public void treeExpanded(TreeExpansionEvent te) { updateRow(); } /** * Invoked when the tree has collapsed. */ public void treeCollapsed(TreeExpansionEvent te) { updateRow(); } /** * Updates the reloadRow and path, this does not genernate a * change event. */ protected void updateRow() { reloadPath = model.getPathLoading(); if (reloadPath != null) { reloadRow = treeTable.getTree().getRowForPath(reloadPath); } } } /** * A renderer that will give an indicator when a cell is being reloaded. */ class IndicatorRenderer extends DefaultTableCellRenderer { /** Makes sure the number of displayed in an internationalized * manner. */ protected NumberFormat formatter; /** Row that is currently being painted. */ protected int lastRow; IndicatorRenderer() { setHorizontalAlignment(JLabel.RIGHT); formatter = NumberFormat.getInstance(); } /** * Invoked as part of DefaultTableCellRenderers implemention. Sets * the text of the label. */ public void setValue(Object value) { setText((value == null) ? "---" : formatter.format(value)); } /** * Returns this. */ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); lastRow = row; return this; } /** * If the row being painted is also being reloaded this will draw * a little indicator. */ public void paint(Graphics g) { if (lastRow == reloadRow) { int width = getWidth(); int height = getHeight(); g.setColor(getBackground()); g.fillRect(0, 0, width, height); g.setColor(getForeground()); int diameter = Math.min(width, height); if (reloadCounter < 5) { g.fillArc((width - diameter) / 2, (height - diameter) / 2, diameter, diameter, 90, -(reloadCounter * 90)); } else { g.fillArc((width - diameter) / 2, (height - diameter) / 2, diameter, diameter, 90, (4 - reloadCounter % 4) * 90); } } else { super.paint(g); } } } public static void main(String[] args) { if (args.length > 0) { for (int counter = args.length - 1; counter >= 0; counter--) { new TreeTableExample2(args[counter]); } } else { String path; try { path = System.getProperty("user.home"); if (path != null) { new TreeTableExample2(path); } } catch (SecurityException se) { path = null; } if (path == null) { System.out.println("Could not determine home directory"); } } } } freehep-swing-2.0.3/src/test/java/org/freehep/swing/treetable/test/MergeSort.java0000644012010301201030000000340510466735775031016 0ustar mascellanimascellanipackage org.freehep.swing.treetable.test; /** * An implementation of MergeSort, needs to be subclassed to compare the terms. * * @author Scott Violet */ public abstract class MergeSort extends Object { protected Object toSort[]; protected Object swapSpace[]; public void sort(Object array[]) { if(array != null && array.length > 1) { int maxLength; maxLength = array.length; swapSpace = new Object[maxLength]; toSort = array; this.mergeSort(0, maxLength - 1); swapSpace = null; toSort = null; } } public abstract int compareElementsAt(int beginLoc, int endLoc); protected void mergeSort(int begin, int end) { if(begin != end) { int mid; mid = (begin + end) / 2; this.mergeSort(begin, mid); this.mergeSort(mid + 1, end); this.merge(begin, mid, end); } } protected void merge(int begin, int middle, int end) { int firstHalf, secondHalf, count; firstHalf = count = begin; secondHalf = middle + 1; while((firstHalf <= middle) && (secondHalf <= end)) { if(this.compareElementsAt(secondHalf, firstHalf) < 0) swapSpace[count++] = toSort[secondHalf++]; else swapSpace[count++] = toSort[firstHalf++]; } if(firstHalf <= middle) { while(firstHalf <= middle) swapSpace[count++] = toSort[firstHalf++]; } else { while(secondHalf <= end) swapSpace[count++] = toSort[secondHalf++]; } for(count = begin;count <= end;count++) toSort[count] = swapSpace[count]; } } freehep-swing-2.0.3/src/test/java/org/freehep/swing/treetable/test/FileSystemModel2.java0000644012010301201030000004555610466735775032253 0ustar mascellanimascellanipackage org.freehep.swing.treetable.test; import java.io.File; import java.io.IOException; import java.util.Date; import java.util.Stack; import javax.swing.SwingUtilities; import javax.swing.tree.TreePath; import org.freehep.swing.treetable.AbstractTreeTableModel; import org.freehep.swing.treetable.TreeTableModel; /** * FileSystemModel2 is a TreeTableModel representing a hierarchical file * system.

* This will recursively load all the children from the path it is * created with. The loading is done with the method reloadChildren, and * happens in another thread. The method isReloading can be invoked to check * if there are active threads. The total size of all the files are also * accumulated. *

* By default links are not descended. java.io.File does not have a way * to distinguish links, so a file is assumed to be a link if its canonical * path does not start with its parent path. This may not cover all cases, * but works for the time being. *

Reloading happens such that all the files of the directory are * loaded and immediately available. The background thread then recursively * loads all the files of each of those directories. When each directory has * finished loading all its sub files they are attached and an event is * generated in the event dispatching thread. A more ambitious approach * would be to attach each set of directories as they are loaded and generate * an event. Then, once all the direct descendants of the directory being * reloaded have finished loading, it is resorted based on total size. *

* While you can invoke reloadChildren as many times as you want, care * should be taken in doing this. You should not invoke reloadChildren * on a node that is already being reloaded, or going to be reloaded * (meaning its parent is reloading but it hasn't started reloading * that directory yet). If this is done odd results may * happen. FileSystemModel2 does not enforce any policy in this manner, * and it is up to the user of FileSystemModel2 to ensure it doesn't * happen. * * @version 1.12 05/12/98 * @author Philip Milne * @author Scott Violet */ public class FileSystemModel2 extends AbstractTreeTableModel { // Names of the columns. static protected String[] cNames = {"Name", "Size", "Type", "Modified"}; // Types of the columns. static protected Class[] cTypes = { TreeTableModel.class, Integer.class, String.class, Date.class}; // The the returned file length for directories. public static final Integer ZERO = new Integer(0); /** An array of MergeSorter sorters, that will sort based on size. */ static Stack sorters = new Stack(); /** True if the receiver is valid, once set to false all Threads * loading files will stop. */ protected boolean isValid; /** Node currently being reloaded, this becomes somewhat muddy if * reloading is happening in multiple threads. */ protected FileNode reloadNode; /** > 0 indicates reloading some nodes. */ int reloadCount; /** Returns true if links are to be descended. */ protected boolean descendLinks; /** * Returns a MergeSort that can sort on the totalSize of a FileNode. */ protected static MergeSort getSizeSorter() { synchronized(sorters) { if (sorters.size() == 0) { return new SizeSorter(); } return (MergeSort)sorters.pop(); } } /** * Should be invoked when a MergeSort is no longer needed. */ protected static void recycleSorter(MergeSort sorter) { synchronized(sorters) { sorters.push(sorter); } } /** * Creates a FileSystemModel2 rooted at File.separator, which is usually * the root of the file system. This does not load it, you should invoke * reloadChildren with the root to start loading. */ public FileSystemModel2() { this(File.separator); } /** * Creates a FileSystemModel2 with the root being rootPath. * This does not load it, you should invoke * reloadChildren with the root to start loading. */ public FileSystemModel2(String rootPath) { super(null); isValid = true; root = new FileNode(new File(rootPath)); } // // The TreeModel interface // /** * Returns the number of children of node. */ public int getChildCount(Object node) { Object[] children = getChildren(node); return (children == null) ? 0 : children.length; } /** * Returns the child of node at index i. */ public Object getChild(Object node, int i) { return getChildren(node)[i]; } /** * Returns true if the passed in object represents a leaf, false * otherwise. */ public boolean isLeaf(Object node) { return ((FileNode)node).isLeaf(); } // // The TreeTableNode interface. // /** * Returns the number of columns. */ public int getColumnCount() { return cNames.length; } /** * Returns the name for a particular column. */ public String getColumnName(int column) { return cNames[column]; } /** * Returns the class for the particular column. */ public Class getColumnClass(int column) { return cTypes[column]; } /** * Returns the value of the particular column. */ public Object getValueAt(Object node, int column) { FileNode fn = (FileNode)node; try { switch(column) { case 0: return fn.getFile().getName(); case 1: if (fn.isTotalSizeValid()) { return new Integer((int)((FileNode)node).totalSize()); } return null; case 2: return fn.isLeaf() ? "File" : "Directory"; case 3: return fn.lastModified(); } } catch (SecurityException se) { } return null; } // // Some convenience methods. // /** * Reloads the children of the specified node. */ public void reloadChildren(Object node) { FileNode fn = (FileNode)node; synchronized(this) { reloadCount++; } fn.resetSize(); new Thread(new FileNodeLoader((FileNode)node)).start(); } /** * Stops and waits for all threads to finish loading. */ public void stopLoading() { isValid = false; synchronized(this) { while (reloadCount > 0) { try { wait(); } catch (InterruptedException ie) {} } } isValid = true; } /** * If newValue is true, links are descended. Odd results * may happen if you set this while other threads are loading. */ public void setDescendsLinks(boolean newValue) { descendLinks = newValue; } /** * Returns true if links are to be automatically descended. */ public boolean getDescendsLinks() { return descendLinks; } /** * Returns the path node represents. */ public String getPath(Object node) { return ((FileNode)node).getFile().getPath(); } /** * Returns the total size of the receiver. */ public long getTotalSize(Object node) { return ((FileNode)node).totalSize(); } /** * Returns true if the receiver is loading any children. */ public boolean isReloading() { return (reloadCount > 0); } /** * Returns the path to the node that is being loaded. */ public TreePath getPathLoading() { FileNode rn = reloadNode; if (rn != null) { return new TreePath(rn.getPath()); } return null; } /** * Returns the node being loaded. */ public Object getNodeLoading() { return reloadNode; } protected File getFile(Object node) { FileNode fileNode = ((FileNode)node); return fileNode.getFile(); } protected Object[] getChildren(Object node) { FileNode fileNode = ((FileNode)node); return fileNode.getChildren(); } protected static FileNode[] EMPTY_CHILDREN = new FileNode[0]; // Used to sort the file names. static private MergeSort fileMS = new MergeSort() { public int compareElementsAt(int beginLoc, int endLoc) { return ((String)toSort[beginLoc]).compareTo ((String)toSort[endLoc]); } }; /** * A FileNode is a derivative of the File class - though we delegate to * the File object rather than subclassing it. It is used to maintain a * cache of a directory's children and therefore avoid repeated access * to the underlying file system during rendering. */ class FileNode { /** java.io.File the receiver represents. */ protected File file; /** Parent FileNode of the receiver. */ private FileNode parent; /** Children of the receiver. */ protected FileNode[] children; /** Size of the receiver and all its children. */ protected long totalSize; /** Valid if the totalSize has finished being calced. */ protected boolean totalSizeValid; /** Path of the receiver. */ protected String canonicalPath; /** True if the canonicalPath of this instance does not start with * the canonical path of the parent. */ protected boolean isLink; /** Date last modified. */ protected Date lastModified; protected FileNode(File file) { this(null, file); } protected FileNode(FileNode parent, File file) { this.parent = parent; this.file = file; try { canonicalPath = file.getCanonicalPath(); } catch (IOException ioe) { canonicalPath = ""; } if (parent != null) { isLink = !canonicalPath.startsWith(parent.getCanonicalPath()); } else { isLink = false; } if (isLeaf()) { totalSize = file.length(); totalSizeValid = true; } } /** * Returns the date the receiver was last modified. */ public Date lastModified() { if (lastModified == null && file != null) { lastModified = new Date(file.lastModified()); } return lastModified; } /** * Returns the the string to be used to display this leaf in the JTree. */ public String toString() { return file.getName(); } /** * Returns the java.io.File the receiver represents. */ public File getFile() { return file; } /** * Returns size of the receiver and all its children. */ public long totalSize() { return totalSize; } /** * Returns the parent of the receiver. */ public FileNode getParent() { return parent; } /** * Returns true if the receiver represents a leaf, that is it is * isn't a directory. */ public boolean isLeaf() { return file.isFile(); } /** * Returns true if the total size is valid. */ public boolean isTotalSizeValid() { return totalSizeValid; } /** * Clears the date. */ protected void resetLastModified() { lastModified = null; } /** * Sets the size of the receiver to be 0. */ protected void resetSize() { alterTotalSize(-totalSize); } /** * Loads the children, caching the results in the children * instance variable. */ protected FileNode[] getChildren() { return children; } /** * Recursively loads all the children of the receiver. */ protected void loadChildren(MergeSort sorter) { totalSize = file.length(); children = createChildren(null); for (int counter = children.length - 1; counter >= 0; counter--) { Thread.yield(); // Give the GUI CPU time to draw itself. if (!children[counter].isLeaf() && (descendLinks || !children[counter].isLink())) { children[counter].loadChildren(sorter); } totalSize += children[counter].totalSize(); if (!isValid) { counter = 0; } } if (isValid) { if (sorter != null) { sorter.sort(children); } totalSizeValid = true; } } /** * Loads the children of of the receiver. */ protected FileNode[] createChildren(MergeSort sorter) { FileNode[] retArray = null; try { String[] files = file.list(); if(files != null) { if (sorter != null) { sorter.sort(files); } retArray = new FileNode[files.length]; String path = file.getPath(); for(int i = 0; i < files.length; i++) { File childFile = new File(path, files[i]); retArray[i] = new FileNode(this, childFile); } } } catch (SecurityException se) {} if (retArray == null) { retArray = EMPTY_CHILDREN; } return retArray; } /** * Returns true if the children have been loaded. */ protected boolean loadedChildren() { return (file.isFile() || (children != null)); } /** * Gets the path from the root to the receiver. */ public FileNode[] getPath() { return getPathToRoot(this, 0); } /** * Returns the canonical path for the receiver. */ public String getCanonicalPath() { return canonicalPath; } /** * Returns true if the receiver's path does not begin with the * parent's canonical path. */ public boolean isLink() { return isLink; } protected FileNode[] getPathToRoot(FileNode aNode, int depth) { FileNode[] retNodes; if(aNode == null) { if(depth == 0) return null; else retNodes = new FileNode[depth]; } else { depth++; retNodes = getPathToRoot(aNode.getParent(), depth); retNodes[retNodes.length - depth] = aNode; } return retNodes; } /** * Sets the children of the receiver, updates the total size, * and if generateEvent is true a tree structure changed event * is created. */ protected void setChildren(FileNode[] newChildren, boolean generateEvent) { long oldSize = totalSize; totalSize = file.length(); children = newChildren; for (int counter = children.length - 1; counter >= 0; counter--) { totalSize += children[counter].totalSize(); } if (generateEvent) { TreePath path = new TreePath(getPath()); fireTreeStructureChanged(FileSystemModel2.this, path, null, null); FileNode parent = getParent(); if (parent != null) { parent.alterTotalSize(totalSize - oldSize); } } } protected synchronized void alterTotalSize(long sizeDelta) { if (sizeDelta != 0 && (parent = getParent()) != null) { totalSize += sizeDelta; nodeChanged(); parent.alterTotalSize(sizeDelta); } else { // Need a way to specify the root. totalSize += sizeDelta; } } /** * This should only be invoked on the event dispatching thread. */ protected synchronized void setTotalSizeValid(boolean newValue) { if (totalSizeValid != newValue) { nodeChanged(); totalSizeValid = newValue; FileNode parent = getParent(); if (parent != null) { parent.childTotalSizeChanged(this); } } } /** * Marks the receivers total size as valid, but does not invoke * node changed, nor message the parent. */ protected synchronized void forceTotalSizeValid() { totalSizeValid = true; } /** * Invoked when a childs total size has changed. */ protected synchronized void childTotalSizeChanged(FileNode child) { if (totalSizeValid != child.isTotalSizeValid()) { if (totalSizeValid) { setTotalSizeValid(false); } else { FileNode[] children = getChildren(); for (int counter = children.length - 1; counter >= 0; counter--) { if (!children[counter].isTotalSizeValid()) { return; } } setTotalSizeValid(true); } } } /** * Can be invoked when a node has changed, will create the * appropriate event. */ protected void nodeChanged() { FileNode parent = getParent(); if (parent != null) { TreePath path = new TreePath(parent.getPath()); int[] index = { getIndexOfChild(parent, this) }; Object[] children = { this }; fireTreeNodesChanged(FileSystemModel2.this, path, index, children); } } } /** * FileNodeLoader can be used to reload all the children of a * particular node. It first resets the children of the FileNode * it is created with, and in its run method will reload all of * that nodes children. FileNodeLoader may not be running in the event * dispatching thread. As swing is not thread safe it is important * that we don't generate events in this thread. SwingUtilities.invokeLater * is used so that events are generated in the event dispatching thread. */ class FileNodeLoader implements Runnable { /** Node creating children for. */ FileNode node; /** Sorter. */ MergeSort sizeMS; FileNodeLoader(FileNode node) { this.node = node; node.resetLastModified(); node.setChildren(node.createChildren(fileMS), true); node.setTotalSizeValid(false); } public void run() { FileNode[] children = node.getChildren(); sizeMS = getSizeSorter(); for (int counter = children.length - 1; counter >= 0; counter--) { if (!children[counter].isLeaf()) { reloadNode = children[counter]; loadChildren(children[counter]); reloadNode = null; } if (!isValid) { counter = 0; } } recycleSorter(sizeMS); if (isValid) { SwingUtilities.invokeLater(new Runnable() { public void run() { MergeSort sorter = getSizeSorter(); sorter.sort(node.getChildren()); recycleSorter(sorter); node.setChildren(node.getChildren(), true); synchronized(FileSystemModel2.this) { reloadCount--; FileSystemModel2.this.notifyAll(); } } }); } else { synchronized(FileSystemModel2.this) { reloadCount--; FileSystemModel2.this.notifyAll(); } } } protected void loadChildren(FileNode node) { if (!node.isLeaf() && (descendLinks || !node.isLink())) { final FileNode[] children = node.createChildren(null); for (int counter = children.length - 1; counter >= 0; counter--) { if (!children[counter].isLeaf()) { if (descendLinks || !children[counter].isLink()) { children[counter].loadChildren(sizeMS); } else { children[counter].forceTotalSizeValid(); } } if (!isValid) { counter = 0; } } if (isValid) { final FileNode fn = node; // Reset the children SwingUtilities.invokeLater(new Runnable() { public void run() { MergeSort sorter = getSizeSorter(); sorter.sort(children); recycleSorter(sorter); fn.setChildren(children, true); fn.setTotalSizeValid(true); fn.nodeChanged(); } }); } } else { node.forceTotalSizeValid(); } } } /** * Sorts the contents, which must be instances of FileNode based on * totalSize. */ static class SizeSorter extends MergeSort { public int compareElementsAt(int beginLoc, int endLoc) { long firstSize = ((FileNode)toSort[beginLoc]).totalSize(); long secondSize = ((FileNode)toSort[endLoc]).totalSize(); if (firstSize != secondSize) { return (int)(secondSize - firstSize); } return ((FileNode)toSort[beginLoc]).toString().compareTo (((FileNode)toSort[endLoc]).toString()); } } } freehep-swing-2.0.3/src/test/java/org/freehep/swing/graphics/0000755012010301201030000000000011275634131025073 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/java/org/freehep/swing/graphics/test/0000755012010301201030000000000011275634131026052 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/java/org/freehep/swing/graphics/test/TestGraphicalSelections.java0000644012010301201030000004136310466735775033530 0ustar mascellanimascellanipackage org.freehep.swing.graphics.test; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Polygon; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLayeredPane; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.WindowConstants; import org.freehep.swing.graphics.GraphicalSelectionEvent; import org.freehep.swing.graphics.GraphicalSelectionListener; import org.freehep.swing.graphics.ParallelogramSelectionPanel; import org.freehep.swing.graphics.PointSelectionEvent; import org.freehep.swing.graphics.PointSelectionPanel; import org.freehep.swing.graphics.RectangularSelectionPanel; import org.freehep.swing.graphics.RegionSelectionEvent; import org.freehep.swing.graphics.RotatedRectangleSelectionPanel; import org.freehep.swing.graphics.SquareSelectionPanel; import org.freehep.swing.graphics.XSkewSelectionPanel; import org.freehep.swing.graphics.XSliceSelectionPanel; import org.freehep.swing.graphics.YSkewSelectionPanel; import org.freehep.swing.graphics.YSliceSelectionPanel; import org.freehep.swing.layout.StackedLayout; public class TestGraphicalSelections extends JFrame { JLayeredPane mainPanel; TestPanel drawPanel; PointSelectionPanel pointSelect; RectangularSelectionPanel rectSelect; SquareSelectionPanel squareSelect; RotatedRectangleSelectionPanel rotateSelect; XSkewSelectionPanel xskewSelect; YSkewSelectionPanel yskewSelect; XSliceSelectionPanel xsliceSelect; YSliceSelectionPanel ysliceSelect; ParallelogramSelectionPanel parallelogramSelect; public TestGraphicalSelections() { // Title this frame. super("Graphical Selections Test"); // Make this exit when the close button is clicked. setDefaultCloseOperation(WindowConstants. DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) {quit();} }); // Make the main panel container. mainPanel = new JLayeredPane(); mainPanel.setLayout(new StackedLayout()); // Make the drawing panel. drawPanel = new TestPanel(); mainPanel.add(drawPanel, new Integer(0)); drawPanel.setPreferredSize(new Dimension(600,400)); // Make the selection panels. pointSelect = new PointSelectionPanel(); mainPanel.add(pointSelect, new Integer(10)); pointSelect.addGraphicalSelectionListener(drawPanel); rectSelect = new RectangularSelectionPanel(); mainPanel.add(rectSelect, new Integer(20)); rectSelect.addGraphicalSelectionListener(drawPanel); squareSelect = new SquareSelectionPanel(); mainPanel.add(squareSelect, new Integer(30)); squareSelect.addGraphicalSelectionListener(drawPanel); rotateSelect = new RotatedRectangleSelectionPanel(); mainPanel.add(rotateSelect, new Integer(40)); rotateSelect.addGraphicalSelectionListener(drawPanel); xskewSelect = new XSkewSelectionPanel(); mainPanel.add(xskewSelect, new Integer(50)); xskewSelect.addGraphicalSelectionListener(drawPanel); yskewSelect = new YSkewSelectionPanel(); mainPanel.add(yskewSelect, new Integer(60)); yskewSelect.addGraphicalSelectionListener(drawPanel); xsliceSelect = new XSliceSelectionPanel(); mainPanel.add(xsliceSelect, new Integer(70)); xsliceSelect.addGraphicalSelectionListener(drawPanel); ysliceSelect = new YSliceSelectionPanel(); mainPanel.add(ysliceSelect, new Integer(80)); ysliceSelect.addGraphicalSelectionListener(drawPanel); parallelogramSelect = new ParallelogramSelectionPanel(); mainPanel.add(parallelogramSelect, new Integer(70)); parallelogramSelect.addGraphicalSelectionListener(drawPanel); // Make a menu bar and menu. JMenuBar menuBar = new JMenuBar(); JMenu menu = new JMenu("File"); menuBar.add(menu); // Quit menu item. JMenuItem item = new JMenuItem("Quit"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { quit(); }}); menu.add(item); // Add the various types of selections. menu = new JMenu("Selections"); menuBar.add(menu); item = new JMenuItem("Point Select"); menu.add(item); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { activePanel(pointSelect); }}); item = new JMenuItem("Rectangular Selection"); menu.add(item); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { activePanel(rectSelect); }}); item = new JMenuItem("Square Selection"); menu.add(item); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { activePanel(squareSelect); }}); item = new JMenuItem("Rot. Rectangle Selection"); menu.add(item); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { activePanel(rotateSelect); }}); item = new JMenuItem("X-Skew Selection"); menu.add(item); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { activePanel(xskewSelect); }}); item = new JMenuItem("Y-Skew Selection"); menu.add(item); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { activePanel(yskewSelect); }}); item = new JMenuItem("X-Slice Selection"); menu.add(item); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { activePanel(xsliceSelect); }}); item = new JMenuItem("Y-Slice Selection"); menu.add(item); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { activePanel(ysliceSelect); }}); item = new JMenuItem("Parallelogram Selection"); menu.add(item); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { activePanel(parallelogramSelect); }}); // Choose what to check. menu = new JMenu("Options"); menuBar.add(menu); // Reduce the size. item = new JMenuItem("Check Selection"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { drawPanel.checkSelection(); }}); menu.add(item); item = new JMenuItem("Check Transform Of Graphics"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { drawPanel.checkTransform(); }}); menu.add(item); item = new JMenuItem("Check Transform Of Shapes"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { drawPanel.checkTransformShapes(); }}); menu.add(item); menu.addSeparator(); item = new JMenuItem("Restore Default Zoom"); menu.add(item); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { drawPanel.defaultTransform(); }}); // Add this to the frame. setJMenuBar(menuBar); // Get the content pane. Container content = this.getContentPane(); content.setLayout(new BorderLayout()); content.add(mainPanel,BorderLayout.CENTER); //setContentPane(mainPanel); activePanel(squareSelect); } /** * Just exit the JVM. */ public void quit() { System.exit(0); } public void activePanel(JComponent active) { pointSelect.setVisible(false); rectSelect.setVisible(false); squareSelect.setVisible(false); rotateSelect.setVisible(false); xskewSelect.setVisible(false); yskewSelect.setVisible(false); xsliceSelect.setVisible(false); ysliceSelect.setVisible(false); parallelogramSelect.setVisible(false); active.setVisible(true); } class TestPanel extends JPanel implements GraphicalSelectionListener { /** * Flag to indicate whether the transform or the selection * component of the GraphicalSelectionEvent should be * tested. */ private boolean checkTransform; /** * Flag indicating whether to transform the shapes or to set * the transformation of the Graphics context. */ private boolean transformShapes; /** * The transform which should be used for the zooming. */ private AffineTransform transform = new AffineTransform(); /** * The outline of the selection. For a point, create a small * diamond surrounding the selected point. */ private Polygon polygon = null; /** * List of colors for the six test figures which are drawn. */ private Color[] colors = new Color[6]; /** * The six test figures. */ Polygon[] bkg = new Polygon[6]; /** * Temporary array used to create the test * polygons. (x-coord.) */ int[] xval = new int[4]; /** * Temporary array used to create the test * polygons. (y-coord.) */ int[] yval = new int[4]; /** * GeneralPath used when transforming the shapes directly. */ GeneralPath gp = new GeneralPath(); /** * Constructor sets up the various geometrical shapes needed * for this test. */ public TestPanel() { // Make sure that this component is opaque. setOpaque(true); // Start by checking the selections only. checkTransform = false; // Start by transforming the shapes. transformShapes = true; // Setup the colors for the six geometrical shapes. colors[0] = Color.red; colors[1] = Color.green; colors[2] = Color.blue; colors[3] = Color.cyan; colors[4] = Color.magenta; colors[5] = Color.black; // A square. xval[0] = 50; yval[0] = 50; xval[1] = 150; yval[1] = 50; xval[2] = 150; yval[2] = 150; xval[3] = 50; yval[3] = 150; bkg[0] = new Polygon(xval,yval,4); // A rectangle. xval[0] = 200+50; yval[0] = 20; xval[1] = 200+150; yval[1] = 20; xval[2] = 200+150; yval[2] = 180; xval[3] = 200+50; yval[3] = 180; bkg[1] = new Polygon(xval,yval,4); // A diamond. xval[0] = 400+100; yval[0] = 50; xval[1] = 400+180; yval[1] = 100; xval[2] = 400+100; yval[2] = 150; xval[3] = 400+20; yval[3] = 100; bkg[2] = new Polygon(xval,yval,4); // A y-skew parallelogram. xval[0] = 20; yval[0] = 200+20; xval[1] = 70; yval[1] = 200+20; xval[2] = 180; yval[2] = 200+180; xval[3] = 130; yval[3] = 200+180; bkg[3] = new Polygon(xval,yval,4); // An x-skew parallelogram. xval[0] = 200+20; yval[0] = 200+20; xval[1] = 200+20; yval[1] = 200+70; xval[2] = 200+180; yval[2] = 200+180; xval[3] = 200+180; yval[3] = 200+130; bkg[4] = new Polygon(xval,yval,4); // A rotated rectangle. xval[0] = 400+160; yval[0] = 200+20; xval[1] = 400+180; yval[1] = 200+40; xval[2] = 400+40; yval[2] = 200+180; xval[3] = 400+20; yval[3] = 200+160; bkg[5] = new Polygon(xval,yval,4); } /** * Paint the component. */ public void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D) g.create(); // Always draw the background on an untransformed graphics // context. g2d.setColor(Color.orange); g2d.fillRect(0,0,getWidth(),getHeight()); // Now draw the shapes on top. if (transformShapes) { drawTransformedShapes(g2d); } else { drawTransformedGraphics(g2d); } } public void drawTransformedShapes(Graphics2D g2d) { if (!(checkTransform && transform!=null)) { transform = new AffineTransform(); } // Draw all of the standard shapes. for (int i=0; i<6; i++) { gp.reset(); gp.append(bkg[i].getPathIterator(transform),false); g2d.setColor(colors[i]); g2d.fill(gp); } if (polygon!=null && !checkTransform) { gp.reset(); gp.append(polygon.getPathIterator(transform),false); g2d.setColor(Color.black); g2d.draw(gp); } } public void drawTransformedGraphics(Graphics2D g2d) { if (checkTransform && transform!=null) { g2d.transform(transform); } else { transform = new AffineTransform(); } // Draw all of the standard shapes. for (int i=0; i<6; i++) { g2d.setColor(colors[i]); g2d.fillPolygon(bkg[i]); } if (polygon!=null && !checkTransform) { g2d.setColor(Color.black); g2d.drawPolygon(polygon); } } public void checkTransformShapes() { transformShapes = true; checkTransform = true; transform = new AffineTransform(); polygon = null; repaint(); } public void checkTransform() { transformShapes = false; checkTransform = true; transform = new AffineTransform(); polygon = null; repaint(); } public void checkSelection() { transformShapes = true; checkTransform = false; polygon = null; transform = new AffineTransform(); repaint(); } public void defaultTransform() { transform = new AffineTransform(); repaint(); } public void graphicalSelectionMade(GraphicalSelectionEvent gsEvent) { AffineTransform tx = gsEvent.getTransform(); if (transform!=null && tx!=null) { transform.preConcatenate(tx); } else { transform = tx; } if (gsEvent instanceof RegionSelectionEvent) { polygon = (Polygon) gsEvent.getSelection(); } else if (gsEvent instanceof PointSelectionEvent) { Point p = (Point) gsEvent.getSelection(); xval[0] = p.x; yval[0] = p.y+10; xval[1] = p.x+10; yval[1] = p.y; xval[2] = p.x; yval[2] = p.y-10; xval[3] = p.x-10; yval[3] = p.y; polygon = new Polygon(xval,yval,4); } repaint(); } } public static void main(String[] args) { // Create a new instance of this class. TestGraphicalSelections test = new TestGraphicalSelections(); // Layout the component and make it visible. test.pack(); test.setVisible(true); test.setLocation(20,20); test.pack(); } } freehep-swing-2.0.3/src/test/java/org/freehep/swing/graphics/test/package.html0000644012010301201030000000005010470537377030340 0ustar mascellanimascellani Tests for swing graphics. freehep-swing-2.0.3/src/test/java/org/freehep/swing/table/0000755012010301201030000000000011275634131024362 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/java/org/freehep/swing/table/test/0000755012010301201030000000000011275634131025341 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/java/org/freehep/swing/table/test/DefaultSortableTableModelTest.java0000644012010301201030000002237210466735775034104 0ustar mascellanimascellanipackage org.freehep.swing.table.test; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Random; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableModel; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.freehep.swing.table.DefaultSortableTableModel; import org.freehep.swing.table.SortableTableModel; import org.freehep.swing.table.TableColumnSelector; /** * * @author Tony Johnson * @version $Id: DefaultSortableTableModelTest.java 8584 2006-08-10 23:06:37Z duns $ */ public class DefaultSortableTableModelTest extends TestCase { public DefaultSortableTableModelTest(java.lang.String testName) { super(testName); } public static Test suite() { TestSuite suite = new TestSuite(DefaultSortableTableModelTest.class); return suite; } public void testBasic() { TestModel test = new TestModel(100); test.testInvariants(test); DefaultSortableTableModel model = new DefaultSortableTableModel(test); test.testInvariants(model); TestListener l = new TestListener(); model.addTableModelListener(l); TableModelEvent expected = new TableModelEvent(model,0,model.getRowCount()-1,TableModelEvent.ALL_COLUMNS,TableModelEvent.UPDATE); model.sort(0,true); test.testInvariants(model); test.testSortOrder(model,0,true); test.testSortOrder(model,1,true); l.testEvent(1,expected); model.sort(0,true); test.testInvariants(model); test.testSortOrder(model,0,true); test.testSortOrder(model,1,true); l.testEvent(0,null); model.sort(0,false); test.testInvariants(model); test.testSortOrder(model,0,false); test.testSortOrder(model,1,false); l.testEvent(1,expected); model.sort(1,false); test.testInvariants(model); test.testSortOrder(model,1,false); test.testSortOrder(model,0,false); l.testEvent(1,expected); model.sort(1,true); test.testInvariants(model); test.testSortOrder(model,1,true); test.testSortOrder(model,0,true); l.testEvent(1,expected); model.sort(2,true); test.testInvariants(model); test.testSortOrder(model,2,true); l.testEvent(1,expected); model.sort(SortableTableModel.UNSORTED,true); test.testInvariants(model); test.testEquals(model); l.testEvent(1,expected); model.sort(SortableTableModel.UNSORTED,true); test.testInvariants(model); test.testEquals(model); l.testEvent(0,null); } public void testColumns() { TestModel test = new TestModel(100); test.testInvariants(test); TableColumnSelector selector = new TableColumnSelector(test); TableModel columns = selector.getFilteredTableModel(); test.testInvariants(columns); DefaultSortableTableModel model = new DefaultSortableTableModel(columns); test.testInvariants(model); TestListener l = new TestListener(); model.addTableModelListener(l); model.sort(2,false); test.testInvariants(model); test.testSortOrder(model,2,false); selector.setHideColumn(1,true); test.testSortOrder(model,1,false); selector.setHideColumn(1,false); test.testSortOrder(model,2,false); selector.setHideColumn(2,true); assertEquals(model.getColumnCount(),test.getColumnCount()-1); selector.setHideColumn(2,false); test.testInvariants(model); model.sort(2,false); test.testInvariants(model); test.testSortOrder(model,2,false); model.sort(0,true); test.testInvariants(model); test.testSortOrder(model,0,true); selector.setHideColumn(0,true); model.sort(0,true); test.testSortOrder(model,0,true); selector.setHideColumn(0,false); test.testInvariants(model); test.testSortOrder(model,0,true); test.testSortOrder(model,1,true); } public void testAdvanced() { TestModel test = new TestModel(100); test.testInvariants(test); DefaultSortableTableModel model = new DefaultSortableTableModel(test); test.testInvariants(model); TestListener l = new TestListener(); model.addTableModelListener(l); TableModelEvent expected = new TableModelEvent(model,0,model.getRowCount()-1,TableModelEvent.ALL_COLUMNS,TableModelEvent.UPDATE); model.sort(0,true); test.testInvariants(model); test.testSortOrder(model,0,true); l.testEvent(1,expected); Random random = new Random(); for (int j=0; j<100; j++) { int source = random.nextInt(test.getRowCount()); int dest = random.nextInt(test.getRowCount()); int n = test.getColumnCount(); Object[] row = new Object[n]; for (int i=0; i= 0); prev = next; } } void testEquals(TableModel in) { assertEquals(in.getRowCount(), getRowCount()); assertEquals(in.getColumnCount(), getColumnCount()); for (int i=0; i pid2) { i1.add(process2); fireTableRowsInserted(row,row); row++; advance1 = false; advance2 = true; } } } public int getColumnCount() { return headers.length; } public Class getColumnClass(int col) { return types[col]; } public String getColumnName(int col) { return headers[col]; } public int getRowCount() { return processes.size(); } public Object getValueAt(int row, int col) { Process process = (Process) processes.get(row); switch (col) { case 0: return new Integer(process.pid); case 1: return process.exe; case 2: return process.state; case 3: return new Integer(process.dutime); case 4: return new Integer(process.dstime); case 5: return new Integer(process.prio); default: return null; } } } } freehep-swing-2.0.3/src/test/java/org/freehep/swing/table/test/DirectoryList.java0000644012010301201030000001302710630324340030777 0ustar mascellanimascellanipackage org.freehep.swing.table.test; import java.io.File; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.ListIterator; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.table.AbstractTableModel; import junit.framework.TestCase; import org.freehep.swing.popup.PopupListener; import org.freehep.swing.table.DefaultSortableTableModel; import org.freehep.swing.table.TableColumnPacker; import org.freehep.swing.table.TableColumnSelector; import org.freehep.swing.table.TableSorter; /** * A Test routine for the Table Column Packer. * * @author Mark Donszelmann * @version $Id: DirectoryList.java 10766 2007-06-02 17:29:04Z tonyj $ */ public class DirectoryList extends TestCase { private static JTable table; private static File dir = new File("."); private static List files() { File[] list = dir.listFiles(); return Arrays.asList(list); } public void testMain() { DirectoryList.main(null); } public static void main(String[] args) { List dir = files(); final DirectoryTableModel model = new DirectoryTableModel(dir); TableColumnSelector selector = new TableColumnSelector(model); DefaultSortableTableModel sm = new DefaultSortableTableModel(selector.getFilteredTableModel()); final TableColumnPacker packer = new TableColumnPacker(); packer.setHeaderMargin(15); table = new JTable(sm) { public void setBounds(int x, int y, int w, int h) { super.setBounds(x, y, w, h); packer.packColumns(table); } }; table.addMouseListener(new PopupListener(selector.createPopupMenu())); new TableSorter(table); JFrame frame = new JFrame("Directory List"); frame.setContentPane(new JScrollPane(table)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); // Main thread continues in background to update display //Thread.currentThread().setDaemon(true); while (true) { try { Thread.sleep(1000); final List list = files(); Runnable r = new Runnable() { public void run() { model.update(list); } }; SwingUtilities.invokeAndWait(r); } catch (Exception x) { x.printStackTrace(); } } } private static class DirectoryTableModel extends AbstractTableModel { private List files; private String[] headers = { "name", "size", "dir", "r/o", "hidden", "modified", "path" }; private Class[] types = { String.class, Long.class, Boolean.class, Boolean.class , Boolean.class, Date.class, String.class }; DirectoryTableModel(List files) { this.files = files; } void update(List newFiles) { ListIterator i1 = files.listIterator(); ListIterator i2 = newFiles.listIterator(); int row = 0; File file1 = null; File file2 = null; boolean advance1 = true; boolean advance2 = true; while (true) { if (advance1) { if (i1.hasNext()) { file1 = (File) i1.next(); } else file1 = null; } if (advance2) { if (i2.hasNext()) { file2 = (File) i2.next(); } else file2 = null; } if ((file1 == null) && (file2 == null)) break; int c = file1.getName().compareTo(file2.getName()); if (c < 0) { i1.remove(); fireTableRowsDeleted(row,row); advance1 = true; advance2 = false; } else if (c == 0) { if (!file1.equals(file2)) { i1.set(file2); fireTableRowsUpdated(row,row); } row++; advance1 = advance2 = true; } else if (c > 0) { i1.add(file2); fireTableRowsInserted(row,row); row++; advance1 = false; advance2 = true; } } } public int getColumnCount() { return headers.length; } public Class getColumnClass(int col) { return types[col]; } public String getColumnName(int col) { return headers[col]; } public int getRowCount() { return files.size(); } public Object getValueAt(int row, int col) { File file = (File) files.get(row); switch (col) { case 0: return file.getName(); case 1: return new Long(file.length()); case 2: return new Boolean(file.isDirectory()); case 3: return new Boolean(!file.canWrite()); case 4: return new Boolean(file.isHidden()); case 5: return new Date(file.lastModified()); case 6: return file.getAbsolutePath(); default: return "N/A"; } } } } freehep-swing-2.0.3/src/test/java/org/freehep/swing/table/test/TableTestSuite.java0000644012010301201030000000134710466735775031133 0ustar mascellanimascellanipackage org.freehep.swing.table.test; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * * @author Tony Johnson * @version $Id: TableTestSuite.java 8584 2006-08-10 23:06:37Z duns $ * */ public class TableTestSuite extends TestCase { private TestSuite suite; public TableTestSuite(java.lang.String testName) { super(testName); suite = (TestSuite) suite(); } public TestSuite getSuite() { return suite; } public static Test suite() { TestSuite suite = new TestSuite(); // Add all the test suites here suite.addTestSuite( DefaultSortableTableModelTest.class ); return suite; } } freehep-swing-2.0.3/src/test/java/org/freehep/swing/images/0000755012010301201030000000000011275634131024540 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/java/org/freehep/swing/images/test/0000755012010301201030000000000011275634131025517 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/java/org/freehep/swing/images/test/ImageTest.java0000644012010301201030000000602410466735775030267 0ustar mascellanimascellanipackage org.freehep.swing.images.test; import java.awt.BorderLayout; import java.awt.Container; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JPanel; import javax.swing.JToolBar; import org.freehep.swing.images.FreeHepImage; public class ImageTest extends JFrame { String cursors[] = { "ParallelogramCursor", "PointCursor", "RectangularCursor", "RotatedRectangleCursor", "SquareCursor", "XSkewCursor", "YSkewCursor", "RotationCursor", "NotFoundCursor" }; String selections[] = { "Parallelogram", "Point", "Rectangular", "RotatedRectangle", "Square", "XSkew", "YSkew", "Rotation", "NotFound" }; public ImageTest() { super("Image, Cursor and Icon Test"); Container content = getContentPane(); content.setLayout(new BorderLayout()); // create button panel JPanel buttonPanel = new JPanel(); content.add(buttonPanel, "Center"); buttonPanel.setLayout(new GridLayout(4,2)); for (int i=0; i Tests for the swing images. freehep-swing-2.0.3/src/test/java/org/freehep/swing/test/0000755012010301201030000000000011275634131024252 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/java/org/freehep/swing/test/JTriStateTest.java0000644012010301201030000000350010466735775027645 0ustar mascellanimascellani// Copyright 2000, CERN, Geneva, Switzerland. package org.freehep.swing.test; import java.awt.GridLayout; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JCheckBox; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JPanel; import org.freehep.swing.JTriStateBox; import org.freehep.swing.JTriStateMenuItem; /** * @author Mark Donszelmann * @version $Id: JTriStateTest.java 8584 2006-08-10 23:06:37Z duns $ */ public class JTriStateTest extends TestFrame { Icon icon; protected void addToMenuBar(JMenuBar menuBar) { icon = new ImageIcon(getClass().getResource("Stop.gif")); JMenu m1 = new JMenu("CheckBoxes"); menuBar.add(m1); m1.add(new JCheckBoxMenuItem("CheckBox1", true)); m1.add(new JCheckBoxMenuItem("CheckBox2", false)); m1.add(new JCheckBoxMenuItem("CheckBox3")); m1.add(new JCheckBoxMenuItem("CheckBox4", icon, false)); JMenu m2 = new JMenu("TriStateBoxes"); menuBar.add(m2); m2.add(new JTriStateMenuItem("TriStateBox1", 1)); m2.add(new JTriStateMenuItem("TriStateBox2", 0)); m2.add(new JTriStateMenuItem("TriStateBox3", -1)); m2.add(new JTriStateMenuItem("TriStateBox4", icon)); } protected JComponent createComponent() { JPanel p = new JPanel(); p.setLayout(new GridLayout(4,2)); p.add(new JCheckBox("CheckBox1", true)); p.add(new JTriStateBox("TriStateBox1", 1)); p.add(new JCheckBox("CheckBox2", false)); p.add(new JTriStateBox("TriStateBox2", 0)); p.add(new JCheckBox("CheckBox3")); p.add(new JTriStateBox("TriStateBox3", -1)); p.add(new JCheckBox("CheckBox4", icon, false)); p.add(new JTriStateBox("TriStateBox4", icon)); return p; } public static void main(String[] argv) { new JTriStateTest(); } } freehep-swing-2.0.3/src/test/java/org/freehep/swing/test/JDirectoryChooserTest.java0000644012010301201030000000242310466735775031400 0ustar mascellanimascellanipackage org.freehep.swing.test; import java.awt.event.ActionEvent; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JPanel; import org.freehep.swing.JDirectoryChooser; public class JDirectoryChooserTest extends TestFrame { protected JComponent createComponent() { JPanel p = new JPanel(); final JDirectoryChooser chooser = new JDirectoryChooser(); JButton browse = new JButton("Browse...") { public void fireActionPerformed(ActionEvent e) { chooser.showDialog(this); } }; p.add(browse); JCheckBox dirOnly = new JCheckBox("Directories Only") { public void fireActionPerformed(ActionEvent e) { chooser.setFileSelectionMode(isSelected() ? JDirectoryChooser.DIRECTORIES_ONLY : JDirectoryChooser.FILES_AND_DIRECTORIES); } }; dirOnly.setSelected(chooser.getFileSelectionMode() == JDirectoryChooser.DIRECTORIES_ONLY); p.add(dirOnly); JCheckBox multi = new JCheckBox("Multiple Selection") { public void fireActionPerformed(ActionEvent e) { chooser.setMultiSelectionEnabled(isSelected()); } }; multi.setSelected(chooser.isMultiSelectionEnabled()); p.add(multi); return p; } public static void main(String[] arg) throws Exception { new JDirectoryChooserTest(); } } freehep-swing-2.0.3/src/test/java/org/freehep/swing/test/package.html0000644012010301201030000000005610470537377026546 0ustar mascellanimascellani Tests for the swing extensions. freehep-swing-2.0.3/src/test/java/org/freehep/swing/test/JSpinBoxTest.java0000644012010301201030000000130210466735775027466 0ustar mascellanimascellanipackage org.freehep.swing.test; import java.awt.event.ActionEvent; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JPanel; import org.freehep.swing.JSpinBox; public class JSpinBoxTest extends TestFrame { protected JComponent createComponent() { JPanel p = new JPanel(); final JSpinBox spin = new JSpinBox(50,0,100); spin.setEnabled(false); p.add(spin); JCheckBox enable = new JCheckBox("enable") { public void fireActionPerformed(ActionEvent e) { spin.setEnabled(isSelected()); } }; enable.setSelected(spin.isEnabled()); p.add(enable); return p; } public static void main(String[] arg) throws Exception { new JSpinBoxTest(); } } freehep-swing-2.0.3/src/test/resources/0000755012010301201030000000000011275634131021030 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/resources/org/0000755012010301201030000000000011275634131021617 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/resources/org/freehep/0000755012010301201030000000000011275634131023235 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/resources/org/freehep/swing/0000755012010301201030000000000011275634131024364 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/resources/org/freehep/swing/test/0000755012010301201030000000000011275634131025343 5ustar mascellanimascellanifreehep-swing-2.0.3/src/test/resources/org/freehep/swing/test/Stop.gif0000644012010301201030000000161110340426354026754 0ustar mascellanimascellaniGIF89a3f333f3333f3ffffff3f̙3f3f333f333333333f33333333f33f3ff3f3f3f3333f33̙33333f3333333f3333f3ffffff3f33ff3f3f3f3fff3ffffffffffff3ffff̙fff3fffffff3ffffff3f333f3333f3ffffff3f̙̙3̙f̙̙̙̙3f3f̙333f3̙333f3fff̙fff3f̙̙3f̙3f̙3f333f3333f3ffffff3f̙3f3f!,fY  A4XaC pHaĉ+P85V=^+ AtXR"E),XQF/EdʕqE$nj7"5ɇ38Zӫ;freehep-swing-2.0.3/src/site/0000755012010301201030000000000011275634131017003 5ustar mascellanimascellanifreehep-swing-2.0.3/src/site/site.xml0000644012010301201030000000316710502105024020462 0ustar mascellanimascellani FreeHEP Swing Extensions http://java.freehep.org/freehep-swing FreeHEP http://java.freehep.org/images/sm-freehep.gif http://java.freehep.org/

freehep-swing-2.0.3/src/site/doc/0000755012010301201030000000000011275634131017550 5ustar mascellanimascellanifreehep-swing-2.0.3/src/site/doc/AnimatedEditClassDiagram.ppt0000644012010301201030000005300010340426354025074 0ustar mascellanimascellaniࡱ> ( ) !"#$%&'Root EntrydO)x@PowerPoint Document(h!SummaryInformation(%DocumentSummaryInformation8_(0 / 0LDArial||&0:A 0"@ .  @n?" dd@  @@`` x  0AA@3ʚ;ʚ;g4EdEd:A 0~ppp@ <4dddd@$ 0|& 80___PPT10   ` 33` Sf3f` 33g` f` www3PP` ZXdbmo` \ғ3y`Ӣ` 3f3ff` 3f3FKf` hk]wwwfܹ` ff>>\`Y{ff` R>&- {p_/̴>?" dd@,|?" dd@   " @ ` n?" dd@   @@``PR    @ ` ` p>> f(    6b  `}  T Click to edit Master title style! !  0`  `  RClick to edit Master text styles Second level Third level Fourth level Fifth level!     S  0 ^ `  >*  0 ^   @*  0 ^ `  @*H  0޽h ? 3380___PPT10.0 Default Design y i(    Bȅ8c"`@ X LinkableEdit     B|s8c"`tfJk \ UndoableEdit     Bh3n>c>--'--p8 {rr{{kbbkk``^^```^^``y`y^^`s`j`j^s^s`gZgQiQiZgZgJgAiAiJgJc>h3n>c>--'--8&{rr{{kbbkk^^``^^^``^^^``^^^``^^^``^^^``^^^``^^^``^^ ^ ``^^^``^"^+^+`"`"^1^:^:`1`1^A^J^J`A`A^P^Y^Y`P`P^`^i^i````^o^x^x`o`o^^^``^^^``^^^``^^^``^^^``^^^``^^^``^^^``^^^``^ ^^` ` ^^#^#``^*^3^3`*`*^:^C^C`:`:^I^R^R`I`I^Y^b^b`Y`Y^g_gViVi_g_gOgFiFiOgOg@g=i=i@g@c>h3n>c>--'--8-IILLIIILLIIILLIIILLIIILLIIIMMJLLIT]]TTdlldds||ss''.77..=FF==MVVMM\ee\\luull|||~uu~~offoo_VV__PGGPP@77@@1((11!!!  --'--[8 --'--18vnnvvg^^ggWWYYWWWYYWWWYYWW W YYWWWYYWW(W(YYW/W8W8Y/Y/W>WGWGY>Y>WNWWWWYNYNW]WfWfY]Y]WmWvWvYmYmW}WWY}Y}WWWYYWWWXXXYYWRIIRRB99BB3**33###  --'--$8    --'--$8 vTTU>>VVUvv?4??--'--$8 IIJ>>LLI}?4?}?--'--$8 ~~--'--$8 XX>>Z[[X}?4?}?--'--$8 ~~--'--h8 IILLIIILLIIILLIIILLIIILLIIILLIIILLIIILLIIILLIIzIrLrLzIzIkIbLbLkIkI[IRLRL[I[ILICLCLLILI<I3L3L<I<I-I$L$L-I-IILLIIILLIIILLIIILLIIINNJLLIU^^UUdmmddt}}tt--'Current User,_D!dunsdunsfreehep-swing-2.0.3/src/site/apt/0000755012010301201030000000000011275634131017567 5ustar mascellanimascellanifreehep-swing-2.0.3/src/site/apt/index.apt0000644012010301201030000000021110502113066021365 0ustar mascellanimascellani --- FreeHEP Swing Extensions --- --- Mark Donszelmann --- Introduction Package with a number of Swing extensions. freehep-swing-2.0.3/src/main/0000755012010301201030000000000011275634131016763 5ustar mascellanimascellanifreehep-swing-2.0.3/src/main/java/0000755012010301201030000000000011275634131017704 5ustar mascellanimascellanifreehep-swing-2.0.3/src/main/java/org/0000755012010301201030000000000011275634131020473 5ustar mascellanimascellanifreehep-swing-2.0.3/src/main/java/org/freehep/0000755012010301201030000000000011275634131022111 5ustar mascellanimascellanifreehep-swing-2.0.3/src/main/java/org/freehep/swing/0000755012010301201030000000000011275634131023240 5ustar mascellanimascellanifreehep-swing-2.0.3/src/main/java/org/freehep/swing/wizard/0000755012010301201030000000000011275634131024540 5ustar mascellanimascellanifreehep-swing-2.0.3/src/main/java/org/freehep/swing/wizard/Finishable.java0000644012010301201030000000133110466735775027466 0ustar mascellanimascellanipackage org.freehep.swing.wizard; /** * A WizardPage that implements this interface can be the final page * on a WizardDialog. When a Finishable page is displayed on the wizard, the * "Finish" button is enabled. A sensible wizard page would implement either * this interface, or HasNextPages, or both. If your page implemented neither * then neither the "Next" nor "Finish" button would enable, so your page * would be a "dead end." * @author Jonas Gifford * @see WizardPage * @see WizardDialog * @see HasNextPages */ public interface Finishable { /** * Invoked by the WizardDialog when the used clicks on * the "Finish" button. * @see WizardDialog */ public abstract void onFinish(); } freehep-swing-2.0.3/src/main/java/org/freehep/swing/wizard/WizardDialog.java0000644012010301201030000002036110466735775030006 0ustar mascellanimascellanipackage org.freehep.swing.wizard; import java.awt.AWTEvent; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Cursor; import java.awt.Dialog; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowEvent; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JPanel; import javax.swing.border.EtchedBorder; /** * The wizard is useful for getting user input on multiple pages. The WizardDialog supports a * tree structure of WizardPages, and the path down that tree is determined by each node * when the "Next" button is clicked. At a leaf (or at any node), the "Finish" button can be * clicked and the wizard closes. The "Next" button is enabled when a WizardPage that implements * the interface HasNextPages is showing, the "Finish" button is enabled when a page that implements * the interface Finishable is showing, and the "Help" button is enabled when a page that implements * HasHelpPages is showing. * @author Jonas Gifford * @see WizardPage * @see HasNextPages * @see Finishable * @see HasHelpPage */ public class WizardDialog extends JDialog implements ActionListener { private CardLayout m_layout; private Cursor m_default = Cursor.getDefaultCursor(); private Cursor m_wait = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR); private WizardPage m_firstPage; private JPanel m_wizardPagePanel; private WizardPage m_currentPage; private JButton m_cancel; private JButton m_finish; private JButton m_help; private JButton m_next; private JButton m_prev; private boolean m_currentPageHasAmbiguousDefault; /** * @param title the title for the wizard dialog * @param firstPage the root of the tree structure and the page the wizard opens to */ public WizardDialog(String title, WizardPage firstPage) { super(); this.setTitle(title); init(firstPage); } public WizardDialog(Frame owner, String title, WizardPage firstPage) { super(owner,title,true); init(firstPage); } public WizardDialog(Dialog owner, String title, WizardPage firstPage) { super(owner,title,true); init(firstPage); } private void init(WizardPage firstPage) { getContentPane().setLayout(new BorderLayout()); m_wizardPagePanel = new JPanel(m_layout = new CardLayout()); firstPage.addTo(m_wizardPagePanel, this, null); // recursive call JPanel buttons = new JPanel(new FlowLayout()); buttons.add(m_cancel = new JButton("Cancel")); m_cancel.setMnemonic('C'); buttons.add(m_help = new JButton("Help")); m_help.setMnemonic('H'); buttons.add(m_prev = new JButton("<< Previous")); m_prev.setMnemonic('P'); buttons.add(m_next = new JButton("Next >>")); m_next.setMnemonic('N'); buttons.add(m_finish = new JButton("Finish")); m_finish.setMnemonic('F'); m_wizardPagePanel.setBorder(new EtchedBorder()); getContentPane().add(BorderLayout.CENTER, m_wizardPagePanel); getContentPane().add(BorderLayout.SOUTH, buttons); m_layout.first(m_wizardPagePanel); (m_currentPage = m_firstPage = firstPage).doEnable(); m_cancel.addActionListener(this); m_help.addActionListener(this); m_prev.addActionListener(this); m_next.addActionListener(this); m_finish.addActionListener(this); m_currentPageHasAmbiguousDefault = m_currentPage.isFinishable() && m_currentPage.hasNextPages(); // setDefaultButton(); m_help.setEnabled(firstPage instanceof HasHelpPage); setResizable(false); enableEvents(AWTEvent.WINDOW_EVENT_MASK); firstPage.beforeShowing(); } /** Public as an implementation side effect; do not call. */ public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source == m_cancel) onCancel(); else if (source == m_help) onHelp(); else if (source == m_prev) onPrev(); else if (source == m_next) onNext(); else if (source == m_finish) onFinish(); } /** * Closes the wizard. Invoked by dispose() in WizardPage. * @see WizardPage * @see WizardPage#dispose() */ public void dispose() { m_firstPage.clear(); /* * References in it and all pages linked to * it are set to null. */ WizardPage.pageNumber = 0; super.dispose(); } /** Public as an implementation side effect; do not call. */ public void processWindowEvent(WindowEvent e) { int id = e.getID(); if (id == WindowEvent.WINDOW_CLOSING) onCancel(); else if (id == WindowEvent.WINDOW_ACTIVATED) setDefaultButton(); } protected void handleError(String message, Throwable t) { t.printStackTrace(); } void setDefaultButton() { if (m_currentPageHasAmbiguousDefault && m_next.isEnabled()) getRootPane().setDefaultButton(m_next); else if (m_currentPageHasAmbiguousDefault && m_finish.isEnabled()) getRootPane().setDefaultButton(m_finish); else getRootPane().setDefaultButton(m_currentPage.hasNextPages() ? m_next : m_finish); } void setFinishEnabled(boolean b) { m_finish.setEnabled(b && m_currentPage.isFinishable()); } void setNextEnabled(boolean b) { m_next.setEnabled(b && m_currentPage.hasNextPages()); } void setToDefaultCursor() { setCursor(m_default); } void setToWaitCursor() { setCursor(m_wait); } void doPrevEnabled() { m_prev.setEnabled(m_currentPage.getPrev() != null); } private void setToCurrentPage(WizardPage page) { m_currentPage = page; m_currentPageHasAmbiguousDefault = m_currentPage.isFinishable() && m_currentPage.hasNextPages(); page.doEnable(); if (!m_currentPageHasAmbiguousDefault) setDefaultButton(); m_help.setEnabled(page instanceof HasHelpPage); page.beforeShowing(); m_layout.show(m_wizardPagePanel, page.toString()); } private void onCancel() { setToWaitCursor(); try { // This traveses all pages, calling their doCancel method m_firstPage.doCancel(); dispose(); } catch (Throwable t) { handleError("Error during wizard processing", t); } finally { setToDefaultCursor(); } } private void onFinish() { setToWaitCursor(); try { ((Finishable) m_currentPage).onFinish(); // Notify all previous pages WizardPage prev = m_currentPage.getPrev(); while (prev != null) { prev.onWasFinished(); prev = prev.getPrev(); } } catch (Throwable t) { handleError("Error during wizard processing", t); } finally { setToDefaultCursor(); } } private void onHelp() { setToWaitCursor(); // HasHelpPage h = ((HasHelpPage) m_currentPage); // Application.getApplication().showHelpTopic(h.getHelpTopic(), this); setToDefaultCursor(); } private void onNext() { setToWaitCursor(); try { WizardPage newPage = ((HasNextPages) m_currentPage).getNext(); if (newPage != null) { // Make sure this page was already added to the current (soon to be previous) page, // if not add it now. if (!m_wizardPagePanel.isAncestorOf(newPage)) { newPage.addTo(m_wizardPagePanel, this, m_currentPage); newPage.invalidate(); validate(); } setToCurrentPage(newPage); } } catch (Throwable t) { handleError("Error during wizard processing", t); } finally { setToDefaultCursor(); } } private void onPrev() { setToWaitCursor(); try { WizardPage prev = m_currentPage.getPrev(); m_currentPage.onPrevious(); setToCurrentPage(prev); } catch (Throwable t) { handleError("Error during wizard processing", t); } finally { setToDefaultCursor(); } } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/wizard/WizardPage.java0000644012010301201030000002235110466735775027464 0ustar mascellanimascellanipackage org.freehep.swing.wizard; import java.awt.Container; import java.awt.LayoutManager; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import javax.swing.JPanel; /** * Extend this class to create a page for the WizardDialog. Implement the * interface HasNextPages if you want there to be pages following this * page, and implement the Finishable interface if you want this to be * the last page. You may implement one or both, but implementing * neither would be silly because then neither the "Next" nor "Finish" * button will enable and your page will be a "dead end". Implement * HasHelpPage if you want your page to link to a help topic. Override * the methods getNextEnabled() and getFinishEnabled() * to control how the "Next" and "Finish" buttons enable. *

* This class is a KeyListener and has implemented the interface * with non-methods. If you do not override these * methods, doEnable() will be called when a key * is released on components registered as KeyListeners. * This implementation is designed for when the buttons * enable when text is added to them. For example, if you page had
* * m_text = new JASTextField();
* text.addKeyListener(this);
*

* then the "Next" and "Finish" buttons would enable each time a key is released * in the field text. You might define getNextEnabled() * as follows:
*

 * protected boolean getNextEnabled()
 * {
 *                String s = m_text.getText();
 *                return s != null && s.length() > 0;
 * }
 * 
* @author Jonas Gifford * @see WizardDialog * @see HasNextPages * @see Finishable * @see HasHelpPage */ public abstract class WizardPage extends JPanel implements KeyListener { static int pageNumber = 0; private WizardDialog m_wizard; private WizardPage m_prev = null; private WizardPage[] m_nextWizardPages = null; private boolean m_hasNextPages; private boolean m_isFinishable; private String m_number; private boolean m_nextEnabled = true; private boolean m_finishEnabled = true; /** * Supply a layout manager for the panel to use. See Sun's notes on * using * layout managers. In the constructor of your subclass, add components * to the page as you would add components to a regular container, using the * add(..) methods. It is not a good idea to use AWT components * here because those heavy-weight components do not mix well with swing's * light-weight components. You should use only * swing components. * The jas.util package has a number of * utility * components that may be useful for these pages. * @param lm the layout manager to use for this page. * @see java.awt.LayoutManager */ public WizardPage(LayoutManager lm) { super(lm); m_isFinishable = (this instanceof Finishable); m_hasNextPages = (this instanceof HasNextPages); } public WizardPage() { m_isFinishable = (this instanceof Finishable); m_hasNextPages = (this instanceof HasNextPages); } /** * This method is called just before the page is brought to the screen. By default, it * does nothing but you can override it to do some last-minute setup on your page. */ protected void beforeShowing() {} public void doBusy(Runnable run) { m_wizard.setToWaitCursor(); try { run.run(); } finally { m_wizard.setToDefaultCursor(); } } /** Override this to provide your own behaviour for key events; does nothing by default. */ public void keyPressed(KeyEvent e) {} /** * If you add this class as a KeyListener and don't override this method then * the buttons will be enabled on every key event in the definition for this method. */ public void keyReleased(KeyEvent e) { if (e.getKeyCode() != KeyEvent.VK_ENTER) doEnable(); } /** Override this to provide your own behaviour for key events; does nothing by default. */ public void keyTyped(KeyEvent e) {} /** * This method is called if the user uses the previous button to traverse backwards * from this page. By default it does nothing, but you can override it if necessary * to do some cleanup. */ protected void onPrevious() {} /** * This method is called if the user has canceled the wizard. By default it does nothing, * but you can override it to perform cleanup if necessary. The wizard follows a preorder * tree traversal, so the onCancel() methods are called starting from the bottom * and working up each branch separately to the root. */ protected void onCancel() {} /** * Called when a page following this page had its onFinish() method invoked. * By default does nothing, but can be used to perform cleanup operations */ protected void onWasFinished() {} /** This method is public as an implementation side effect; do not call. */ public String toString() { return m_number; } /** * Override to provide customized behaviour for enabling the "Finish" button. By * default, this method returns whether the page implements Finishable. If * your page does not implement that interface, the "Finish" button will never * enable. Call doEnable() to call this method, or add your * page as a key listener to a component, and then doEnable() will * be called each time a key is released in that component. * @see #doEnable() * @see Finishable * @return whether to enable the "Finish" button */ protected boolean getFinishEnabled() { return m_isFinishable && m_finishEnabled; } /** * Override to provide customized behaviour for enabling the "Next" button. By * default, this method returns whether the page implements HasNextPages. If * your page does not implement that interface, the "Next" button will never * enable. Call doEnable() to call this method, or add your * page as a key listener to a component, and then doEnable() will * be called each time a key is released in that component. * @see #doEnable() * @see HasNextPages * @return whether to enable the "Next" button */ protected boolean getNextEnabled() { return m_hasNextPages && m_nextEnabled; } protected void setNextEnabled(boolean enabled) { if (enabled != m_nextEnabled) { m_nextEnabled = enabled; doEnable(); } } protected void setFinishEnabled(boolean enabled) { if (enabled != m_finishEnabled) { m_finishEnabled = enabled; doEnable(); } } /** Call to dispose the wizard (i.e., to have it close). */ protected void dispose() { m_wizard.dispose(); } /** * Forces the wizard to call getNextEnabled() and getFinishEnabled() to enable the * buttons on the wizard. This method is called by the keyReleased(KeyEvent) method * if you add this class as a KeyListener to a text field. * @see #getNextEnabled() * @see #getFinishEnabled() * @see #keyReleased(KeyEvent) * @see java.awt.event.KeyEvent * @see java.awt.event.KeyListener */ protected void doEnable() { // m_wizard will be null if this page has not yet been attached to a WizardDialog if (m_wizard == null) return; m_wizard.setNextEnabled(getNextEnabled()); m_wizard.setFinishEnabled(getFinishEnabled()); m_wizard.doPrevEnabled(); if (m_isFinishable && m_hasNextPages) m_wizard.setDefaultButton(); } protected void handleError(String message, Throwable t) { m_wizard.handleError(message, t); } boolean isFinishable() { return m_isFinishable; } WizardPage getPrev() { return m_prev; } void addTo(Container c, WizardDialog wizard, WizardPage prev) { c.add(m_number = String.valueOf(pageNumber++), this); if (m_hasNextPages) { m_nextWizardPages = ((HasNextPages) this).getNextWizardPages(); if (m_nextWizardPages != null) for (int i = 0; i < m_nextWizardPages.length; i++) if (m_nextWizardPages[i] != null) m_nextWizardPages[i].addTo(c, wizard, this); } m_wizard = wizard; m_prev = prev; } void clear() { if (m_hasNextPages) { for (int i = 0; i < m_nextWizardPages.length; i++) if (m_nextWizardPages[i] != null) m_nextWizardPages[i].clear(); m_nextWizardPages = null; } m_prev = null; m_wizard = null; } void doCancel() // preorder tree traversal { if (m_nextWizardPages != null) for (int i = 0; i < m_nextWizardPages.length; i++) if (m_nextWizardPages[i] != null) m_nextWizardPages[i].doCancel(); onCancel(); } boolean hasNextPages() { return m_hasNextPages; } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/wizard/HasNextPages.java0000644012010301201030000000250210466735775027755 0ustar mascellanimascellanipackage org.freehep.swing.wizard; /** * A WizardPage that implements this interface will have one or more subsequent * pages. When a page that implements this interface is showing in a WizardDialog, * the "Next" button will be enabled. A sensible wizard page would implement this * interface, or the Finishable interface, or both. If you implement neither then * neither the "Next" nor "Finish" button will enable on the wizard, and you page * will be a "dead end". * @author Jonas Gifford * @see WizardPage * @see WizardDialog * @see Finishable */ public interface HasNextPages { /** * This method is called when the user clicks on the "Next" button. You must * return a page that was in the array returned by getNextWizardPages. * @return a WizardPage that was included in the array returned by getNextWizardPages */ public abstract WizardPage getNext(); /** * Returns an array of all possible next pages. There could, of course, be just * one element in this array. This method will be called before the wizard * shows on the screen. The wizard needs to know all of the possible pages so that * it can size itself to fit them all. * @return an array of all possible subsequent pages */ public abstract WizardPage[] getNextWizardPages(); } freehep-swing-2.0.3/src/main/java/org/freehep/swing/wizard/package.html0000644012010301201030000000026110470537377027032 0ustar mascellanimascellani An implementation of a Wizard Dialog. The wizard f=dialog is used to present the user with a set of pages, each of which collects some information from the user. freehep-swing-2.0.3/src/main/java/org/freehep/swing/wizard/HasHelpPage.java0000644012010301201030000000110010466735775027535 0ustar mascellanimascellanipackage org.freehep.swing.wizard; /** * A WizardPage that implements this interface can link the user to * a help topic. When a HasHelpPage page is showing, the "Help" button * will enable. * @see WizardPage * @author Jonas Gifford * @author Peter Armstrong */ public interface HasHelpPage { /** * Returns the help topic to open if the user clicks on the "Help" button. This * string must be one of the XML targets. (This is a cheesy adaptation of * what Jonas built for the Oracle Help system.) */ public abstract String getHelpTopic(); } freehep-swing-2.0.3/src/main/java/org/freehep/swing/JTriStateMenuItem.java0000644012010301201030000000306410466735775027444 0ustar mascellanimascellani// Copyright 2000, CERN, Geneva, Switzerland. package org.freehep.swing; import javax.swing.Icon; import javax.swing.JCheckBoxMenuItem; import javax.swing.UIManager; /** * * @author Mark Donszelmann * @version $Id: JTriStateMenuItem.java 8584 2006-08-10 23:06:37Z duns $ */ public class JTriStateMenuItem extends JCheckBoxMenuItem implements TriState { static { UIManager.getDefaults().put("TriStateMenuItemUI", "org.freehep.plaf.metal.MetalTriStateMenuItemUI"); } public JTriStateMenuItem () { this(null, null, 0); } public JTriStateMenuItem(Icon icon) { this(null, icon, 0); } public JTriStateMenuItem(Icon icon, int selected) { this(null, icon, selected); } public JTriStateMenuItem (String text) { this(text, null, 0); } public JTriStateMenuItem (String text, int selected) { this(text, null, selected); } public JTriStateMenuItem(String text, Icon icon) { this(text, icon, 0); } public JTriStateMenuItem (String text, Icon icon, int selected) { super(text, icon, false); setModel(new TriStateModel()); setTriState(selected); } public int getTriState() { return ((TriStateModel)getModel()).getTriState(); } public void setTriState(int state) { ((TriStateModel)getModel()).setTriState(state); } public void setTriState(boolean state) { setTriState((state) ? 1 : 0); } public String getUIClassID() { return "TriStateMenuItemUI"; } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/JSpinBox.java0000644012010301201030000001667510466735775025637 0ustar mascellanimascellanipackage org.freehep.swing; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Enumeration; import java.util.Vector; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.PlainDocument; /** * This is an implementation of a simple spin box suitable for use * with positive integers. It displays as a text area with two small * up and down buttons beside it. Pressing the up or down button increments * or decrements the counter. Pressing and holding either button causes the * value to change continuously (unless delay is set to 0). * * @deprecated Probably better to use java.swing.JSpinBox now. */ public class JSpinBox extends JComponent { /** * Creates a spin box * @param init The initial value for the spin box * @param min The minimum value for the spin box * @param max The maximum value for the spin box */ public JSpinBox(int init, int min, int max) { if (min<0 || maxmax) throw new IllegalArgumentException("Invalid initial parameters for spin box"); this.value = init; this.min = min; this.max = max; plus = new JButton(new ImageIcon(getClass().getResource("images/plus.gif"))); minus = new JButton(new ImageIcon(getClass().getResource("images/minus.gif"))); valueChanging = true; field = new JTextField(new JSpinDocument(),String.valueOf(init), (int) (1+Math.log(Math.abs(max))/Math.log(10))); valueChanging = false; valueChanged(); plus.setMargin(new Insets(0,0,0,0)); plus.setModel(new MachineGunButtonModel()); minus.setMargin(new Insets(0,0,0,0)); minus.setModel(new MachineGunButtonModel()); setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0)); JPanel p = new JPanel(new BorderLayout(0,0)); p.add(BorderLayout.NORTH,plus); p.add(BorderLayout.SOUTH,minus); add(field); add(p); plus.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { value++; valueChanged(); } }); minus.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { value--; valueChanged(); } }); } public void addActionListener(ActionListener l) { listener.addElement(l); } public void removeActionListener(ActionListener l) { listener.removeElement(l); } private void fireActionListener() { ActionEvent event = new ActionEvent(this,ActionEvent.ACTION_FIRST,"hi"); Enumeration e = listener.elements(); while (e.hasMoreElements()) { ((ActionListener) e.nextElement()).actionPerformed(event); } } private void valueChanged() { if (value > max) value = max; if (value < min) value = min; plus.setEnabled(value < max); minus.setEnabled(value > min); if (!valueChanging) { valueChanging = true; field.setText(String.valueOf(value)); valueChanging = false; } fireActionListener(); } public void setMin(int value) { min = value; } public void setMax(int value) { max = value; } public int getMin() { return min; } public int getMax() { return max; } public int getValue() { return value; } public void setValue(int value) { this.value = value; valueChanged(); } public int getRepeatDelay() { MachineGunButtonModel model = (MachineGunButtonModel) plus.getModel(); return model.getRepeatDelay(); } public int getInitialDelay() { MachineGunButtonModel model = (MachineGunButtonModel) plus.getModel(); return model.getInitialDelay(); } /** * Sets the delay for the repeat function of the arrow keys. * @param delay The delay between increments in milliseconds, or 0 to disable repeat */ public void setRepeatDelay(int delay) { MachineGunButtonModel model = (MachineGunButtonModel) plus.getModel(); model.setRepeatDelay(delay); model = (MachineGunButtonModel) minus.getModel(); model.setRepeatDelay(delay); } /** * Sets the initial delay for the repeat function of the arrow keys. * @param delay The delay between increments in milliseconds, or 0 to disable repeat */ public void setInitialDelay(int delay) { MachineGunButtonModel model = (MachineGunButtonModel) plus.getModel(); model.setInitialDelay(delay); model = (MachineGunButtonModel) minus.getModel(); model.setInitialDelay(delay); } public void setEnabled(boolean enabled) { plus.setEnabled(enabled); minus.setEnabled(enabled); field.setEnabled(enabled); super.setEnabled(enabled); } private int max = 100; private int min = 0; private int value = 0; private boolean valueChanging = false; private final JTextField field; private final JButton plus; private final JButton minus; private final Vector listener = new Vector(); private class JSpinDocument extends PlainDocument implements Runnable { public void insertString(int pos, String string, AttributeSet p3) throws BadLocationException { if (!valueChanging) { for (int i=0; i max) { super.remove(pos,string.length()); Thread.dumpStack(); getToolkit().beep(); return; } value = nValue; valueChanging = true; valueChanged(); valueChanging = false; } } public void remove(int pos, int len) throws BadLocationException { // Things are complicated here by the fact that the remove may be just // the first part of a replace, so we cant simply test for a illegal value // after the remove, in case an insert is to follow immediately. Instead we // queue a later check on the validity of the field. super.remove(pos,len); if (!valueChanging) SwingUtilities.invokeLater(this); } public void run() { if (field == null) return; String text = field.getText(); int nValue; if (text.length() == 0) { nValue = Integer.MIN_VALUE; } else { nValue = Integer.parseInt(field.getText()); } if (nValue < min) { nValue = min; getToolkit().beep(); field.setText(String.valueOf(nValue)); } value = nValue; valueChanging = true; valueChanged(); valueChanging = false; } } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/Headless.java0000644012010301201030000000165510466735775025663 0ustar mascellanimascellanipackage org.freehep.swing; import javax.swing.JComponent; import javax.swing.JInternalFrame; /** * A class which aids in creating swing components in a "headless" environment. * Useful for using swing components to export graphics to a file, without requiring * a connection to a display (i.e. with -Djava.awt.headless=true). * @author Tony Johnson * @author Mark Donszelmann */ public class Headless extends JInternalFrame { public Headless(JComponent component) { setContentPane(component); } // Note, this must override the (deprecated) method show, not setVisible public void show() { super.show(); // Although the above calculates the size of the components, it does not lay them out. // For some reason frame.validate simply delegates to Container.validate(), which does nothing // if there is no peer defined. addNotify(); super.validateTree(); } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/event/0000755012010301201030000000000011275634131024361 5ustar mascellanimascellanifreehep-swing-2.0.3/src/main/java/org/freehep/swing/event/MouseInputRouter.java0000644012010301201030000001054510466735775030563 0ustar mascellanimascellani// Copyright 2003, SLAC, Stanford, U.S.A. package org.freehep.swing.event; import java.awt.Component; import java.awt.event.MouseEvent; import javax.swing.SwingUtilities; import javax.swing.event.MouseInputListener; /** * This class allows MouseEvents from the three buttons to be routed to * three MouseInputListeners. The MouseEvents generated for these listeners * always have Button1 in their event. * * @author Mark Donszelmann * @version $Id: MouseInputRouter.java 8584 2006-08-10 23:06:37Z duns $ * @status NOT TESTED */ public class MouseInputRouter implements MouseInputListener { MouseInputListener left, middle, right; public MouseInputRouter(Component c) { c.addMouseMotionListener(this); c.addMouseListener(this); } public void setLeftMouseInputListener(MouseInputListener l) { left = l; } public void setMiddleMouseInputListener(MouseInputListener l) { middle = l; } public void setRightInputListener(MouseInputListener l) { right = l; } private MouseEvent convertMouseEvent(MouseEvent event) { int modifiers = event.getModifiers() | event.getModifiersEx(); modifiers |= MouseEvent.BUTTON1_MASK; modifiers &= ~MouseEvent.BUTTON2_MASK; modifiers &= ~MouseEvent.BUTTON3_MASK; modifiers |= MouseEvent.BUTTON1_DOWN_MASK; modifiers &= ~MouseEvent.BUTTON2_DOWN_MASK; modifiers &= ~MouseEvent.BUTTON3_DOWN_MASK; return new MouseEvent(event.getComponent(), event.getID(), event.getWhen(), modifiers, event.getX(), event.getY(), event.getClickCount(), event.isPopupTrigger(), event.getButton()); } public void mousePressed(MouseEvent event) { if ((left != null) && (SwingUtilities.isLeftMouseButton(event))) { left.mousePressed(event); } if ((middle != null) && (SwingUtilities.isMiddleMouseButton(event))) { middle.mousePressed(convertMouseEvent(event)); } if ((right != null) && (SwingUtilities.isRightMouseButton(event))) { right.mousePressed(convertMouseEvent(event)); } } public void mouseReleased(MouseEvent event) { if ((left != null) && (SwingUtilities.isLeftMouseButton(event))) { left.mouseReleased(event); } if ((middle != null) && (SwingUtilities.isMiddleMouseButton(event))) { middle.mouseReleased(convertMouseEvent(event)); } if ((right != null) && (SwingUtilities.isRightMouseButton(event))) { right.mouseReleased(convertMouseEvent(event)); } } public void mouseClicked(MouseEvent event) { if ((left != null) && (SwingUtilities.isLeftMouseButton(event))) { left.mouseClicked(event); } if ((middle != null) && (SwingUtilities.isMiddleMouseButton(event))) { middle.mouseClicked(convertMouseEvent(event)); } if ((right != null) && (SwingUtilities.isRightMouseButton(event))) { right.mouseClicked(convertMouseEvent(event)); } } public void mouseDragged(MouseEvent event) { if ((left != null) && (SwingUtilities.isLeftMouseButton(event))) { left.mouseDragged(event); } if ((middle != null) && (SwingUtilities.isMiddleMouseButton(event))) { middle.mouseDragged(convertMouseEvent(event)); } if ((right != null) && (SwingUtilities.isRightMouseButton(event))) { right.mouseDragged(convertMouseEvent(event)); } } public void mouseMoved(MouseEvent event) { if (left != null) left.mouseMoved(event); if (middle != null) middle.mouseMoved(event); if (right != null) right.mouseMoved(event); } public void mouseEntered(MouseEvent event) { if (left != null) left.mouseEntered(event); if (middle != null) middle.mouseEntered(event); if (right != null) right.mouseEntered(event); } public void mouseExited(MouseEvent event) { if (left != null) left.mouseExited(event); if (middle != null) middle.mouseExited(event); if (right != null) right.mouseExited(event); } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/popup/0000755012010301201030000000000011275634131024403 5ustar mascellanimascellanifreehep-swing-2.0.3/src/main/java/org/freehep/swing/popup/PopupListener.java0000644012010301201030000000145310466735775030103 0ustar mascellanimascellanipackage org.freehep.swing.popup; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JPopupMenu; /** * A simple helper class for popping up popup menus. * This should be added as a mouse listener to the component to which * the popup menu should be associated. * @author tonyj */ public class PopupListener extends MouseAdapter { private JPopupMenu popup; public PopupListener(JPopupMenu popup) { this.popup = popup; } public void mousePressed(MouseEvent e) { maybeShowPopup(e); } public void mouseReleased(MouseEvent e) { maybeShowPopup(e); } protected void maybeShowPopup(MouseEvent e) { if (popup.isPopupTrigger(e)) { popup.show(e.getComponent(), e.getX(), e.getY()); } } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/popup/GlobalMouseListener.java0000644012010301201030000001131310466735775031205 0ustar mascellanimascellanipackage org.freehep.swing.popup; import java.awt.Component; import java.awt.Container; import java.awt.event.ContainerEvent; import java.awt.event.ContainerListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.event.EventListenerList; /** * This class is designed to work around a deficiency in Swing's mouse handling. * It enables a listener to be applied to a component so that all mouse events * in that component, or any of its subcomponents will be reported. This is * useful for example in creating Popup menus for complex graphical objects * (such as plots). *

* There is no easy way to implement this functionality in Swing, so this class * works by recursively adding mouse listeners to all components in the heirarchy. * It also adds a ComponentListener so that it can add and remove listeners from * items as they are added to the tree. *

* Warning: This class can have unexpected side effects in some rare cases. * Normally swing will delegate mouse events to a component's parent if that component * does not listen for mouse events itself. Since this class adds mouse listeners to * all components, it can have the side effect of preventing this mouse event delegation. * (In Java 1.4 it is possible to tell if a mouse listener already exists on a component, * so maybe it would be possible to work around this limitation. Not clear how you would * know if a mouse listener was subsequently added). * @author tonyj * @version $Id: GlobalMouseListener.java 8584 2006-08-10 23:06:37Z duns $ */ public class GlobalMouseListener { /** Create a new GlobalMouseListener associated to a component * @param c The component on which to listen for mouse events */ public GlobalMouseListener(Component c) { final MouseListener ml = new MouseListener() { public void mouseClicked(MouseEvent e) { redispatch(e); } public void mouseEntered(MouseEvent e) { redispatch(e); } public void mouseExited(MouseEvent e) { redispatch(e); } public void mousePressed(MouseEvent e) { redispatch(e); } public void mouseReleased(MouseEvent e) { redispatch(e); } }; ContainerListener cl = new ContainerListener() { public void componentAdded(ContainerEvent e) { Component source = e.getChild(); changeGlobalMouseListener(true,source,ml,this); } public void componentRemoved(ContainerEvent e) { Component source = e.getChild(); changeGlobalMouseListener(false,source,ml,this); } }; changeGlobalMouseListener(true,c,ml,cl); } private void changeGlobalMouseListener(boolean add, Component c, MouseListener ml, ContainerListener cl) { if (add) c.addMouseListener(ml); else c.removeMouseListener(ml); if (c instanceof Container) { Container cc = (Container) c; if (add) cc.addContainerListener(cl); else cc.removeContainerListener(cl); int l = cc.getComponentCount(); for (int i=0; i 0) { MouseListener[] list = (MouseListener[]) listeners.getListeners(MouseListener.class); switch (e.getID()) { case MouseEvent.MOUSE_CLICKED: for (int i=0; i Utilities for dealing with Popup menus. freehep-swing-2.0.3/src/main/java/org/freehep/swing/popup/HasPopupItems.java0000644012010301201030000000174310466735775030035 0ustar mascellanimascellani/* * HasPopupItems.java * Created on March 13, 2001, 1:56 PM */ package org.freehep.swing.popup; import java.awt.Component; import java.awt.Point; import javax.swing.JPopupMenu; /** * Implemented by any component that wants to contribute to a popup menu. * When an Application processes a popup trigger event it searches for the * deepest component beneath event, then works up throught all the parents * checking each component in turn to see if it implements HasPopupItems, and * it so calling its modifyPopupMenu item. * @author Tony Johnson (tonyj@slac.stanford.edu) * @version $Id: HasPopupItems.java 8584 2006-08-10 23:06:37Z duns $ */ public interface HasPopupItems { /** * Allows a component to create or modify a popup menu * @param menu The menu created by the components descendents * @param source The deepest component * @return The modified menu */ public JPopupMenu modifyPopupMenu(JPopupMenu menu, Component source, Point p); } freehep-swing-2.0.3/src/main/java/org/freehep/swing/popup/GlobalPopupListener.java0000644012010301201030000000267210466735775031230 0ustar mascellanimascellanipackage org.freehep.swing.popup; import java.awt.Component; import java.awt.Point; import java.awt.Window; import java.awt.event.MouseEvent; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; /** * * @author tonyj */ public class GlobalPopupListener extends PopupListener { public GlobalPopupListener() { super(null); } protected void maybeShowPopup(MouseEvent me) { JPopupMenu popup = new JPopupMenu(); if (popup.isPopupTrigger(me)) { Component source = me.getComponent(); Window w = (Window) (source instanceof Window ? source : SwingUtilities.getAncestorOfClass(Window.class,source)); if (w != null) // FreeHEP-455 { Point p = SwingUtilities.convertPoint(source,me.getPoint(),w); processPopupEvent(popup,w,p.x,p.y); } } } private void processPopupEvent(JPopupMenu menu, Component source, int x, int y) { Component target = SwingUtilities.getDeepestComponentAt(source,x,y); for (Component c = target; c != null; c = c.getParent()) { if (c instanceof HasPopupItems) { Point p = SwingUtilities.convertPoint(source,x,y,c); menu = ((HasPopupItems) c).modifyPopupMenu(menu,target,p); } } if (menu != null && menu.getComponentCount() > 0) { menu.show(source,x,y); } } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/layout/0000755012010301201030000000000011275634131024555 5ustar mascellanimascellanifreehep-swing-2.0.3/src/main/java/org/freehep/swing/layout/StackedLayout.java0000644012010301201030000001075010466735775030220 0ustar mascellanimascellani// Charles A. Loomis, Jr., and University of California, Santa Cruz, // Copyright (c) 2000 package org.freehep.swing.layout; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Insets; import java.awt.LayoutManager; /** * This layout manager places all of the components the same size and * places them at the same position. This is an appropriate layout * manager for a JLayeredPane. * * @author Charles Loomis * @version $Id: StackedLayout.java 8584 2006-08-10 23:06:37Z duns $ */ public class StackedLayout implements LayoutManager { /** * Create a new StackedLayout manager. */ public StackedLayout() { } /** * Adds the specified component with the specified name to the * layout. (This method actually does nothing since the component * list is obtained from the container directly.) * * @param name the name of the component * @param comp the component to add */ public void addLayoutComponent(String name, Component comp) { } /** * Removes the specified component from the layout. (This method * actually does nothing since the component list is obtained from * the container directly.) * * @param comp the component to be removed */ public void removeLayoutComponent(Component comp) { } /** * Calculates the preferred size dimensions for the specified * panel given the components in the specified parent container. * * @param parent the component to be laid out * * @see #minimumLayoutSize */ public Dimension preferredLayoutSize(Container parent) { return getLayoutSize(parent, true); } /** * Calculates the minimum size dimensions for the specified panel * given the components in the specified parent container. * * @param parent the component to be laid out * * @see #preferredLayoutSize */ public Dimension minimumLayoutSize(Container parent) { return getLayoutSize(parent, false); } /** * Scan the list of components and pick out the largest width and * height. * * @param parent the container in which to do the layout. * @param isPreferred true for calculating preferred size, * false for calculating minimum size. * * @return the largest width and height needed */ protected Dimension getLayoutSize(Container parent, boolean isPreferred) { // Get the number of components in the parent container. int n = parent.getComponentCount(); // Loop over the components and get the maximum widths and // heights. Dimension returnSize = new Dimension(); for (int i=0; i0) { // Total dimensions of the parent. We will make all // of the components of this size. Dimension size = parent.getSize(); int width = size.width - (insets.left + insets.right); int height = size.height - (insets.top + insets.bottom); // Actually loop over the components and set the size // to the full width and height. for (int i=0; iToolbarLayout.LEFT, ToolbarLayout.RIGHT, * or ToolbarLayout.CENTER. * @param align the alignment value */ public ToolBarLayout(int align) { this(align, 5, 5); } /** * Creates a new ToolbarLayout with the indicated alignment * and the indicated horizontal and vertical gaps. *

* The value of the alignment argument must be one of * ToolbarLayout.LEFT, ToolbarLayout.RIGHT, * or ToolbarLayout.CENTER. * @param align the alignment value. * @param hgap the horizontal gap between components. * @param vgap the vertical gap between components. */ public ToolBarLayout(int align,int hgap,int vgap) { this.align = align; this.hgap = hgap; this.vgap = vgap; } /** * Gets the alignment for this layout. * Possible values are ToolbarLayout.LEFT, * ToolbarLayout.RIGHT, or ToolbarLayout.CENTER. * @return the alignment value for this layout. * @see #setAlignment */ public int getAlignment() { return align; } /** * Sets the alignment for this layout. * Possible values are ToolbarLayout.LEFT, * ToolbarLayout.RIGHT, and ToolbarLayout.CENTER. * @param align the alignment value. * @see #getAlignment */ public void setAlignment(int align) { this.align = align; } /** * Gets the horizontal gap between components. * @return the horizontal gap between components. * @see #setHgap */ public int getHgap() { return hgap; } /** * Sets the horizontal gap between components. * @param hgap the horizontal gap between components * @see #getHgap */ public void setHgap(int hgap) { this.hgap = hgap; } /** * Gets the vertical gap between components. * @return the vertical gap between components. * @see #setVgap */ public int getVgap() { return vgap; } /** * Sets the vertical gap between components. * @param vgap the vertical gap between components * @see #getVgap */ public void setVgap(int vgap) { this.vgap = vgap; } /** * Adds the specified component to the layout. Sets the orientation to be horizontal. * @param name the name of the component * @param comp the component to be added */ public void addLayoutComponent(String name, Component comp) { try { ((JToolBar)comp).setOrientation(JToolBar.HORIZONTAL); } catch (Exception e){ } } /** * Removes the specified component from the layout. Not used by * this class. * @param comp the component to remove * @see java.awt.Container#removeAll */ public void removeLayoutComponent(Component comp) { } /** * Returns the preferred dimensions for this layout given the components * in the specified target container. This method is the difference * between ToolbarLayout and FlowLayout. * @param target the component which needs to be laid out * @return the preferred dimensions to lay out the * subcomponents of the specified container. * @see Container * @see #minimumLayoutSize * @see java.awt.Container#getPreferredSize */ public Dimension preferredLayoutSize(Container target) { synchronized (target.getTreeLock()) { Dimension dim = new Dimension(0, 0); int nmembers = target.getComponentCount(); Insets insets = target.getInsets(); int numRows = 1; //the number of rows int rowSumWidth = insets.left + insets.right; //the width of the row so far int rowMaxWidth = target.getSize().width; //the width that the ToolbarLayout is in int rowHeight = 0; //the height of each row int numOnRow = 0; //the number of components on the row for (int i = 0 ; i < nmembers ; i++) { Component m = target.getComponent(i); if (m.isVisible()) { Dimension d = m.getPreferredSize(); rowHeight = Math.max(rowHeight, d.height); //make each row the height of the biggest component of all if (i > 0) { rowSumWidth += hgap;//add on the pre-spacing if this is not the first component } rowSumWidth += d.width; //add the width of the component //if it overflowed and if there are components already on this row then bump this component to next row if ((rowSumWidth + hgap) > rowMaxWidth) { if (numOnRow > 0) { numRows++; rowSumWidth = insets.left + insets.right + d.width; numOnRow = 0;//reset the number of components on the next row (we ++ no matter what later) } } numOnRow++;//add this component to the count of the number on the row } } dim.width = rowMaxWidth; dim.height = insets.top + insets.bottom + numRows*rowHeight + vgap*(numRows - 1); return dim; } } /** * Returns the minimum dimensions needed to layout the components * contained in the specified target container. * @param target the component which needs to be laid out * @return the minimum dimensions to lay out the * subcomponents of the specified container. * @see #preferredLayoutSize * @see java.awt.Container * @see java.awt.Container#doLayout */ public Dimension minimumLayoutSize(Container target) { synchronized (target.getTreeLock()) { Dimension dim = new Dimension(0, 0); int nmembers = target.getComponentCount(); for (int i = 0 ; i < nmembers ; i++) { Component m = target.getComponent(i); if (m.isVisible()) { Dimension d = m.getMinimumSize(); dim.height = Math.max(dim.height, d.height); if (i > 0) { dim.width += hgap; } dim.width += d.width; } } Insets insets = target.getInsets(); dim.width += insets.left + insets.right + hgap*2; dim.height += insets.top + insets.bottom; return dim; } } /** * Centers the elements in the specified row, if there is any slack. * @param target the component which needs to be moved * @param x the x coordinate * @param y the y coordinate * @param width the width dimensions * @param height the height dimensions * @param rowStart the beginning of the row * @param rowEnd the the ending of the row */ private void moveComponents(Container target, int x, int y, int width, int height, int rowStart, int rowEnd) { synchronized (target.getTreeLock()) { switch (align) { case LEFT: break; case CENTER: x += width / 2; break; case RIGHT: x += width; break; } for (int i = rowStart ; i < rowEnd ; i++) { Component m = target.getComponent(i); if (m.isVisible()) { m.setLocation(x, y + (height - m.getSize().height) / 2);//JDK1.2 porting: replace with getHeight() x += hgap + m.getSize().width; //JDK1.2 porting: replace with getWidth() } } } } /** * Lays out the container. This method lets each component take * its preferred size by reshaping the components in the * target container in order to satisfy the constraints of * this ToolbarLayout object. * @param target the specified component being laid out. * @see Container * @see java.awt.Container#doLayout */ public void layoutContainer(Container target) { synchronized (target.getTreeLock()) { Insets insets = target.getInsets(); int maxwidth = target.getSize().width - (insets.left + insets.right + hgap*2);//JDK1.2 porting: replace with getWidth() int nmembers = target.getComponentCount(); int x = 0, y = insets.top; int rowh = 0, start = 0; for (int i = 0 ; i < nmembers ; i++) { Component m = target.getComponent(i); if (m.isVisible()) { Dimension d = m.getPreferredSize(); m.setSize(d.width, d.height); if ((x == 0) || ((x + d.width) <= maxwidth)) { if (x > 0) { x += hgap; } x += d.width; rowh = Math.max(rowh, d.height); } else { moveComponents(target, insets.left + hgap, y, maxwidth - x, rowh, start, i); x = d.width; y += vgap + rowh; rowh = d.height; start = i; } } } moveComponents(target, insets.left + hgap, y, maxwidth - x, rowh, start, nmembers); } } /** * Returns a string representation of this ToolbarLayout * object and its values. * @return a string representation of this layout. */ public String toString() { String str = ""; switch (align) { case LEFT: str = ",align=left"; break; case CENTER: str = ",align=center"; break; case RIGHT: str = ",align=right"; break; } return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + str + "]"; } }freehep-swing-2.0.3/src/main/java/org/freehep/swing/layout/PercentLayout.java0000644012010301201030000001155410466735775030245 0ustar mascellanimascellanipackage org.freehep.swing.layout; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.LayoutManager2; import java.util.Enumeration; import java.util.Hashtable; /** * Lays out components within a Container such that each component takes a fixed percentage of the size. * * Each Component added to the Container must have a Constraint object that specifies what proportion * of the container it will fill. The Component will be stretched to fill exactly that percentage. * * @see Constraint */ public class PercentLayout implements LayoutManager2 { private Hashtable hash = new Hashtable(); public float getLayoutAlignmentX(Container p1) { return 0.5f; } public float getLayoutAlignmentY(Container p1) { return 0.5f; } public void addLayoutComponent(Component component, Object constraint) { if (constraint instanceof Constraint) { hash.put(component, constraint); } else { throw new IllegalArgumentException("Invalid constraint"); } } public void addLayoutComponent(String constraint, Component comp) { throw new IllegalArgumentException("Invalid constraint"); } public void invalidateLayout(Container p1) { } public void layoutContainer(Container p1) { Dimension size = p1.getSize(); Enumeration keys = hash.keys(); while (keys.hasMoreElements()) { Component comp = (Component) keys.nextElement(); Constraint constraint = (Constraint) hash.get(comp); int x = (int) (size.width * constraint.x / 100); int y = (int) (size.height * constraint.y / 100); int width = (int) (size.width * constraint.width / 100); int height = (int) (size.height * constraint.height / 100); comp.setBounds(x, y, width, height); } } public Dimension maximumLayoutSize(Container p1) { int maxx = Integer.MAX_VALUE; int maxy = Integer.MAX_VALUE; Enumeration keys = hash.keys(); while (keys.hasMoreElements()) { Component comp = (Component) keys.nextElement(); Constraint constraint = (Constraint) hash.get(comp); Dimension max = comp.getMaximumSize(); int mx = (max.width == Integer.MAX_VALUE) ? max.width : (int) (max.width * 100 / constraint.width); int my = (max.height == Integer.MAX_VALUE) ? max.height : (int) (max.height * 100 / constraint.height); if (mx < maxx) { maxx = mx; } if (my < maxy) { maxy = my; } } return new Dimension(maxx, maxy); } public Dimension minimumLayoutSize(Container p1) { int minx = 0; int miny = 0; Enumeration keys = hash.keys(); while (keys.hasMoreElements()) { Component comp = (Component) keys.nextElement(); Constraint constraint = (Constraint) hash.get(comp); Dimension min = comp.getMinimumSize(); int mx = (int) (min.width * 100 / constraint.width); int my = (int) (min.height * 100 / constraint.height); if (mx > minx) { minx = mx; } if (my > miny) { miny = my; } } return new Dimension(minx, miny); } public Dimension preferredLayoutSize(Container p1) { int prefx = 0; int prefy = 0; Enumeration keys = hash.keys(); while (keys.hasMoreElements()) { Component comp = (Component) keys.nextElement(); Constraint constraint = (Constraint) hash.get(comp); Dimension pref = comp.getPreferredSize(); prefx += ((pref.width * 100) / constraint.width); prefy += ((pref.height * 100) / constraint.height); } int n = hash.size(); return new Dimension(prefx / n, prefy / n); } public void removeLayoutComponent(Component component) { hash.remove(component); } public Constraint getConstraintFor(Component component) { return (Constraint) hash.get(component); } public static class Constraint { double height; double width; double x; double y; /** * Creates a Constraint Object. * @param x The X position of the top left corner of the component (0-100) * @param y The Y position of the top left corner of the component (0-100) * @param width The percentage width of the component (0-100) * @param height The percentage height of the component (0-100) */ public Constraint(double x, double y, double width, double height) { setConstraints(x,y,width,height); } public void setConstraints(double x, double y, double width, double height) { this.x = x; this.y = y; this.width = width; this.height = height; } } }freehep-swing-2.0.3/src/main/java/org/freehep/swing/layout/ConstrainedGridLayout.java0000644012010301201030000010040210466735775031713 0ustar mascellanimascellani// Charles A. Loomis, Jr., and University of California, Santa Cruz, // Copyright (c) 2000 package org.freehep.swing.layout; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.LayoutManager2; import java.awt.Rectangle; import java.awt.Window; import javax.swing.JComponent; import javax.swing.SwingUtilities; /** * The ConstrainedGridLayout layout manager is based on * the GraphPaperLayout layout manager written by Michael * Martak. * * This layout manager divides the container into a set of equally * sized cells arranged in a grid which has nw cells * in the horizontal direction and nh cells in the * vertical direction. Components can occupy an rectangular subset of * these cells; the component's position and size are based on given * rectangular constraints. * * This extends the functionality of the GraphPaperLayout * manager by also constraining the overall aspect ratio of the * container. It will also force a containing window to resize if * the desired size of the container isn't a size which is allowed by * the contraints. A byproduct of this is that the preferred sizes of * components controlled by this layout manager will be reset to the * largest allowed size which is smaller than the current size. * * Components can overlap making this layout manager a good choice for * a JLayeredPane. To allow the standard moveToFront and * moveToBack methods to work as expected, the constraints of a * removed component are retained so that if it is later added again * without contraints the layout manager will still arrange the * components reasonably. (The standard moveToFront implementation, * removes a component and re-adds it without taking into account the * possible constraints.) * * @author Charles A. Loomis, Jr. * @version $Id: ConstrainedGridLayout.java 8584 2006-08-10 23:06:37Z duns $ * */ public class ConstrainedGridLayout implements LayoutManager2 { /** * The virtual grid size. */ private Dimension gridSize; /** * The aspect ratio of the container. */ private Dimension aspectRatio; /** * The smallest dimension which maintains the aspect ratio and has * a width and height which are multiples of the grid size. */ private Dimension containerFormat; final public static String GRID_SIZE_ERROR = "Grid size must have width and height > 0."; final public static String ASPECT_RATIO_ERROR = "Aspect ratio must have width and height > 0."; final public static String CONSTRAINT_ERROR = "Constraint must be a Rectangle with positive width and height."; final public static String CONSTRAINED_GRID_LAYOUT_CONSTRAINT = "ConstrainedGridLayout.RectangularConstraint"; final public static int MINIMUM_LAYOUT = 0; final public static int PREFERRED_LAYOUT = 1; /** * Creates a ConstrainedGridLayout with the given * grid size and aspect ratio. * * @param gridSize size of grid in logical units (width x height) * @param aspectRatio aspect ratio of container (width x height) */ public ConstrainedGridLayout(Dimension gridSize, Dimension aspectRatio) { // Check that all of the dimensions given are reasonable. if (gridSize.width<=0 || gridSize.height<=0 || gridSize.width>100 || gridSize.height>100) { throw new IllegalArgumentException(GRID_SIZE_ERROR); } if (aspectRatio.width<=0 || aspectRatio.height<=0 || aspectRatio.width>100 || aspectRatio.height>100) { throw new IllegalArgumentException(ASPECT_RATIO_ERROR); } // Copy the information into the layout manager. this.gridSize = new Dimension(gridSize); this.aspectRatio = new Dimension(aspectRatio); // Calculate the minimum container format. containerFormat = new Dimension(); containerFormat = getSmallestDimension(containerFormat, aspectRatio, gridSize); } /** * Return a new Dimension which is a copy of the * current grid size. * * @return current grid size */ public Dimension getGridSize() { return new Dimension(gridSize); } /** * Set the current grid size to the given Dimension. * The grid size must have horizontal and vertical components * which are positive. * * @param gridSize new grid size */ public void setGridSize(Dimension gridSize) { if (gridSize.width<=0 || gridSize.height<=0 || gridSize.width>100 || gridSize.height>100) { throw new IllegalArgumentException(GRID_SIZE_ERROR); } this.gridSize.setSize(gridSize); // Get the smallest fraction which keeps the aspect ratio and // grid size. containerFormat = getSmallestDimension(containerFormat, aspectRatio, gridSize); } /** * Return a new Dimension which is a copy of the * current aspect ratio. * * @return current aspect ratio */ public Dimension getAspectRatio() { return new Dimension(aspectRatio); } /** * Set the current aspect ratio to the given * Dimension. The aspect ratio must have horizontal * and vertical components which are positive. * * @param aspectRatio new aspect ratio for the container */ public void setAspectRatio(Dimension aspectRatio) { if (aspectRatio.width<=0 || aspectRatio.height<=0) { throw new IllegalArgumentException(ASPECT_RATIO_ERROR); } this.aspectRatio.setSize(aspectRatio); // Get the smallest fraction which keeps the aspect ratio and // grid size. containerFormat = getSmallestDimension(containerFormat, aspectRatio, gridSize); } /** * Get the constraints being used for the given component. * * @param comp the component to lookup * * @return Rectangle describing the position and size * of the given component */ public Rectangle getConstraints(Component comp) { Rectangle r = null; if (comp instanceof JComponent) { JComponent jc = (JComponent) comp; Object constraint = jc.getClientProperty(CONSTRAINED_GRID_LAYOUT_CONSTRAINT); if (constraint instanceof Rectangle) { r = (Rectangle) constraint; } } return (r!=null) ? new Rectangle(r) : null; } /** * Set (or reset) the constraints for the given component. * * @param comp the component to constrain * @param constraints Rectangle describing the * position and size of the component */ public void setConstraints(Component comp, Rectangle constraints) { if (comp instanceof JComponent) { Rectangle copy = new Rectangle(constraints); JComponent jc = (JComponent) comp; jc.putClientProperty(CONSTRAINED_GRID_LAYOUT_CONSTRAINT, copy); } } /** * Adds the specified component with the specified name to the * layout. ConstrainedGridLayout will arrange this * component normally if a constraint has been set previously or * is set before the container is next validated. If not, then * this component will be ignored by this layout manager. * * The component name is always ignored by this layout manager. * * @param name name of component (ignored) * @param comp component to add to the layout */ public void addLayoutComponent(String name, Component comp) { } /** * Removes the specified component from the layout. This method * actually does nothing since the component list is obtained from * the container when it is laid-out. * * The constraint is still stored in case the component is later * added again to the container without the constraint being * specified. (Happens when the standard implementation of * moveToFront in a JLayeredPane is called.) * * @param comp the component to be removed */ public void removeLayoutComponent(Component comp) { } /** * Calculates the preferred size dimensions for the specified * panel given the components in the specified parent container. * * @param parent the component to be laid out * * @see #minimumLayoutSize */ public Dimension preferredLayoutSize(Container parent) { return getLayoutSize(parent, PREFERRED_LAYOUT); } /** * Calculates the minimum size dimensions for the specified * panel given the components in the specified parent container. * * @param parent the component to be laid out * * @see #preferredLayoutSize */ public Dimension minimumLayoutSize(Container parent) { return getLayoutSize(parent, MINIMUM_LAYOUT); } /** * Calculate the largest minimum or preferred cell size. * * For the minimum or preferred cell sizes: The components' * minimum or preferred sizes are obtained and then divided by the * number of rows and columns that the component spans. The * largest cell size is returned. * * @param parent the container in which to do the layout. * @param selectionFlag either MINIMUM_LAYOUT or PREFERRED_LAYOUT. * * @return the appropriate cell size */ protected Dimension getLayoutSize(Container parent, int selectionFlag) { // Keep track of the cell size. int cellHeight = 0; int cellWidth = 0; // Loop over all of the parent's components. for (int i=0; iDimension is modified and returned rather than * creating a new object. * * @param trialSize parent's size minus insets to adjust; * trialSize is overwritten with the adjusted size of the * component * * @return boolean flag indicating whether the size was actually * changed */ public boolean adjustSize(Dimension trialSize) { int originalWidth = trialSize.width; int originalHeight = trialSize.height; int widthMultiple = Math.max(1,trialSize.width/containerFormat.width); int heightMultiple = Math.max(1,trialSize.height/containerFormat.height); int finalMultiple = Math.min(widthMultiple, heightMultiple); trialSize.width = containerFormat.width*finalMultiple; trialSize.height = containerFormat.height*finalMultiple; return (originalWidth!=trialSize.width || originalHeight!=trialSize.height); } /** * Change the size of the component by the given increment in the * size. Positive increments enlarge the component; negative * increments reduce the component. * * @param parent the component controlled by this layout manager * @param sizeIncrement number of increments by which to increase * the size * * @return flag indicating whether the size actually changed */ public boolean adjustSize(Container parent, int sizeIncrement) { boolean sizeChanged = false; if (parent instanceof JComponent) { JComponent jc = (JComponent) parent; Insets insets = jc.getInsets(); Dimension size = jc.getSize(); size.width -= (insets.left+insets.right); size.height -= (insets.top+insets.bottom); int originalMultiple = size.width/containerFormat.width; int newMultiple = Math.max(1,originalMultiple+sizeIncrement); if (originalMultiple!=newMultiple) { size.width = containerFormat.width*newMultiple; size.height = containerFormat.height*newMultiple; // Add in the insets again. size.width += (insets.left+insets.right); size.height += (insets.top+insets.bottom); // Set the preferred size. sizeChanged = true; jc.setPreferredSize(size); } } // If another validation is needed, then tell the window // containing this container. if (sizeChanged) SwingUtilities.invokeLater(new RunAnotherLayout(parent)); return sizeChanged; } /** * Lays out the container in the specified container. * * @param parent the component which needs to be laid out */ public void layoutContainer(Container parent) { // Flag used to indicate that the constraints caused this // layout manager to set the size of the component to a // smaller one than requested. Force the containing window to // layout its contents again. boolean needAnotherLayout = false; // Lock the component tree while the layout is in progress. synchronized (parent.getTreeLock()) { // Get the number of components and the parent's insets. int n = parent.getComponentCount(); Insets insets = parent.getInsets(); // Total size of the parent without the insets. Dimension size = parent.getSize(); size.width -= (insets.left+insets.right); size.height -= (insets.top+insets.bottom); // Adjust the size for the constraints (component size // and aspect ratio). If an adjustment is made then // the layout will need to be done again. (But only // do this if it is a JComponent, otherwise this will // just cause an infinite loop.) if (parent instanceof JComponent) { JComponent jc = (JComponent) parent; needAnotherLayout = adjustSize(size); // Set the parent's preferred size. if (needAnotherLayout) { // Calculate the full size of parent. Dimension fullSize = new Dimension(size); fullSize.width += (insets.left+insets.right); fullSize.height += (insets.top+insets.bottom); jc.setPreferredSize(fullSize); } } if (n>0) { // Calculate the cell dimensions. Dimension cellSize = new Dimension(size.width/gridSize.width, size.height/gridSize.height); // Now resize the components. for (int i=0; iRectangle */ public void addLayoutComponent(Component comp, Object constraints) { if (constraints instanceof Rectangle) { Rectangle r = (Rectangle) constraints; if (r.width<=0 || r.height<=0) { throw new IllegalArgumentException(CONSTRAINT_ERROR); } // Go ahead and put in the given constraints. setConstraints(comp, r); } else if (constraints != null) { throw new IllegalArgumentException(CONSTRAINT_ERROR); } } /** * Returns the maximum size of this component. This just returns * the largest size possible. * * @see java.awt.Component#getMinimumSize() * @see java.awt.Component#getPreferredSize() * @see LayoutManager */ public Dimension maximumLayoutSize(Container target) { return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); } /** * Returns the alignment along the x axis. This specifies how the * component would like to be aligned relative to other * components. The value should be a number between 0 and 1 where * 0 represents alignment along the origin, 1 is aligned the * furthest away from the origin, 0.5 is centered, etc. * * This just returns the centering alignment (0.5). */ public float getLayoutAlignmentX(Container target) { return 0.5f; } /** * Returns the alignment along the y axis. This specifies how the * component would like to be aligned relative to other * components. The value should be a number between 0 and 1 where * 0 represents alignment along the origin, 1 is aligned the * furthest away from the origin, 0.5 is centered, etc. * * This just returns the centering alignment. */ public float getLayoutAlignmentY(Container target) { return 0.5f; } /** * Invalidates the layout, indicating that if the layout manager * has cached information it should be discarded. */ public void invalidateLayout(Container target) { } /** * The first prime numbers up to 100. */ final private static int[] primes = { 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}; /** * The prime factorizations of the numbers up to 100. */ final private static int[][] factorization = { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,2,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,3,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, {1,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0}, {1,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,2,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, {1,1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0}, {1,2,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0}, {1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,2,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0}, {1,2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0}, {1,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0}, {1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,2,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0}, {1,4,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0}, {1,2,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, {1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, {1,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,2,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0}, {1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,1,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {1,2,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; /** * Get the smallest dimension which maintains the aspect ratio and * has a width and height which is evenly divisible by the grid * size. */ private static Dimension getSmallestDimension(Dimension containerFormat, Dimension aspectRatio, Dimension gridSize) { int[] widthFactors = new int[primes.length]; int[] widthCommonDenominator = new int[primes.length]; int[] heightFactors = new int[primes.length]; int[] heightCommonDenominator = new int[primes.length]; // Make the prime factorization for the product. primeFactorsOfProduct(widthFactors, aspectRatio.width, gridSize.width, gridSize.height); primeFactorsOfProduct(heightFactors, aspectRatio.height, gridSize.width, gridSize.height); // Get the least common denominator for the width and height. leastCommonDenominator(widthCommonDenominator, aspectRatio.width, gridSize.width); leastCommonDenominator(heightCommonDenominator, aspectRatio.height, gridSize.height); // Remove the common factors. removeFactors(widthFactors, widthCommonDenominator); removeFactors(heightFactors, heightCommonDenominator); removeCommonFactors(widthFactors,heightFactors); // Put back in the common denominators. addFactors(widthFactors, widthCommonDenominator); addFactors(heightFactors, heightCommonDenominator); // Return the modified dimension. containerFormat.setSize(product(widthFactors), product(heightFactors)); return containerFormat; } private static void primeFactorsOfProduct(int[] result, int a, int b, int c) { int[] factorsA = factorization[a]; int[] factorsB = factorization[b]; int[] factorsC = factorization[c]; for (int i=0; i Layout managers for swing. freehep-swing-2.0.3/src/main/java/org/freehep/swing/layout/FlowScrollLayout.java0000644012010301201030000002646210466735775030737 0ustar mascellanimascellanipackage org.freehep.swing.layout; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.LayoutManager2; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import javax.swing.JComponent; import javax.swing.JScrollPane; import javax.swing.JViewport; /** This class is a replacement for a FlowLayout inside a JScrollPane. * It can be used as a plain FlowLayout, but it is intended to be * used on a container inside a JScrollPane. If it is the layout for * a Container that is the view of a JViewport inside a JScrollPane, * then it will cause the Container's children to be wrapped so that * the JScrollPane only scrolls vertically. *

* * It can optionally resize all children on each row to be as tall as * the tallest one. IMHO, this often looks better, but is off by * default for compatiblity with FlowLayout. * *

* Note:Each FlowScrollLayout should be used for only one Container. *

* Bug:The JViewport inside the JScrollPane that you give to * FlowScrollLayout must have a child during the whole time that * FlowScrollLayout is used with that JScrollPane. (Typically, that * child is the widget whose layout is the FlowScrollLayout.) * Otherwise FlowScrollLayout will throw a NullPointerException. It * should handle this condition gracefully, but I do not have time to * fix it right now. If anyone wants to send me a patch, it would be * welcome. *

* This software is distributed under the * * Berkeley Software License. * * @author This was written by A. Chris Long (but modified for FreeHEP) * @version $Id: FlowScrollLayout.java 8584 2006-08-10 23:06:37Z duns $ */ public class FlowScrollLayout extends FlowLayout implements ComponentListener, LayoutManager2 { private JScrollPane scroller = null; private boolean uniformHeight; private boolean firstTime = true; public FlowScrollLayout() { this(null); } public FlowScrollLayout(JScrollPane scrollPane) { this(scrollPane, false); } public FlowScrollLayout(JScrollPane scrollPane, boolean uniformHeight) { super(); setScrollPane(scrollPane); this.uniformHeight = uniformHeight; } public void setScrollPane(JScrollPane scrollPane) { if (scrollPane != scroller) { if (scroller != null) { scroller.removeComponentListener(this); } scroller = scrollPane; if (scroller != null) { scroller.addComponentListener(this); } } } /** If uniformHeight is turned on, all widgets on each row will have * their preferred height set to the height of the tallest one * (based on preferredSize). */ public void setUniformHeight(boolean on) { if (uniformHeight != on) { uniformHeight = on; if (scroller != null) { scroller.doLayout(); } } } public boolean isUniformHeight() { return uniformHeight; } /** Follow the layout algorithm that FlowLayout uses to compute how * big we would like to be, given the size of the containing * JScrollPane. Should not be called unless a non-null JScrollPane * has been specified in the constructor or with setScrollPane. */ protected Dimension computeDesiredSize() { JViewport viewport = scroller.getViewport(); Dimension extent = viewport.getExtentSize(); Component child = viewport.getView(); if (child instanceof Container) { Container container = (Container) child; Insets insets = container.getInsets(); int vgap = getVgap(); int hgap = getHgap(); int maxAllowedWidth = extent.width - (insets.left + insets.right + hgap*2); int numComponents = container.getComponentCount(); int x = 0; int y = insets.top + vgap; int rowh = 0; int maxRowWidth = 0; int start = 0; for (int i = 0; i < numComponents; i++) { Component comp = container.getComponent(i); if (comp.isVisible()) { Dimension dim = comp.getPreferredSize(); if ((x == 0) || ((x + dim.width) <= maxAllowedWidth)) { if (x > 0) { x += hgap; } x += dim.width; rowh = Math.max(rowh, dim.height); } else { if (uniformHeight) { setHeights(container, rowh, start, i); } if (x > (maxRowWidth - hgap)) { maxRowWidth = x + hgap; } x = dim.width; y += vgap + rowh; rowh = dim.height; start = i; } } } if (uniformHeight) { setHeights(container, rowh, start, numComponents); } if (x > (maxRowWidth - hgap)) { maxRowWidth = x + hgap; } y += vgap + rowh + insets.bottom; return new Dimension(maxRowWidth, y); } else if (child != null) { Dimension prefSize = child.getPreferredSize(); return new Dimension(extent.width, prefSize.height); } else return extent; } /** Set the preferred size of all JComponents inside container to * have height height, starting at the startIndex'th child and * going up to endIndex-1. */ public static void setHeights(Container container, int height, int startIndex, int endIndex) { for (int i = startIndex; i < endIndex; i++) { Component comp = container.getComponent(i); if (comp instanceof JComponent) { setPreferredHeight((JComponent) comp, height); } } } /** Set preferredSize of comp to be Dimension(current preferredSize.width, height) */ public static void setPreferredHeight(JComponent comp, int height) { Dimension prefSize = comp.getPreferredSize(); prefSize.height = height; comp.setPreferredSize(prefSize); } /** Update the layout of the managed widget and the containing * scrollbar (only if the current size doesn't match the desired * size) */ protected void updateLayout() { if (scroller != null) { JViewport viewport = scroller.getViewport(); Dimension viewSize = viewport.getViewSize(); Dimension extentSize = viewport.getExtentSize(); Dimension desiredSize = computeDesiredSize(); if ((viewSize.width != extentSize.width) || (viewSize.height != desiredSize.height)) { // all is not right, so update sizes Dimension newSize = new Dimension(Math.max(desiredSize.width, extentSize.width), Math.max(desiredSize.height, extentSize.height)); Component child = viewport.getView(); if (child instanceof JComponent) { ((JComponent) child).setPreferredSize(newSize); } viewport.setViewSize(newSize); // You might think that when the preferred size of the child and // the view size of the viewport change that things would // automatically update. But they don't. So... if (!firstTime) { child.doLayout(); scroller.doLayout(); } } } } public void layoutContainer(Container c) { if (firstTime) { updateLayout(); firstTime = false; } super.layoutContainer(c); } public void componentResized(ComponentEvent e) { updateLayout(); } public void componentMoved(ComponentEvent e) { } public void componentShown(ComponentEvent e) { } public void componentHidden(ComponentEvent e) { } public void invalidateLayout(Container target) { firstTime = true; } public float getLayoutAlignmentY(Container target) { return 0.5f; } /** * Returns the alignment along the x axis. This specifies how * the component would like to be aligned relative to other * components. The value should be a number between 0 and 1 * where 0 represents alignment along the origin, 1 is aligned * the furthest away from the origin, 0.5 is centered, etc. */ public float getLayoutAlignmentX(Container target) { return 0.5f; } /** * Returns the maximum size of this component. * @see java.awt.Component#getMinimumSize() * @see java.awt.Component#getPreferredSize() * @see LayoutManager */ public Dimension maximumLayoutSize(Container target) { return preferredLayoutSize(target); } /** * Adds the specified component to the layout, using the specified * constraint object. * @param comp the component to be added * @param constraints where/how the component is added to the layout. */ public void addLayoutComponent(Component comp,Object constraints) { } } /* Copyright (c) 2000 Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed by the Group for User Interface Research at the University of California at Berkeley. 4. The name of the University may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. */ freehep-swing-2.0.3/src/main/java/org/freehep/swing/layout/TableLayout.java0000644012010301201030000004362310466735775027676 0ustar mascellanimascellani// Copyright 2003, FreeHEP. package org.freehep.swing.layout; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * This layoutmanager uses all of the GridBagLayout's managers functionality * and power but allows you to set the options easily. It will construct * the GridBagConstraints object for you. * * To use it, set the layout manager for your Container to TableLayout and * add each component with a name string for which the format is specified * below: * * "gridx gridy gridwidth gridheight ( ipadx ipady ) [ top left bottom right ] { weightx weighty} options" * * you may use spaces or commas as separators. * * gridx and gridy are mandatory, can be * for RELATIVE * gridwidth and gridheight are optional, can be * for REMAINDER * ipadx and ipady are optional * insets (top...right) are optional * weights are optional and override any settings made to them by the options * options are optional * * Options may contain a set of characters which will set the corresponding * flag to true. If not set, the flag is false. * * "r" right align * "l" left align * "t" top align * "b" bottom align * if none of these are set the component is placed in the center. * * "w" resize both cell and component in width * "W" resize only cell in width * "h" resize both cell and component in height * "H" resize only cell in height * if none of these are set neither the component nor the cell is not resized. * and the extra space is put on the outside of the table. * * The weight is calculated as follows, if not set explicitly by the {weight} section: * 1 if character set, fill is set if lowercase. * * You may construct a TableLayout with some default name string. * * @author Mark Donszelmann * @version $Id: TableLayout.java 8584 2006-08-10 23:06:37Z duns $ */ public class TableLayout extends GridBagLayout { // defaults are relative, single row and column, no padding or insets, center // resizing is done for both components and cells. public static final String NO_RESIZE = "* * 1 1 (0, 0) [0, 0, 0, 0] {0.0, 0.0}"; public static final String RESIZE_WIDTH = "* * 1 1 (0, 0) [0, 0, 0, 0] {1.0, 0.0} w"; public static final String RESIZE_HEIGHT = "* * 1 1 (0, 0) [0, 0, 0, 0] {0.0, 1.0} h"; public static final String RESIZE_BOTH = "* * 1 1 (0, 0) [0, 0, 0, 0] {1.0, 1.0} wh"; public static final String LEFT = "0 * [5 15 5 15] r"; public static final String RIGHT = "1 * [5 15 5 15] lw"; public static final String VERY_LEFT = "0 * [5 0 5 15] r"; public static final String VERY_RIGHT = "1 * [5 15 5 0] lw"; public static final String FULL = "0 * * 1 [5 15 5 15] w"; public static final String COLUMN = "0 * wt"; public static final String COLUMN_FILL = "0 * wh"; private GridBagConstraints defaults; public TableLayout() { this(NO_RESIZE); } public TableLayout(String defaultOptions) { super(); defaults = getGridBagConstraints(defaultOptions); if (defaults == null) { usage(); defaults = new GridBagConstraints(); System.err.println("Using Default GridBagConstraints."); } } public void usage() { System.err.println("Usage: gridx gridy gridwidth gridheight ( ipadx ipady ) [ top left bottom right ] { weightx weighty} options"); System.err.println(); System.err.println("you may use spaces or commas as separators."); System.err.println(); System.err.println(" gridx and gridy are mandatory, can be * for RELATIVE"); System.err.println(" gridwidth and gridheight are optional, can be * for REMAINDER"); System.err.println(" ipadx and ipady are optional"); System.err.println(" insets (top...right) are optional"); System.err.println(" weights are optional and override any settings made to them by the options"); System.err.println(" options are optional"); System.err.println(); System.err.println("Options may contain a set of characters which will set the corresponding"); System.err.println("flag to true. If not set, the flag is false."); System.err.println(); System.err.println(" \"r\" right align"); System.err.println(" \"l\" left align"); System.err.println(" \"t\" top align"); System.err.println(" \"b\" bottom align"); System.err.println("if none of these are set the component is placed in the center."); System.err.println(); System.err.println(" \"w\" resize both cell and component in width"); System.err.println(" \"W\" resize only cell in width"); System.err.println(" \"h\" resize both cell and component in height"); System.err.println(" \"H\" resize only cell in height"); System.err.println("if none of these are set neither the component nor the cell is not resized."); System.err.println("and the extra space is put on the outside of the table."); System.err.println(); System.err.println("The weight is calculated as follows, if not set explicitly by the {weight} section:"); System.err.println("1.0 if character set, fill is set if lowercase."); System.err.println(); } public void addLayoutComponent(String name, Component component) { addLayoutComponent(component, name); } public void addLayoutComponent(Component component, Object constraints) { if (constraints instanceof String) { constraints = getGridBagConstraints((String)constraints); if (constraints == null) { usage(); constraints = new GridBagConstraints(); System.err.println("Using Default GridBagConstraints."); } } super.addLayoutComponent(component, constraints); } public String toString() { return "[TableLayout: "+super.toString()+"]"; } protected GridBagConstraints getGridBagConstraints(String name) { return getGridBagConstraints(name, defaults); } public static GridBagConstraints getGridBagConstraints(String name, GridBagConstraints def) { // optional whitespace String ws = "\\s*"; // whitespace or comma String s = "[\\s,]+"; // integer String d = "[+-]?\\d+"; // grouped integer String gd = "([+-]?\\d+)"; // grouped row column span String gdstar = "((?:"+d+")|\\*)"; // grouped float String gf = "([+-]?\\d*(?:\\.\\d*)?)"; // gouped options String go = "([tlbrWwHh]*)"; // gridx gridy gridwidth gridheight // 0 1 2 3 String coordPattern = ws+gdstar+s+gdstar+"(?:"+s+gdstar+s+gdstar+")?"; // ( ipadx ipady ) // 4 5 String ipadPattern = ws+"(?:\\("+ws+gd+s+gd+ws+"\\))?"; // [ top left bottom right ] // 6 7 8 9 String insetsPattern = ws+"(?:\\["+ws+gd+s+gd+s+gd+s+gd+ws+"\\])?"; // { weightx weigthy } // 10 11 String weightPattern = ws+"(?:\\{"+ws+gf+s+gf+ws+"\\})?"; // options // 12 String optionPattern = ws+go; // rest String restPattern = ws+"(.*)"; Pattern pattern = Pattern.compile(coordPattern + ipadPattern + insetsPattern + weightPattern +optionPattern + restPattern); Matcher matcher = pattern.matcher(name); int nArgs = 14; if (!matcher.find()) { if (matcher.groupCount() != nArgs) { System.err.println("Expected "+nArgs+" arguments, but got "+matcher.groupCount()+" in '"+name+"'."); } else { System.err.println("Cannot parse '"+name+"'."); } return null; } try { // non optional int gridx = getPosition(matcher.group(1)); int gridy = getPosition(matcher.group(2)); // optional int gridwidth = matcher.group(3) != null ? getSpan(matcher.group(3)) : def.gridwidth; int gridheight = matcher.group(4) != null ? getSpan(matcher.group(4)) : def.gridheight; int ipadx = matcher.group(5) != null ? Integer.parseInt(matcher.group(5)) : def.ipadx; int ipady = matcher.group(6) != null ? Integer.parseInt(matcher.group(6)) : def.ipady; Insets insets; if (matcher.group(7) != null) { insets = new Insets(Integer.parseInt(matcher.group(7)), Integer.parseInt(matcher.group(8)), Integer.parseInt(matcher.group(9)), Integer.parseInt(matcher.group(10))); } else { insets = def.insets; } double weightx = matcher.group(11) != null ? Double.parseDouble(matcher.group(11)) : def.weightx; double weighty = matcher.group(12) != null ? Double.parseDouble(matcher.group(12)) : def.weighty; String options = matcher.group(13); int anchor = (def != null) ? def.anchor : GridBagConstraints.CENTER; int fill = (def != null) ? def.fill : GridBagConstraints.NONE ; if (options != null) { int position = 0x00; if ((options.indexOf('l') >= 0) && (options.indexOf('r') < 0)) { position |= 0x10; } if ((options.indexOf('r') >= 0) && (options.indexOf('l') < 0)) { position |= 0x20; } if ((options.indexOf('t') >= 0) && (options.indexOf('b') < 0)) { position |= 0x01; } if ((options.indexOf('b') >= 0) && (options.indexOf('t') < 0)) { position |= 0x02; } switch(position) { default: case 0x00: break; case 0x01: anchor = GridBagConstraints.NORTH; break; case 0x02: anchor = GridBagConstraints.SOUTH; break; case 0x10: anchor = GridBagConstraints.WEST; break; case 0x11: anchor = GridBagConstraints.NORTHWEST; break; case 0x12: anchor = GridBagConstraints.SOUTHWEST; break; case 0x20: anchor = GridBagConstraints.EAST; break; case 0x21: anchor = GridBagConstraints.NORTHEAST; break; case 0x22: anchor = GridBagConstraints.SOUTHEAST; break; } boolean fillWidth, fillHeight; switch(fill) { default: case GridBagConstraints.NONE: fillWidth = false; fillHeight = false; break; case GridBagConstraints.HORIZONTAL: fillWidth = true; fillHeight = false; break; case GridBagConstraints.VERTICAL: fillWidth = false; fillHeight = true; break; case GridBagConstraints.BOTH: fillWidth = true; fillHeight = true; break; } if (options.indexOf('w') >= 0) { fillWidth = true; if (matcher.group(11) == null) { weightx = 1.0; } } if (options.indexOf('W') >= 0) { if (matcher.group(11) == null) { weightx = 1.0; } } if (options.indexOf('h') >= 0) { fillHeight = true; if (matcher.group(12) == null) { weighty = 1.0; } } if (options.indexOf('H') >= 0) { if (matcher.group(12) == null) { weighty = 1.0; } } if (fillWidth) { if (fillHeight) { fill = GridBagConstraints.BOTH; } else { fill = GridBagConstraints.HORIZONTAL; } } else if (fillHeight) { fill = GridBagConstraints.VERTICAL; } if ((matcher.group(14) != null) && !matcher.group(14).equals("")) { System.err.println("Cannot parse: '"+matcher.group(14)+"' in '"+name+"'."); return null; } } return new TableConstraints( gridx, gridy, gridwidth, gridheight, weightx, weighty, anchor, fill, insets, ipadx, ipady ); } catch (NumberFormatException nfe) { System.err.println("Problem "+nfe.getMessage()+" in '"+name+"'."); return null; } } private static int getPosition(String position) { if (position.equals("*")) { return GridBagConstraints.RELATIVE; } return Integer.parseInt(position); } private static int getSpan(String span) { if (span.equals("*")) { return GridBagConstraints.REMAINDER; } return Integer.parseInt(span); } public static String toString(GridBagConstraints c) { StringBuffer s = new StringBuffer(); s.append(c.gridx == TableConstraints.RELATIVE ? "*" : String.valueOf(c.gridx)); s.append(" "); s.append(c.gridy == TableConstraints.RELATIVE ? "*" : String.valueOf(c.gridy)); s.append(" "); s.append(c.gridwidth == TableConstraints.REMAINDER ? "*" : String.valueOf(c.gridwidth)); s.append(" "); s.append(c.gridheight == TableConstraints.REMAINDER ? "*" : String.valueOf(c.gridheight)); s.append(" ("); s.append(String.valueOf(c.ipadx)); s.append(" "); s.append(String.valueOf(c.ipady)); s.append(") ["); s.append(String.valueOf(c.insets.top)); s.append(" "); s.append(String.valueOf(c.insets.left)); s.append(" "); s.append(String.valueOf(c.insets.bottom)); s.append(" "); s.append(String.valueOf(c.insets.right)); s.append("] {"); s.append(String.valueOf(c.weightx)); s.append(" "); s.append(String.valueOf(c.weighty)); s.append("} "); switch (c.anchor) { default: break; case GridBagConstraints.CENTER: break; case GridBagConstraints.NORTH: s.append("t"); break; case GridBagConstraints.NORTHWEST: s.append("tl"); break; case GridBagConstraints.WEST: s.append("l"); break; case GridBagConstraints.SOUTHWEST: s.append("bl"); break; case GridBagConstraints.SOUTH: s.append("b"); break; case GridBagConstraints.SOUTHEAST: s.append("br"); break; case GridBagConstraints.EAST: s.append("r"); break; case GridBagConstraints.NORTHEAST: s.append("tr"); break; } switch (c.fill) { default: break; case GridBagConstraints.NONE: if (c.weightx == 1.0) s.append("W"); if (c.weighty == 1.0) s.append("H"); break; case GridBagConstraints.HORIZONTAL: s.append("w"); if (c.weighty == 1.0) s.append("H"); break; case GridBagConstraints.VERTICAL: if (c.weightx == 1.0) s.append("W"); s.append("h"); break; case GridBagConstraints.BOTH: s.append("wh"); break; } return s.toString(); } public static class TableConstraints extends GridBagConstraints { public TableConstraints() { super(); } public TableConstraints(int gridx, int gridy, int gridwidth, int gridheight, double weightx, double weighty, int anchor, int fill, Insets insets, int ipadx, int ipady) { super(gridx, gridy, gridwidth, gridheight, weightx, weighty, anchor, fill, insets, ipadx, ipady); } public String toString() { return "TableConstraints: "+TableLayout.toString(this); } } public static void main(String args[]) { TableLayout layout = new TableLayout(); System.out.println(layout.getGridBagConstraints("1 2 3 4 (5 6) [7 8 9 10] {11 12} tlwh")); System.out.println(layout.getGridBagConstraints("1 2 3 4 [7 8 9 10] {11 12} trWh")); System.out.println(layout.getGridBagConstraints("1 2 3 4 (5 6) {11 12} tlwH")); System.out.println(layout.getGridBagConstraints("1 2 3 4 (5 6) [7 8 9 10] brwh")); System.out.println(layout.getGridBagConstraints("1 2 3 4 (5 6) tlWh")); System.out.println(layout.getGridBagConstraints("1 2 3 4")); System.out.println(layout.getGridBagConstraints("1 2")); System.out.println(layout.getGridBagConstraints("* * 2 4")); System.out.println(layout.getGridBagConstraints("* 0 2 4")); System.out.println(layout.getGridBagConstraints("0 * * *")); System.out.println(layout.getGridBagConstraints("0 0 * 4")); } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/ExtensionFileFilter.java0000644012010301201030000001425210466735775030052 0ustar mascellanimascellanipackage org.freehep.swing; import java.io.File; import java.util.Iterator; import java.util.LinkedList; import javax.swing.filechooser.FileFilter; /** * A FileFilter which filters out all files except those which end with the * given tag. This filter is case sensitive and the string is compared * literally. * * You may add extensions with or without the leading dot. The comparison * always uses the leading dot. * * Long extensions such as ".heprep.zip" are also allowed. * * Example - create a new filter that filerts out all files * but gif and jpg image files: * *

 *     JFileChooser chooser = new JFileChooser();
 *     ExtensionFileFilter filter = new ExtensionFileFilter(
 *                   new String{".gif", ".jpg"}, "JPEG & GIF Images")
 *     chooser.addChoosableFileFilter(filter);
 *     chooser.showOpenDialog(this);
 * 
* * Based on the ExtensionFileFilter written by Jeff Dinkins and provided by * Sun. * * @author Charles A. Loomis, Jr. * @author Mark Donszelmann * @version $Id: ExtensionFileFilter.java 8584 2006-08-10 23:06:37Z duns $ */ public class ExtensionFileFilter extends FileFilter { // private static String TYPE_UNKNOWN = "Type Unknown"; // private static String HIDDEN_FILE = "Hidden File"; private String description = null; private String fullDescription = null; private boolean useExtensionsInDescription = true; private LinkedList endings = null; /** * Creates a file filter. If no filters are added, then all * files are rejected. * * @see #addExtension */ public ExtensionFileFilter() { this.endings = new LinkedList(); } /** * Creates a file filter that accepts files with the given ending. * * @see #addExtension */ public ExtensionFileFilter(String extension) { this(extension, null); } /** * Creates a file filter that accepts the files with the given endings. * * @see #addExtension */ public ExtensionFileFilter(String extension, String description) { this(); if (extension!=null) addExtension(extension); if (description!=null) setDescription(description); } /** * Creates a file filter from the array of given endings. * * @see #addExtension */ public ExtensionFileFilter(String[] filters) { this(filters, null); } /** * Creates a file filter from the given string array and description. * * @see #addExtension */ public ExtensionFileFilter(String[] filters, String description) { this(); for (int i = 0; i < filters.length; i++) { // add filters one by one addExtension(filters[i]); } if (description!=null) setDescription(description); } /** * Return true if this file should be shown in the directory pane, * false if it shouldn't. * * @see FileFilter#accept */ public boolean accept(File f) { if (f!=null) { if (f.isDirectory()) return true; if (match(f)) return true; } return false; } /** * This determines if the file matches any of the extensions. */ protected boolean match(File f) { return (getExtension(f) != null); } /** * Returns the extension portion of the files name (if part of this file filter). * * @return extension including leading ".", or null if not found in filter. */ public String getExtension(File f) { if (f!=null) { String filename = f.getName(); Iterator i = endings.iterator(); while (i.hasNext()) { String end = (String) i.next(); if (filename.endsWith(end)) return end; } } return null; } /** * Adds an extension to filter against. * Leading "." is not mandatory. */ public void addExtension(String extension) { endings.add(extension.startsWith(".") ? extension : "."+extension); fullDescription = null; } /** * Returns the human readable description of this filter. For * example: "JPEG and GIF Image Files (*.jpg, *.gif)" * * @see #setDescription * @see #setExtensionListInDescription * @see #isExtensionListInDescription * @see FileFilter#getDescription */ public String getDescription() { if (fullDescription == null) { if (description == null || isExtensionListInDescription()) { fullDescription = description==null ? "(" : description + " ("; // build the description from the extension list Iterator i = endings.iterator(); while (i.hasNext()) { fullDescription += (String) i.next(); if (i.hasNext()) fullDescription += ", "; } fullDescription += ")"; } else { fullDescription = description; } } return fullDescription; } /** * Sets the human readable description of this filter. For * example: filter.setDescription("Gif and JPG Images"); * * @see #setDescription * @see #setExtensionListInDescription * @see #isExtensionListInDescription */ public void setDescription(String description) { this.description = description; fullDescription = null; } /** * Determines whether the extension list (.jpg, .gif, etc) should * show up in the human readable description. * * Only relevent if a description was provided in the constructor * or using setDescription(); * * @see #getDescription * @see #setDescription * @see #isExtensionListInDescription */ public void setExtensionListInDescription(boolean b) { useExtensionsInDescription = b; fullDescription = null; } /** * Returns whether the extension list (.jpg, .gif, etc) should * show up in the human readable description. * * Only relevent if a description was provided in the constructor * or using setDescription(); * * @see #getDescription * @see #setDescription * @see #setExtensionListInDescription */ public boolean isExtensionListInDescription() { return useExtensionsInDescription; } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/ErrorDialog.java0000644012010301201030000000723510466735775026344 0ustar mascellanimascellanipackage org.freehep.swing; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.JTextArea; import javax.swing.SwingUtilities; import javax.swing.WindowConstants; /** * A utility for displaying errors in dialogs. * @author Tony Johnson */ public class ErrorDialog { private ErrorDialog() { } /** * Creates a dialog which will display a message to the user. * If a Throwable is provided the user can click the "Details" button to * get a full stack trace, including any nested errors ("caused by"). * @param source The parent component to be used for the dialog (may be null) * @param message The message to be displayed in the dialog * @param detail The exception that caused the error (may be null) */ public static void showErrorDialog(Component source, Object message, final Throwable detail) { final JButton details = new JButton("Details..."); details.setEnabled(detail != null); details.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JDialog owner = (JDialog) SwingUtilities.getAncestorOfClass(JDialog.class,details); ErrorDetailsDialog dlg = new ErrorDetailsDialog(owner,detail); dlg.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); dlg.pack(); dlg.setLocationRelativeTo(owner); dlg.setVisible(true); } }); if (source != null) source.getToolkit().beep(); Object[] options = { "OK" , details }; JOptionPane.showOptionDialog(source,message,"Error...",JOptionPane.DEFAULT_OPTION,JOptionPane.ERROR_MESSAGE,null,options,options[0]); } public static class ErrorDetailsDialog extends JDialog { public ErrorDetailsDialog(JDialog owner, Throwable detail) { super(owner); JComponent messageComponent = null; JTabbedPane tabs = null; Throwable ex = detail; for (; ex != null;) { JTextArea ta = new JTextArea(); ta.append(ex+"\n"); StackTraceElement[] trace = ex.getStackTrace(); for (int i=0; i= 0; i -= 2) { if (listeners[i] == TreeModelListener.class) { // Lazily create the event: if (e == null) { e = new TreeModelEvent(source, path, childIndices, children); } ((TreeModelListener) listeners[i + 1]).treeNodesChanged(e); } } } /* * Notify all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. * @see EventListenerList */ protected void fireTreeNodesInserted(Object source, TreePath path, int[] childIndices, Object[] children) { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); TreeModelEvent e = null; // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == TreeModelListener.class) { // Lazily create the event: if (e == null) { e = new TreeModelEvent(source, path, childIndices, children); } ((TreeModelListener) listeners[i + 1]).treeNodesInserted(e); } } } /* * Notify all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. * @see EventListenerList */ protected void fireTreeNodesRemoved(Object source, TreePath path, int[] childIndices, Object[] children) { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); TreeModelEvent e = null; // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == TreeModelListener.class) { // Lazily create the event: if (e == null) { e = new TreeModelEvent(source, path, childIndices, children); } ((TreeModelListener) listeners[i + 1]).treeNodesRemoved(e); } } } /* * Notify all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. * @see EventListenerList */ protected void fireTreeStructureChanged(Object source, TreePath path, int[] childIndices, Object[] children) { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); TreeModelEvent e = null; // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == TreeModelListener.class) { // Lazily create the event: if (e == null) { e = new TreeModelEvent(source, path, childIndices, children); } ((TreeModelListener) listeners[i + 1]).treeStructureChanged(e); } } } // Left to be implemented in the subclass: /* * public Object getChild(Object parent, int index) * public int getChildCount(Object parent) * public int getColumnCount() * public String getColumnName(Object node, int column) * public Object getValueAt(Object node, int column) */ }freehep-swing-2.0.3/src/main/java/org/freehep/swing/treetable/TreeTableModel.java0000644012010301201030000000307110466735775030724 0ustar mascellanimascellanipackage org.freehep.swing.treetable; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; /** * TreeTableModel is the model used by a JTreeTable. It extends TreeModel * to add methods for getting inforamtion about the set of columns each * node in the TreeTableModel may have. Each column, like a column in * a TableModel, has a name and a type associated with it. Each node in * the TreeTableModel can return a value for each of the columns and * set that value if isCellEditable() returns true. * * @author Philip Milne * @author Scott Violet * @version $Id: TreeTableModel.java 8584 2006-08-10 23:06:37Z duns $ */ public interface TreeTableModel extends TreeModel { /** * Indicates whether the the value for node node, * at column number column is editable. */ public boolean isCellEditable(TreePath path, int column); /** * Returns the type for column number column. */ public Class getColumnClass(int column); /** * Returns the number ofs availible column. */ public int getColumnCount(); /** * Returns the name for column number column. */ public String getColumnName(int column); /** * Sets the value for node node, * at column number column. */ public void setValueAt(Object aValue, TreePath path, int column); /** * Returns the value to be displayed for node node, * at column number column. */ public Object getValueAt(TreePath path, int column); }freehep-swing-2.0.3/src/main/java/org/freehep/swing/treetable/JTreeTable.java0000644012010301201030000002551310466735775030062 0ustar mascellanimascellanipackage org.freehep.swing.treetable; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.event.MouseEvent; import java.util.EventObject; import javax.swing.JTable; import javax.swing.JTree; import javax.swing.ListSelectionModel; import javax.swing.LookAndFeel; import javax.swing.UIManager; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.TableCellRenderer; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeSelectionModel; import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; /** * This example shows how to create a simple JTreeTable component, * by using a JTree as a renderer (and editor) for the cells in a * particular column in the JTable. * * @author Philip Milne * @author Scott Violet * @version $Id: JTreeTable.java 8584 2006-08-10 23:06:37Z duns $ */ public class JTreeTable extends JTable { /** * A subclass of JTree. */ protected TreeTableCellRenderer tree; public JTreeTable() { this(null); } public JTreeTable(TreeTableModel treeTableModel) { super(); if (treeTableModel != null) { setModel(treeTableModel); } } public void setModel(TreeTableModel treeTableModel) { // Create the tree. It will be used as a renderer and editor. tree = new TreeTableCellRenderer(treeTableModel); // Install a tableModel representing the visible rows in the tree. super.setModel(new TreeTableModelAdapter(treeTableModel, tree)); // Force the JTable and JTree to share their row selection models. ListToTreeSelectionModelWrapper selectionWrapper = new ListToTreeSelectionModelWrapper(); tree.setSelectionModel(selectionWrapper); setSelectionModel(selectionWrapper.getListSelectionModel()); // Install the tree editor renderer and editor. setDefaultRenderer(TreeTableModel.class, tree); // No grid. setShowGrid(false); // No intercell spacing setIntercellSpacing(new Dimension(0, 0)); // And update the height of the trees row to match that of // the table. if (tree.getRowHeight() < 1) { // Metal looks better like this. setRowHeight(18); } } public Object getNodeForRow(int row) { TreeTableModelAdapter a = (TreeTableModelAdapter) getModel(); return a.nodeForRow(row); } public int getRowForLocation(int x, int y) { TreeTableModelAdapter a = (TreeTableModelAdapter) getModel(); return a.getRowForLocation(x, y); } /** * Overridden to pass the new rowHeight to the tree. */ public void setRowHeight(int rowHeight) { super.setRowHeight(rowHeight); if ((tree != null) && (tree.getRowHeight() != rowHeight)) { tree.setRowHeight(getRowHeight()); } } /** * Returns the tree that is being shared between the model. */ public JTree getTree() { return tree; } public TreePath getTreePathForRow(int row) { TreeTableModelAdapter a = (TreeTableModelAdapter) getModel(); return a.pathForRow(row); } /** * Overriden to pass events on to the tree if the editor * does not want to start editing. */ public boolean editCellAt(int row, int column, EventObject e) { if (!super.editCellAt(row, column, e)) { if (e instanceof MouseEvent) { for (int counter = getColumnCount() - 1; counter >= 0; counter--) { if (getColumnClass(counter) == TreeTableModel.class) { MouseEvent me = (MouseEvent) e; MouseEvent newME = new MouseEvent(tree, me.getID(), me.getWhen(), me.getModifiers(), me.getX() - getCellRect(0, counter, true).x, me.getY(), me.getClickCount(), me.isPopupTrigger()); tree.dispatchEvent(newME); break; } } } return false; } return true; } /** * Overridden to message super and forward the method to the tree. * Since the tree is not actually in the component hieachy it will * never receive this unless we forward it in this manner. */ public void updateUI() { super.updateUI(); if (tree != null) { tree.updateUI(); } // Use the tree's default foreground and background colors in the // table. LookAndFeel.installColorsAndFont(this, "Tree.background", "Tree.foreground", "Tree.font"); } /** * A TreeCellRenderer that displays a JTree. */ public class TreeTableCellRenderer extends JTree implements TableCellRenderer { /** * Last table/tree row asked to renderer. */ protected int visibleRow; public TreeTableCellRenderer(TreeModel model) { super(model); } /** * This is overridden to set the height to match that of the JTable. */ public void setBounds(int x, int y, int w, int h) { super.setBounds(x, 0, w, JTreeTable.this.getHeight()); } /** * Sets the row height of the tree, and forwards the row height to * the table. */ public void setRowHeight(int rowHeight) { if (rowHeight > 0) { super.setRowHeight(rowHeight); if ((JTreeTable.this != null) && (JTreeTable.this.getRowHeight() != rowHeight)) { JTreeTable.this.setRowHeight(getRowHeight()); } } } /** * TreeCellRenderer method. Overridden to update the visible row. */ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if (isSelected) { setBackground(table.getSelectionBackground()); } else { setBackground(table.getBackground()); } visibleRow = row; return this; } /** * Sublcassed to translate the graphics such that the last visible * row will be drawn at 0,0. */ public void paint(Graphics g) { g.translate(0, -visibleRow * getRowHeight()); super.paint(g); } /** * updateUI is overridden to set the colors of the Tree's renderer * to match that of the table. */ public void updateUI() { super.updateUI(); // Make the tree's cell renderer use the table's cell selection // colors. TreeCellRenderer tcr = getCellRenderer(); if (tcr instanceof DefaultTreeCellRenderer) { DefaultTreeCellRenderer dtcr = (DefaultTreeCellRenderer) tcr; // For 1.1 uncomment this, 1.2 has a bug that will cause an // exception to be thrown if the border selection color is // null. // dtcr.setBorderSelectionColor(null); dtcr.setTextSelectionColor(UIManager.getColor("Table.selectionForeground")); dtcr.setBackgroundSelectionColor(UIManager.getColor("Table.selectionBackground")); } } } /** * ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel * to listen for changes in the ListSelectionModel it maintains. Once * a change in the ListSelectionModel happens, the paths are updated * in the DefaultTreeSelectionModel. */ class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel { /** * Set to true when we are updating the ListSelectionModel. */ protected boolean updatingListSelectionModel; public ListToTreeSelectionModelWrapper() { super(); getListSelectionModel().addListSelectionListener(createListSelectionListener()); } /** * This is overridden to set updatingListSelectionModel * and message super. This is the only place DefaultTreeSelectionModel * alters the ListSelectionModel. */ public void resetRowSelection() { if (!updatingListSelectionModel) { updatingListSelectionModel = true; try { super.resetRowSelection(); } finally { updatingListSelectionModel = false; } } // Notice how we don't message super if // updatingListSelectionModel is true. If // updatingListSelectionModel is true, it implies the // ListSelectionModel has already been updated and the // paths are the only thing that needs to be updated. } /** * Creates and returns an instance of ListSelectionHandler. */ protected ListSelectionListener createListSelectionListener() { return new ListSelectionHandler(); } /** * If updatingListSelectionModel is false, this will * reset the selected paths from the selected rows in the list * selection model. */ protected void updateSelectedPathsFromSelectedRows() { if (!updatingListSelectionModel) { updatingListSelectionModel = true; try { // This is way expensive, ListSelectionModel needs an // enumerator for iterating. int min = listSelectionModel.getMinSelectionIndex(); int max = listSelectionModel.getMaxSelectionIndex(); clearSelection(); if ((min != -1) && (max != -1)) { for (int counter = min; counter <= max; counter++) { if (listSelectionModel.isSelectedIndex(counter)) { TreePath selPath = tree.getPathForRow(counter); if (selPath != null) { addSelectionPath(selPath); } } } } } finally { updatingListSelectionModel = false; } } } /** * Returns the list selection model. ListToTreeSelectionModelWrapper * listens for changes to this model and updates the selected paths * accordingly. */ ListSelectionModel getListSelectionModel() { return listSelectionModel; } /** * Class responsible for calling updateSelectedPathsFromSelectedRows * when the selection of the list changse. */ class ListSelectionHandler implements ListSelectionListener { public void valueChanged(ListSelectionEvent e) { updateSelectedPathsFromSelectedRows(); } } } }freehep-swing-2.0.3/src/main/java/org/freehep/swing/treetable/package.html0000644012010301201030000000071310470537377027503 0ustar mascellanimascellani Utilities for dealing with Swing tables.

The code in this package is based on the code presented in the series of articles on the "The Swing Connection", which can be found here:

http://java.sun.com/products/jfc/tsc/articles/treetable1/

The classes in this package have been modified from those presented above to fix some limitations in the original classes. freehep-swing-2.0.3/src/main/java/org/freehep/swing/treetable/TreeTableModelAdapter.java0000644012010301201030000000766410466735775032241 0ustar mascellanimascellanipackage org.freehep.swing.treetable; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; import javax.swing.table.AbstractTableModel; import javax.swing.tree.TreePath; /** * This is a wrapper class takes a TreeTableModel and implements * the table model interface. The implementation is trivial, with * all of the event dispatching support provided by the superclass: * the AbstractTableModel. * * @author Philip Milne * @author Scott Violet * @version $id$ */ public class TreeTableModelAdapter extends AbstractTableModel { JTree tree; TreeTableModel treeTableModel; public TreeTableModelAdapter(TreeTableModel treeTableModel, JTree tree) { this.tree = tree; this.treeTableModel = treeTableModel; tree.addTreeExpansionListener(new TreeExpansionListener() { // Don't use fireTableRowsInserted() here; the selection model // would get updated twice. public void treeExpanded(TreeExpansionEvent event) { fireTableDataChanged(); } public void treeCollapsed(TreeExpansionEvent event) { fireTableDataChanged(); } }); // Install a TreeModelListener that can update the table when // tree changes. We use delayedFireTableDataChanged as we can // not be guaranteed the tree will have finished processing // the event before us. treeTableModel.addTreeModelListener(new TreeModelListener() { public void treeNodesChanged(TreeModelEvent e) { delayedFireTableDataChanged(); } public void treeNodesInserted(TreeModelEvent e) { delayedFireTableDataChanged(); } public void treeNodesRemoved(TreeModelEvent e) { delayedFireTableDataChanged(); } public void treeStructureChanged(TreeModelEvent e) { delayedFireTableDataChanged(); } }); } public boolean isCellEditable(int row, int column) { return treeTableModel.isCellEditable(pathForRow(row), column); } public Class getColumnClass(int column) { return treeTableModel.getColumnClass(column); } // Wrappers, implementing TableModel interface. public int getColumnCount() { return treeTableModel.getColumnCount(); } public String getColumnName(int column) { return treeTableModel.getColumnName(column); } public int getRowCount() { return tree.getRowCount(); } public void setValueAt(Object value, int row, int column) { treeTableModel.setValueAt(value, pathForRow(row), column); } public Object getValueAt(int row, int column) { return treeTableModel.getValueAt(pathForRow(row), column); } protected int getRowForLocation(int x, int y) { return tree.getRowForLocation(x, y); } /** * Invokes fireTableDataChanged after all the pending events have been * processed. SwingUtilities.invokeLater is used to handle this. */ protected void delayedFireTableDataChanged() { SwingUtilities.invokeLater(new Runnable() { public void run() { fireTableDataChanged(); } }); } protected Object nodeForRow(int row) { TreePath treePath = tree.getPathForRow(row); if (treePath == null) { System.err.println("WARNING: nodeForRow returning null for " + row); return null; } return treePath.getLastPathComponent(); } protected TreePath pathForRow(int row) { TreePath treePath = tree.getPathForRow(row); if (treePath == null) { System.err.println("WARNING: pathForRow returning null for " + row); return null; } return treePath; } }freehep-swing-2.0.3/src/main/java/org/freehep/swing/graphics/0000755012010301201030000000000011275634131025040 5ustar mascellanimascellanifreehep-swing-2.0.3/src/main/java/org/freehep/swing/graphics/Scale.java0000644012010301201030000001760010466735775026757 0ustar mascellanimascellani// Charles A. Loomis, Jr., and University of California, Santa Cruz, // Copyright (c) 2000 package org.freehep.swing.graphics; import java.awt.geom.GeneralPath; /** * This class contains static methods which are useful for the * ScaleBorder class and any potential subclasses. * * @author Charles Loomis * @version $Id: Scale.java 8584 2006-08-10 23:06:37Z duns $ */ public class Scale { private static int[] p = {2,2,5,5,5,10,10,10,20,20,50,50}; private static int[] ps = {2,10,5,10,20,10,20,50,20,100,50,100}; final static public int LEFT_TICKS = 0; final static public int RIGHT_TICKS = 1; final static public int BOTH_TICKS = 2; /** * The size in pixels of the primary tick marks. This is a global * property for all scales. */ protected static float primaryTickSize = 8.f; /** * The size in pixels of the secondary tick marks. This is a * global property for all scales. */ protected static float secondaryTickSize = 5.f; /** * Set the tick sizes (in pixels) for the primary and secondary * tick marks. */ static public void setTickSizes(float primaryTickSize, float secondaryTickSize) { Scale.primaryTickSize = primaryTickSize; Scale.secondaryTickSize = secondaryTickSize; } /** * Get the primary tick size (in pixels). */ static public float getPrimaryTickSize() { return Scale.primaryTickSize; } /** * Get the secondary tick size (in pixels). */ static public float getSecondaryTickSize() { return Scale.secondaryTickSize; } /** * A utility method to add a tick mark to the given GeneralPath at * the given position. */ static private void addTickMark(GeneralPath gp, int location, float tickPosition, float tickLength) { switch (location) { case (Scale.RIGHT_TICKS): gp.moveTo(tickPosition,0.f); gp.lineTo(tickPosition,tickLength); break; case (Scale.LEFT_TICKS): gp.moveTo(tickPosition,0.f); gp.lineTo(tickPosition,-tickLength); break; case (Scale.BOTH_TICKS): gp.moveTo(tickPosition,-tickLength); gp.lineTo(tickPosition,tickLength); break; } } static public void drawLinearScale(double value0, double value1, int scaleSize, int minPrimary, int minSeparation, int location, GeneralPath primaryTicks, GeneralPath secondaryTicks, String[] label, double[] position) { // First calculate the range of the scale. double range = Math.abs(value1-value0); // Calculate the smallest order of magnitude which will NOT // fit in the range. double m = Math.pow(10.,Math.ceil(Math.log(range)/Math.log(10.))); // Get the size of the window. double w = scaleSize; // Calculate the minimum value of np (number of primary tick // marks in m). double minNP = m*minPrimary/range; // Calculate the maximum value of np*ns. double maxNPNS = w*m/(range*minSeparation); // Find the optimal combination of primary and secondary tick // marks. int optimal = -1; int oldPS = -1; int oldP = Integer.MAX_VALUE; for (int i=0; iminNP && ps[i]oldPS) { optimal = i; oldP = p[i]; oldPS = ps[i]; } } } // Setup the two paths which will contain the primary and // secondary tick marks. primaryTicks.reset(); secondaryTicks.reset(); primaryTicks.moveTo(0.f,0.f); primaryTicks.lineTo((float) w,0.f); secondaryTicks.moveTo(0.f,0.f); secondaryTicks.lineTo((float) w,0.f); // Only do something if a solution was found. if (optimal>0) { // Calculate the size of the secondary tick marks. double size = m/ps[optimal]; // Calculate the limits for the tick marks. Make sure // that we take the integers which are on the interior of // the interval! int average = (int) (0.5*(value0+value1)/size); int limit0 = (int) (value0/size-average) + average; int limit1 = (int) (value1/size-average) + average; // Now make the secondary tick marks. for (int iv= Math.min(limit0,limit1); iv <= Math.max(limit0,limit1); iv++) { double val = iv*size; float tickPosition = interpolate(val,w,value0,value1); addTickMark(secondaryTicks,location, tickPosition,secondaryTickSize); } // Calculate the size of the primary tick marks. size = m/p[optimal]; // Again calculate the limits for the tick marks on the // interior of the interval. average = (int) (0.5*(value0+value1)/size); limit0 = (int) (value0/size-average) + average; limit1 = (int) (value1/size-average) + average; // Make the primary tick marks. for (int iv = Math.min(limit0,limit1); iv <= Math.max(limit0,limit1); iv++) { double val = iv*size; float tickPosition = interpolate(val,w,value0,value1); addTickMark(primaryTicks,location, tickPosition,primaryTickSize); } // Now the labels with the correct precision must be made. // First calculate the necessary precision. int ndigits = (int) (Math.floor(Math.log(size)/Math.log(10.))); ndigits = -Math.min(ndigits,0); // Now make the labels. int iv = Math.min(limit0,limit1); int zero = iv; double val = iv*size; float tickPosition = interpolate(val,w,value0,value1); label[0] = fixedPrecision(val, ndigits); position[0] = (double) tickPosition; iv = Math.max(limit0,limit1); zero *= iv; val = iv*size; tickPosition = interpolate(val,w,value0,value1); label[1] = fixedPrecision(val, ndigits); position[1] = (double) tickPosition; // Check to see if zero is inside the interval. if (zero<=0) { tickPosition = interpolate(0.,w,value0,value1); label[2] = fixedPrecision(0., ndigits); position[2] = (double) tickPosition; } else { label[2] = null; position[2] = position[1]; } } } static private float interpolate(double value, double size, double value0, double value1) { return (float) (size*(value-value0)/(value1-value0)); } public static String fixedPrecision(double d, int ndigits) { String dstring = Double.toString(d); StringBuffer buffer = new StringBuffer(dstring); int index = dstring.lastIndexOf("."); if (index<0) { buffer.append("."); index = buffer.length()-1; } buffer.setLength(index+ndigits+1); for (int i=0; i0 && h>0) { if (!oldDimension.equals(dim)) { synchronized (getLock()) { // Make the actual backing image and get the // graphics context for this image. backingImage = (isOpaque()) ? (BufferedImage)super.createImage(w,h) : new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB); backingGraphics = backingImage.getGraphics(); // Reset the old size of this panel. oldDimension.setSize(dim); } } } else { synchronized (getLock()) { backingImage = null; backingGraphics = null; } } } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/graphics/AbstractRegionSelectionPanel.java0000644012010301201030000005161210466735775033466 0ustar mascellanimascellani// Charles A. Loomis, Jr., and University of California, Santa Cruz, // Copyright (c) 2000 package org.freehep.swing.graphics; import java.awt.Cursor; import java.awt.Graphics; import java.awt.Point; import java.awt.Polygon; import java.awt.Rectangle; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.geom.AffineTransform; import javax.swing.SwingUtilities; import org.freehep.swing.images.FreeHepImage; /** * This abstract class defines the majority of the functionality * needed to make selections of arbitrary parallelogram regions * on the screen. * * @author Charles Loomis * @author Mark Donszelmann * @version $Id: AbstractRegionSelectionPanel.java 8584 2006-08-10 23:06:37Z duns $ */ abstract public class AbstractRegionSelectionPanel extends GraphicalSelectionPanel { /** * A constant which flags that no control point was near the * mouse-pressed event. */ final public static int NO_CONTROL_POINT = -1; /** * Flag indicating whether or not additional guide lines should be * visible. */ protected boolean visibleGuides; /** * The bounding rectangle of the next box to be drawn. */ protected Rectangle rectToDraw = new Rectangle(); /** * The bounding rectangle of the last box which was drawn. */ protected Rectangle lastDrawnRect = new Rectangle(); /** * The bounding box of the region to repaint, usually the union of * the rectToDraw and lastDrawnRect rectangles. */ protected Rectangle updateRect = new Rectangle(); /** * Flag indicating whether or not the selection box is visible. */ protected boolean visible; /** * Flag indicating whether or not the last drawn rectangle is * valid. (Not valid when the box is first made visible.) */ protected boolean lastDrawnRectValid; /** * The maximum distance from a control point the cursor can be and * still be selected. */ protected int hitThreshold = 10; /** * The size of the control point boxes. */ protected static int ctrlPtSize = 1; /** * The number of control points for this component. */ protected int nCtrlPts; /** * Which control point is the active one, or which one can be * controlled from the arrow keys on the keyboard? */ protected int activeCtrlPt; /** * The x-coordinates of the control points. The first four of * these control points MUST define the outer boundries of the * selected region. */ protected int[] xCtrlPts; /** * The y-coordinates of the control points. The first four of * these control points MUST define the outer boundries of the * selected region. */ protected int[] yCtrlPts; /** * This constructor makes a new AbstractRegionSelectionPanel. * This constructor only sets the visiblilty flag and the * last-drawn rectangle valid flag to false. */ public AbstractRegionSelectionPanel() { // First make the selection region invisible and invalidate // the last-drawn rectangle. visible = false; lastDrawnRectValid = false; setSelectionActionsEnabled(false); // The guides are by default visible. visibleGuides = true; // Create the arrays of the x- and y-coordinates. There must // be at least four control points. nCtrlPts = Math.max(4,getNumberOfControlPoints()); xCtrlPts = new int[nCtrlPts]; yCtrlPts = new int[nCtrlPts]; activeCtrlPt = NO_CONTROL_POINT; // set the default cursor setCursor(); } /** * Determine whether or not to display guide lines. */ public void setVisibleGuides(boolean visibleGuides) { this.visibleGuides = visibleGuides; repaintPanel(); } /** * Get whether or not the guides are visible. */ public boolean getVisibleGuides() { return visibleGuides; } /** * Process key-released events. This allows selection panels * which derive from this one to automatically have the default * behaviour. * *

     * arrow keys:    move the active control point in the specified
     *                direction.
     * backspace key: reset selection region (make invisible).
     * delete key:    reset selection region (make invisible).
     * escape key:    leave selection mode (make component invisible).
     * tab key:       next selection mode (make next component visible).
     * enter key:     accept selection region (send off region selected
     *                event)
     * spacebar:      accept selection region (send off region selected
     *                event)
     * 
* * @param e KeyEvent describing the key which has been released */ public void keyReleased(KeyEvent e) { // Change the size of the increment in the given direction. int increment = (e.isShiftDown()) ? 1 : 2; switch (e.getKeyCode()) { case KeyEvent.VK_UP: moveActiveControlPoint(0,-increment); break; case KeyEvent.VK_DOWN: moveActiveControlPoint(0,increment); break; case KeyEvent.VK_RIGHT: moveActiveControlPoint(increment,0); break; case KeyEvent.VK_LEFT: moveActiveControlPoint(-increment,0); break; default: super.keyReleased(e); break; } } /** * A utility function which creates an appropriate selection event * when the user accepts the current selection. */ protected void makeSelectionEvent(int actionCode) { switch (actionCode) { case GraphicalSelectionEvent.DEFAULT_MODE: resetSelection(); setVisible(false); fireGraphicalSelectionMade(new GraphicalSelectionEvent(this, GraphicalSelectionEvent.DEFAULT_MODE, null,null)); break; case GraphicalSelectionEvent.NEXT_MODE: resetSelection(); setVisible(false); fireGraphicalSelectionMade(new GraphicalSelectionEvent(this, GraphicalSelectionEvent.NEXT_MODE, null,null)); break; case GraphicalSelectionEvent.PREVIOUS_MODE: resetSelection(); setVisible(false); fireGraphicalSelectionMade(new GraphicalSelectionEvent(this, GraphicalSelectionEvent.PREVIOUS_MODE, null,null)); break; default: if (visible) { // Make an array of points describing the corners of this // rectangular region. NOTE: the first four control // points must define the outer extent of the selected // region. Point[] points = new Point[4]; for (int i=0; i<4; i++) { points[i] = new Point(xCtrlPts[i], yCtrlPts[i]); } // Send off the event to interested parties. fireGraphicalSelectionMade(new RegionSelectionEvent(this,actionCode, makeOutlinePolygon(), makeAffineTransform())); } resetSelection(); break; } } /** * Sets the cursor to whatever the current active control point dictates. */ private void setCursor() { // active cursor Cursor cursor = getControlPointCursor(activeCtrlPt); // default cursor if no active cursor if (cursor == null) { cursor = getControlPointCursor(NO_CONTROL_POINT); } // set only when available if (cursor != null) { setCursor(cursor); } } /** * Changes the active control point according to mouse movements * */ public void mouseMoved(MouseEvent e) { if (!isProcessingPopup(e)) { if (visible) { int newCtrlPt = nearWhichControlPoint(e.getX(), e.getY(), hitThreshold); if (newCtrlPt != activeCtrlPt) { activeCtrlPt = newCtrlPt; setCursor(); repaintPanel(); return; } } } } /** * Handle the mousePressed events. */ public void mousePressed(MouseEvent e) { // Only do something if this isn't part of a popup menu // selection. if (!isProcessingPopup(e)) { // If the selection box is visible AND the user has // clicked near one of the existing control points, make // the nearest one the active control point and update the // current selection. Return when finished. if (visible) { int newCtrlPt = nearWhichControlPoint(e.getX(), e.getY(), hitThreshold); if (newCtrlPt>=0) { activeCtrlPt = newCtrlPt; setCursor(); repaintPanel(); return; } } // User wants to start a new selection. So first set the // flag to make the selection region visible. visible = true; setSelectionActionsEnabled(true); // Get the mouse point and force point within boundries. int x = forceXCoordinateWithinBounds(e.getX()); int y = forceYCoordinateWithinBounds(e.getY()); // The initialize method is responsible for setting all of // the control points to reasonable values and for setting // which point should be the active one. activeCtrlPt = NO_CONTROL_POINT; initializeControlPoints(x,y); setCursor(); // Update the display. repaintPanel(); } } /** * A utility method which forces the x-coordinate to be within the * component boundries. * * @param x x-coordinate to force within boundries * @return modified x-value */ public int forceXCoordinateWithinBounds(int x) { int xmin = 0; int xmax = getWidth()-1; return Math.max(Math.min(x,xmax),xmin); } /** * A utility method which forces the y-coordinate to be within the * component boundries. * * @param y y-coordinate to force within boundries * @return modified y-value */ public int forceYCoordinateWithinBounds(int y) { int ymin = 0; int ymax = getHeight()-1; return Math.max(Math.min(y,ymax),ymin); } public void mouseDragged(MouseEvent e) { if (!isProcessingPopup(e)) { updateActiveControlPoint(e.getX(),e.getY()); setCursor(); } } public void mouseReleased(MouseEvent e) { if (!isProcessingPopup(e)) { updateActiveControlPoint(e.getX(),e.getY()); if (!isValidSelection()) resetSelection(); setCursor(); } else { activeCtrlPt = NO_CONTROL_POINT; setCursor(); } } /** * This returns whether the current selected region is valid. * Generally if the area has zero volume, then this method should * return false. */ abstract public boolean isValidSelection(); /** * A utility method which moves the currently active control point * by the given delta-x and delta-y. It does this by calling * updateActiveControlPoint(x,y), so subclasses shouldn't normally * need to override this method. * * @param dx the distance to move the x-coordinate * @param dy the distance to move the y-coordinate */ protected void moveActiveControlPoint(int dx, int dy) { if (activeCtrlPt>=0) { int x = xCtrlPts[activeCtrlPt] + dx; int y = yCtrlPts[activeCtrlPt] + dy; updateActiveControlPoint(x,y); } } /** * Check to see if the point (x,y) is near one of the control * points. If it is, return the index of the nearest one, * otherwise return NO_CONTROL_POINT. * * @param x x-coordinate to compare to control points * @param y y-coordinate to compare to control points * @param maxDist the maximum distance from a control point which * still selects it * * @return the index of the nearest control point */ protected int nearWhichControlPoint(int x, int y, int maxDist) { // Initialize to no control point selected. int nearestCtrlPt = NO_CONTROL_POINT; int minDist2 = -1; // Loop over all control points and get the closest one. // (Actually calculate distance-squared here.) for (int i=0; imaxDist*maxDist) nearestCtrlPt = NO_CONTROL_POINT; return nearestCtrlPt; } /** * Make the selection box invisible. */ public void resetSelection() { visible = false; lastDrawnRectValid = false; setSelectionActionsEnabled(false); activeCtrlPt = NO_CONTROL_POINT; setCursor(); repaintPanel(); } /** * Repaint the panel. Calculate the bounding box of the selection * box along with associated control points. */ protected void repaintPanel() { // Find the bounding points for the polygon. int x0 = xCtrlPts[0]; int y0 = yCtrlPts[0]; int x1 = xCtrlPts[0]; int y1 = yCtrlPts[0]; for (int i=1; ix1) x1 = xCtrlPts[i]; if (yCtrlPts[i]>y1) y1 = yCtrlPts[i]; } // Adjust for the size of the active control point and line // widths. x0 -= ctrlPtSize+2; y0 -= ctrlPtSize+2; x1 += ctrlPtSize+2; y1 += ctrlPtSize+2; // Set the bounds of the current polygon. rectToDraw.setRect(x0,y0,x1-x0,y1-y0); // Repaint the new bounds. updateRect.setBounds(rectToDraw); if (lastDrawnRectValid) { updateRect = SwingUtilities.computeUnion(lastDrawnRect.x, lastDrawnRect.y, lastDrawnRect.width, lastDrawnRect.height, updateRect); } repaint(updateRect); } /** * Initialize the control points. Subclasses must provide an * implementation of this method which initializes the control * points to reasonable values given the first mouse-pressed * coordinates, and must also set the activeCtrlPt to the index of * the control point which should be active. * * @param x x-coordinate of initial mouse-pressed event * @param y y-coordinate of initial mouse-pressed event */ abstract public void initializeControlPoints(int x, int y); /** * Change the active control point to the point (x,y). Subclasses * should implement this routine to get the behaviour which is * desired. This is the place to impose constraints on how the * control points can move. NOTE: repaintPanel() should be called * at the end of this method to update the display. * * @param x x-coordinate of the new point * @param y y-coordinate of the new point */ abstract public void updateActiveControlPoint(int x, int y); /** * Useful subclasses must define the number of control points on * the selected region. The first four control points define the * outer extent of the selected region. This method MUST NOT * return a number less than four. */ abstract public int getNumberOfControlPoints(); /** * Returns the Cursor to be displayed for a certain control point * and the default cursor for this SelectionPanel for an index of * NO_CONTROL_POINT. Return of null will not change the cursor. * Subclasses should override this method to provide a default * cursor and/or to provide cursors for the different control points. */ public Cursor getControlPointCursor(int index) { return null; } /** * Repaint this component. This must be overridden by subclasses * so that the selection region appears correctly. The subclass * should check the visibility flag (visible) to decide if any * painting needs to be done. * * @param g Graphics context in which to draw */ public void paintComponent(Graphics g) { super.paintComponent(g); // Update the last drawn rectangle. lastDrawnRectValid = true; lastDrawnRect.setBounds(rectToDraw); } /** * Make the outline of the selection. Note that the order of the * points is not guaranteed. * * @return a polygon object which describes the outline of * the selection */ public Polygon makeOutlinePolygon() { Polygon polygon = new Polygon(); // Only take the first four control points, since these define // the outline of the selection. for (int i=0; i<4; i++) { polygon.addPoint(xCtrlPts[i], yCtrlPts[i]); } return polygon; } /** * Make the affine transform which corresponds to this rectangular * selection. * * @return AffineTransform which describes the selected region */ abstract public AffineTransform makeAffineTransform(); /** * A utility which makes an AffineTransform given three corner * points. The first point must be the upper, left-hand corner * point, the second, the upper, right-hand corner point, and the * third, the lower, right-hand corner point. * * @return AffineTransform which does the appropriate mapping */ protected AffineTransform makeTransform(double x0, double y0, double x1, double y1, double x2, double y2) { double sx = 0.; double kx = 0.; double tx = 0.; double sy = 0.; double ky = 0.; double ty = 0.; double delta = (x2*(y1-y0)-x1*(y2-y0)+x0*(y2-y1)); if (delta==0) { return null; } else { delta = 1./delta; double w = getWidth(); double h = getHeight(); sx = -(delta*w)*(y2-y1); kx = (delta*w)*(x2-x1); tx = -(x0*sx+y0*kx); ky = (delta*h)*(y1-y0); sy = -(delta*h)*(x1-x0); ty = -(x0*ky+y0*sy); return new AffineTransform(sx,ky,kx,sy,tx,ty); } } /** * returns the appropriate cursor for any of the * compass points. If both dx and dy are zero, null is returned * * @param type type of cursor (Resize/Rotation) * @param dx screen x of direction * @param dy screen y of direction (positive is down) * @param n number of compass points (4 or 8) * @param diagonal in case n = 4, a diagonal compass point is returned * @return XX_RESIZE_CURSOR */ public static Cursor compassCursor(String type, int dx, int dy, int n, boolean diagonal) { if ((dx == 0) && (dy == 0)) return null; double offset; if (n == 4) { offset = (diagonal) ? 0 : Math.PI/4; } else { n = 8; offset = Math.PI/8; } double delta = 2*Math.PI/n; double alpha = (Math.atan2(-dy, dx) + 2*Math.PI + offset) % (2*Math.PI); int d = (int)(alpha / delta); if (n == 4) { d = (diagonal) ? d * 2 + 1 : d * 2; } switch(d) { case 0: return FreeHepImage.getCursor("E_"+type+"Cursor", 16, 16); case 1: return FreeHepImage.getCursor("NE_"+type+"Cursor", 16, 16); case 2: return FreeHepImage.getCursor("N_"+type+"Cursor", 16, 16); case 3: return FreeHepImage.getCursor("NW_"+type+"Cursor", 16, 16); case 4: return FreeHepImage.getCursor("W_"+type+"Cursor", 16, 16); case 5: return FreeHepImage.getCursor("SW_"+type+"Cursor", 16, 16); case 6: return FreeHepImage.getCursor("S_"+type+"Cursor", 16, 16); case 7: return FreeHepImage.getCursor("SE_"+type+"Cursor", 16, 16); } System.err.println("compassCursor invalid value: "+d); return Cursor.getDefaultCursor(); } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/graphics/GraphicalSelectionPanel.java0000644012010301201030000004740610466735775032457 0ustar mascellanimascellani// Charles A. Loomis, Jr., and University of California, Santa Cruz, // Copyright (c) 2000 package org.freehep.swing.graphics; import java.awt.BasicStroke; import java.awt.KeyboardFocusManager; import java.awt.Stroke; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.Iterator; import java.util.LinkedList; import java.util.Set; import java.util.TreeSet; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.InputMap; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.KeyStroke; import javax.swing.border.Border; import javax.swing.event.EventListenerList; /** * The primary superclass of all graphical selection panels. These * panels are expected to handle all of the interaction with the user, * and generate a GraphicalSelectionEvent when a selection has been * made. * * Note that GraphicalSelectionPanels use the information about the * size of the component to send back meaningful zoom transformation * and the like. To keep these calculations simple, Borders are not * allowed on these components. If a Border is desired, then embed * the selection panel within a container and put the Border on the * container. * * @author Charles Loomis * @version $Id: GraphicalSelectionPanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class GraphicalSelectionPanel extends JPanel implements MouseListener, KeyListener, MouseMotionListener, java.io.Serializable { /** * A private ActionEvent which is used when a selection is made. Since * the sender never changes, this event is simply reused. */ private ActionEvent actionEvent; /** * The list of selection actions. */ protected LinkedList selectionActions = new LinkedList(); /** * The hash map which maps keys to actions. */ protected ActionMap actionMap = new ActionMap(); /** * The "Leave" action in the popup menu. Created here as an * Action so that subclasses can more easily enable and disable * this item. */ protected SelectionAction defaultModeAction = new SelectionAction("Default Mode", GraphicalSelectionEvent.DEFAULT_MODE, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0)); /** * The "Next" action in the popup menu. Created here as an * Action so that subclasses can more easily enable and disable * this item. */ protected SelectionAction nextAction = new SelectionAction("Next Mode", GraphicalSelectionEvent.NEXT_MODE, KeyStroke.getKeyStroke(KeyEvent.VK_N,0)); /** * The "Previous" action in the popup menu. Created here as an * Action so that subclasses can more easily enable and disable * this item. */ protected SelectionAction previousAction = new SelectionAction("Previous Mode", GraphicalSelectionEvent.PREVIOUS_MODE, KeyStroke.getKeyStroke(KeyEvent.VK_P,0)); /** * Thin stroke for the white part of the selection box. Set the * miter limit so that the drawing doesn't extend outside of the * bounding box. */ final protected static Stroke thinStroke = new BasicStroke(1.f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 3.f); /** * Thick stroke for the black part of the selection box. Set the * miter limit so that the drawing doesn't extend outside of the * bounding box. */ final protected static Stroke thickStroke = new BasicStroke(3.f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 5.f); /** * An empty popup menu is available for subclasses of this * object. */ private JPopupMenu popup; /** * A flag to indicate whether a popup menu is currently being * processed or not. */ private boolean processingPopup; /** * Keeps track of all of the event listeners. */ private EventListenerList listenerList; /** * Error string when user attempts to set a non-null border. */ private final static String NON_NULL_BORDER_ERROR = "GraphicalSelectionPanel does not support borders."; /** * Creates a selection panel which is transparent. */ public GraphicalSelectionPanel() { // make sure that tab and shift-tab can be used to cycle between components. Set forwardKeys = new TreeSet(); forwardKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0)); setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forwardKeys); Set backwardKeys = new TreeSet(); backwardKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK)); setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, backwardKeys); setOpaque(false); listenerList = new EventListenerList(); actionEvent = new ActionEvent(this,0,"KeyAction"); addMouseListener(this); addMouseMotionListener(this); addKeyListener(this); setRequestFocusEnabled(true); // Make the necessary selection actions. makeSelectionActions(); // Make the popup menu. popup = new JPopupMenu(); processingPopup = false; // Get the popup menu. JPopupMenu popup = getPopupMenu(); // Add items to this popup. JMenuItem item; // Add all of the selection actions. Iterator i = selectionActions.iterator(); while (i.hasNext()) { Action action = (Action) i.next(); item = new JMenuItem(action); KeyStroke accelerator = (KeyStroke) action.getValue(Action.ACCELERATOR_KEY); addActionEntry(accelerator,action); item.setAccelerator(accelerator); popup.add(item); } popup.addSeparator(); item = new JMenuItem(nextAction); KeyStroke accelerator = (KeyStroke) nextAction.getValue(Action.ACCELERATOR_KEY); addActionEntry(accelerator,nextAction); item.setAccelerator(accelerator); popup.add(item); item = new JMenuItem(previousAction); accelerator = (KeyStroke) previousAction.getValue(Action.ACCELERATOR_KEY); addActionEntry(accelerator,previousAction); item.setAccelerator(accelerator); popup.add(item); item = new JMenuItem(defaultModeAction); accelerator = (KeyStroke) defaultModeAction.getValue(Action.ACCELERATOR_KEY); addActionEntry(accelerator,defaultModeAction); item.setAccelerator(accelerator); popup.add(item); } /** * This makes all of the selection actions and binds them to specific * keys. */ private void makeSelectionActions() { // Make the zoom actions. Action action = new SelectionAction("Zoom",GraphicalSelectionEvent.ZOOM, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0)); selectionActions.add(action); addActionEntry(KeyEvent.VK_ENTER,action); action = new SelectionAction("Zoom (new view)", GraphicalSelectionEvent.ZOOM_NEW_VIEW, KeyStroke.getKeyStroke(KeyEvent.VK_V,0)); selectionActions.add(action); addActionEntry(KeyEvent.VK_N,action); // Make all of the picking actions. action = new SelectionAction("Pick", GraphicalSelectionEvent.PICK, KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,0)); selectionActions.add(action); addActionEntry(KeyEvent.VK_SPACE,action); action = new SelectionAction("Pick (add)", GraphicalSelectionEvent.PICK_ADD, KeyStroke.getKeyStroke(KeyEvent.VK_PLUS,0)); selectionActions.add(action); addActionEntry(KeyEvent.VK_EQUALS,action); addActionEntry(KeyEvent.VK_PLUS,action); action = new SelectionAction("Un-Pick", GraphicalSelectionEvent.UNPICK, KeyStroke.getKeyStroke(KeyEvent.VK_MINUS,0)); selectionActions.add(action); addActionEntry(KeyEvent.VK_UNDERSCORE,action); addActionEntry(KeyEvent.VK_MINUS,action); action = new ClearAction(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,0)); selectionActions.add(action); addActionEntry(KeyEvent.VK_ESCAPE,action); addActionEntry(KeyEvent.VK_BACK_SPACE,action); addActionEntry(KeyEvent.VK_DELETE,action); } /** * Activate or inactivate all of the selection actions. */ protected void setSelectionActionsEnabled(boolean enable) { Iterator i = selectionActions.iterator(); while (i.hasNext()) { Action action = (Action) i.next(); action.setEnabled(enable); } } /** * The default implementation of this method does nothing. * Subclasses should provide the needed functionality to ensure * that the selection is no longer visible after this method is * called. */ public void resetSelection() { } /** * This method returns the popup menu for this component. This * may be modified by subclasses of this event to provide needed * menu items. * * @return the component's popup menu */ public JPopupMenu getPopupMenu() { return popup; } /** * This resets a flag which indicates when a popup menu is being * processed. This should be called by subclasses when the * ActionEvent from a popup menu is received. */ protected void cancelPopupProcessing() { processingPopup = false; } /** * This method determines whether or not a popup menu is being * processed. If it is then this will return true and the mouse * event should be ignored. * * @param e MouseEvent passed into mouse handling routine * * @return a boolean indicating whether or not to ignore the mouse * event */ public boolean isProcessingPopup(MouseEvent e) { int id = e.getID(); boolean flag = processingPopup; if (id==MouseEvent.MOUSE_PRESSED) { if (!processingPopup && testPopupTrigger(e)) { getPopupMenu().show(e.getComponent(), e.getX(),e.getY()); processingPopup = true; flag = true; } } else if (id==MouseEvent.MOUSE_RELEASED) { if (!processingPopup && testPopupTrigger(e)) { getPopupMenu().show(e.getComponent(), e.getX(),e.getY()); processingPopup = true; flag = true; } else if (processingPopup && !getPopupMenu().isVisible()) { processingPopup = false; flag = true; } } return flag; } /** * This component does not support borders. If this method is * called with any non-null argument, then an * IllegalArgumentException is thrown. If a border is desired, * then this component should be embedded within container which * has one. * * @param border must be null */ public final void setBorder(Border border) { if (border!=null) throw new IllegalArgumentException(NON_NULL_BORDER_ERROR); } /** * This component does not support borders. Null is always * returned by this method. * * @return null */ public final Border getBorder() { return null; } /** * Moves and resizes this component. This is overridden so that * the selection can be reset if the size changes. * * @param x x-coordinate of component * @param y y-coordinate of component * @param width width of the component * @param height height of the component */ public void setBounds(int x, int y, int width, int height) { resetSelection(); super.setBounds(x,y,width,height); } /** * Add a GraphicalSelectionListener. * * @param listener the GraphicalSelectionListener to add */ public void addGraphicalSelectionListener(GraphicalSelectionListener listener) { listenerList.add(GraphicalSelectionListener.class, listener); } /** * Remove a GraphicalSelectionListener. * * @param listener the GraphicalSelectionListener to remove */ public void removeGraphicalSelectionListener(GraphicalSelectionListener listener) { listenerList.remove(GraphicalSelectionListener.class, listener); } /** * Send the GraphicalSelectionMade event to all currently * registered GraphicalSelectionListeners. * * @param gsEvent the GraphicalSelectionEvent which is sent to all * currently registered GraphicalSelectionListeners */ protected void fireGraphicalSelectionMade(GraphicalSelectionEvent gsEvent){ Object[] listeners = listenerList.getListenerList(); for (int i=listeners.length-2; i>=0; i-=2) { if (listeners[i]==GraphicalSelectionListener.class) { ((GraphicalSelectionListener)listeners[i+1]). graphicalSelectionMade(gsEvent); } } } /** * Invoked when the mouse has been clicked on a component. This * is an empty method which subclasses should override if * necessary. * * @param e MouseEvent describing action */ public void mouseClicked(MouseEvent e) {} /** * Invoked when the mouse enters a component. This method just * requests the keyboard focus. Subclasses which override this * method should also request the keyboard focus with a call to * requestFocus(). * * @param e MouseEvent describing action */ public void mouseEntered(MouseEvent e) { requestFocus(); } /** * Invoked when the mouse exits a component. This is an empty * method which subclasses should override if necessary. * * @param e MouseEvent describing action */ public void mouseExited(MouseEvent e) {} /** * Invoked when the mouse button has been pressed on a component. * This is an empty method which subclasses should override if * necessary. * * @param e MouseEvent describing action */ public void mousePressed(MouseEvent e) {} /** * Invoked when a mouse button has been released on a component. * This is an empty method which subclasses should override if * necessary. * * @param e MouseEvent describing action */ public void mouseReleased(MouseEvent e) {} /** * Invoked when a mouse button is pressed on a component and then * dragged. This is an empty method which subclasses should * override if necessary. * * @param e MouseEvent describing action */ public void mouseDragged(MouseEvent e) {} /** * Invoked when the mouse button has been moved on a component * (with no buttons down). This is an empty method which * subclasses should override if necessary. * * @param e MouseEvent describing action */ public void mouseMoved(MouseEvent e) {} /** * Invoked when a key has been pressed. This is an empty method * which subclasses should override if necessary. * * @param e KeyEvent describing key which has been pressed. */ public void keyPressed(KeyEvent e) {} /** * Process key-released events. This defines and uses the following key * bindings: * * Subclasses may override this method to provide additional * key-bindings. However if the subclass doesn't handle a particular * key event, this method should be called. * * @param e KeyEvent describing the key which has been released */ public void keyReleased(KeyEvent e) { // Get the keystroke. Ignore the modifiers for all keys except the // arrow keys. int keyCode = e.getKeyCode(); int modifiers = 0; KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode,modifiers); InputMap inputMap = getInputMap(); Object actionKey = inputMap.get(keyStroke); if (actionKey!=null) { Action action = (Action) actionMap.get(actionKey); if (action!=null) { action.actionPerformed(actionEvent); } } } /** * Invoked when a key has been typed. This is an empty method * which subclasses should override if necessary. * * @param e KeyEvent describing key which has been typed. */ public void keyTyped(KeyEvent e) {} /** * A utility function which creates an appropriate selection event * when the user accepts the current selection and sends it to all * listeners. */ protected void makeSelectionEvent(int type) {} /** * A utility method which tests to see if the given mouse event * should trigger the popup menu. Normally, Java itself has an * isPopupTrigger() method, but this doesn't work reliably under * Windows. This method will return true if the mouse click is on * the right button. */ protected boolean testPopupTrigger(MouseEvent e) { int modifiers = e.getModifiers(); return ((modifiers & InputEvent.BUTTON3_MASK)!=0); } /** * This class defines the Select action. This causes a * GraphicalSelectionEvent to be generated and sent to all * listeners. */ class SelectionAction extends AbstractAction { private int actionCode; public SelectionAction(String name, int actionCode) { super(name); this.actionCode = actionCode; } public SelectionAction(String name, int actionCode, KeyStroke keyStroke) { this(name,actionCode); putValue(ACCELERATOR_KEY,keyStroke); } public void actionPerformed(ActionEvent e) { cancelPopupProcessing(); if (isEnabled()) { makeSelectionEvent(actionCode); } } } /** * This class defines the Clear action. This causes the current * selection to be cleared. */ class ClearAction extends AbstractAction { public ClearAction(KeyStroke keyStroke) { super("Clear"); putValue(ACCELERATOR_KEY,keyStroke); } public void actionPerformed(ActionEvent e) { cancelPopupProcessing(); resetSelection(); } } /** * This utility method binds an action to a particular key. The * associated action will be done when the given key is typed. */ protected void addActionEntry(int keyCode, Action action) { KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode,0); addActionEntry(keyStroke,action); } /** * This utility method binds an action to a KeyStroke. The associated * action will be done when the given KeyStroke is encountered. */ protected void addActionEntry(KeyStroke keyStroke, Action action) { Object actionMapKey = action.getValue(Action.NAME); actionMap.put(actionMapKey,action); InputMap inputMap = getInputMap(); inputMap.put(keyStroke,actionMapKey); } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/graphics/SquareSelectionPanel.java0000644012010301201030000001522010466735775032012 0ustar mascellanimascellani// Charles A. Loomis, Jr., and University of California, Santa Cruz, // Copyright (c) 2000 package org.freehep.swing.graphics; import java.awt.Color; import java.awt.Cursor; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.util.Arrays; import org.freehep.swing.images.FreeHepImage; /** * A panel which selects a "square" region on the screen. The * definition of "square" is that this region will retain the relative * scaling of the x and y-axes. * * @author Charles Loomis * @author Mark Donszelmann * @version $Id: SquareSelectionPanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class SquareSelectionPanel extends AbstractRegionSelectionPanel { /** * Creates a SquareSelectionPanel. */ public SquareSelectionPanel() { super(); } /** * Return the number of control points,5---the four corners and * one point in the center of the square. * * @return 5 the number of control points */ public int getNumberOfControlPoints() { return 5; } /** * Returns the NE, SE, NW and SW cursors for the four different * directions and SquareCursor as the default */ public Cursor getControlPointCursor(int index) { switch (index) { case NO_CONTROL_POINT: return FreeHepImage.getCursor("SquareCursor"); case 4: return FreeHepImage.getCursor("0_MoveCursor", 16, 16); default: return compassCursor("Resize", xCtrlPts[index] - xCtrlPts[4], yCtrlPts[index] - yCtrlPts[4], 4, true); } } /** * Initialize the control points based on the starting point * (x,y). * * @param x x-coordinate of starting point * @param y y-coordinate of starting point */ public void initializeControlPoints(int x, int y) { activeCtrlPt = 0; Arrays.fill(xCtrlPts,x); Arrays.fill(yCtrlPts,y); } /** * Move the active control point to the point (x,y). * * @param x x-coordinate of the new point * @param y y-coordinate of the new point */ public void updateActiveControlPoint(int x, int y) { // Bring the location within bounds. x = forceXCoordinateWithinBounds(x); y = forceYCoordinateWithinBounds(y); if (activeCtrlPt==4) { // Get the change in the center point. int dx = x - xCtrlPts[4]; int dy = y - yCtrlPts[4]; // Change all control points by this amount. for (int i=0; i= 0) { // Draw the active control point. g.setColor(Color.black); g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize-1, yCtrlPts[activeCtrlPt]-ctrlPtSize-1, 2*ctrlPtSize+3, 2*ctrlPtSize+3); g.setColor(Color.white); g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize, yCtrlPts[activeCtrlPt]-ctrlPtSize, 2*ctrlPtSize+1, 2*ctrlPtSize+1); } } } /** * Make the affine transform which corresponds to this "square" * selection. * * @return AffineTransform which describes the selected region */ public AffineTransform makeAffineTransform() { // Do a bit of calculation to maintain the aspect ratio. double dx = Math.abs(xCtrlPts[0]-xCtrlPts[4]); double dy = (dx*getHeight())/getWidth(); double x0 = xCtrlPts[4]-dx; double y0 = yCtrlPts[4]-dy; double x1 = xCtrlPts[4]+dx; double y1 = yCtrlPts[4]-dy; double x2 = xCtrlPts[4]+dx; double y2 = yCtrlPts[4]+dy; // Now call the utility function of the parent. return makeTransform(x0,y0,x1,y1,x2,y2); } /** * Determine if the selection is valid; regions of zero area are * considered invalid. * * @return flag indicating whether the region is valid */ public boolean isValidSelection() { return (visible) && (xCtrlPts[0]!=xCtrlPts[2] || yCtrlPts[0]!=yCtrlPts[2]); } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/graphics/YSkewSelectionPanel.java0000644012010301201030000002075710466735775031627 0ustar mascellanimascellani// Charles A. Loomis, Jr., and University of California, Santa Cruz, // Copyright (c) 2000 package org.freehep.swing.graphics; import java.awt.Color; import java.awt.Cursor; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.util.Arrays; import org.freehep.swing.images.FreeHepImage; /** * A panel which selects a parallogram-shaped region in which two * sides are parallel to the x-axis and the other two are skewed with * respect to the y-axis. * * @author Charles Loomis * @version $Id: YSkewSelectionPanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class YSkewSelectionPanel extends AbstractRegionSelectionPanel { /** * The initial starting width of the skewed rectangle. */ final private static int STARTING_WIDTH = 25; /** * Creates a YSkewSelectionPanel. */ public YSkewSelectionPanel() { super(); } /** * Get the number of control points 6---the four corners and the * centerpoints of the two sides parallel to the x-axis. * * @return 6 the number of control points */ public int getNumberOfControlPoints() { return 6; } public Cursor getControlPointCursor(int index) { int k; switch(index) { case 0: case 3: k = 4; break; case 1: case 2: k = 5; break; case 4: case 5: return FreeHepImage.getCursor("0_MoveCursor", 16, 16); default: return FreeHepImage.getCursor("YSkewCursor"); } return compassCursor("Resize", xCtrlPts[index] - xCtrlPts[k], yCtrlPts[index] - yCtrlPts[k], 4, false); } /** * Initialize the control points based on the starting point * (x,y). * * @param x x-coordinate of the starting point * @param y y-coordinate of the starting point */ public void initializeControlPoints(int x, int y) { // Set the fifth control point to be the active one and // initialize all of the coordinates. activeCtrlPt = 5; Arrays.fill(yCtrlPts,y); xCtrlPts[0] = x-STARTING_WIDTH; xCtrlPts[1] = x-STARTING_WIDTH; xCtrlPts[2] = x+STARTING_WIDTH; xCtrlPts[3] = x+STARTING_WIDTH; xCtrlPts[4] = x; xCtrlPts[5] = x; } /** * Move the active control point to the point (x,y). * * @param x x-coordinate of the new point * @param y y-coordinate of the new point */ public void updateActiveControlPoint(int x, int y) { // Bring the location within bounds. x = forceXCoordinateWithinBounds(x); y = forceYCoordinateWithinBounds(y); // Change what is done depending on which control point is // active. int width; switch (activeCtrlPt) { case 0: width = x-xCtrlPts[4]; xCtrlPts[0] = xCtrlPts[4]+width; xCtrlPts[1] = xCtrlPts[5]+width; xCtrlPts[2] = xCtrlPts[5]-width; xCtrlPts[3] = xCtrlPts[4]-width; break; case 1: width = x-xCtrlPts[5]; xCtrlPts[0] = xCtrlPts[4]+width; xCtrlPts[1] = xCtrlPts[5]+width; xCtrlPts[2] = xCtrlPts[5]-width; xCtrlPts[3] = xCtrlPts[4]-width; break; case 2: width = x-xCtrlPts[5]; xCtrlPts[0] = xCtrlPts[4]-width; xCtrlPts[1] = xCtrlPts[5]-width; xCtrlPts[2] = xCtrlPts[5]+width; xCtrlPts[3] = xCtrlPts[4]+width; break; case 3: width = x-xCtrlPts[4]; xCtrlPts[0] = xCtrlPts[4]-width; xCtrlPts[1] = xCtrlPts[5]-width; xCtrlPts[2] = xCtrlPts[5]+width; xCtrlPts[3] = xCtrlPts[4]+width; break; case 4: // Determine the width. width = xCtrlPts[4] - xCtrlPts[0]; // Update the active control point. xCtrlPts[activeCtrlPt] = x; yCtrlPts[activeCtrlPt] = y; // Update the control points on either side. xCtrlPts[0] = x-width; yCtrlPts[0] = y; xCtrlPts[3] = x+width; yCtrlPts[3] = y; break; case 5: // Determine the width. width = xCtrlPts[4] - xCtrlPts[0]; // Update the active control point. xCtrlPts[activeCtrlPt] = x; yCtrlPts[activeCtrlPt] = y; // Update the control points on either side. xCtrlPts[1] = x-width; yCtrlPts[1] = y; xCtrlPts[2] = x+width; yCtrlPts[2] = y; break; default: break; } repaintPanel(); } public void paintComponent(Graphics g) { // Allow parent to draw any custom painting. super.paintComponent(g); // If the selection region is visible, paint it. if (visible) { // Make a 2D graphics context. Graphics2D g2d = (Graphics2D) g; // Draw a rectangle on top the the image. g2d.setStroke(thickStroke); g.setColor(Color.black); g.drawPolygon(xCtrlPts, yCtrlPts, 4); if (visibleGuides) { g.drawLine(xCtrlPts[4], yCtrlPts[4], xCtrlPts[5], yCtrlPts[5]); } g2d.setStroke(thinStroke); g.setColor(Color.white); g.drawPolygon(xCtrlPts, yCtrlPts, 4); if (visibleGuides) { g.drawLine(xCtrlPts[4], yCtrlPts[4], xCtrlPts[5], yCtrlPts[5]); } // Draw the active control point. if (activeCtrlPt >= 0) { g.setColor(Color.black); g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize-1, yCtrlPts[activeCtrlPt]-ctrlPtSize-1, 2*ctrlPtSize+3, 2*ctrlPtSize+3); g.setColor(Color.white); g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize, yCtrlPts[activeCtrlPt]-ctrlPtSize, 2*ctrlPtSize+1, 2*ctrlPtSize+1); } } } /** * Make the affine transform which corresponds to this skewed * selection. * * @return AffineTransform which describes the selected region */ public AffineTransform makeAffineTransform() { // Find first the upper, left-hand point. This is the one // with the smallest y-value and then the smallest x-value. int first = 0; int xSavedValue = xCtrlPts[first]; int ySavedValue = yCtrlPts[first]; for (int i=1; i<4; i++) { int xValue = xCtrlPts[i]; int yValue = yCtrlPts[i]; if (yValue0) second = (first+3)%4; // Now call the utility function of the parent. return makeTransform((double) xCtrlPts[first], (double) yCtrlPts[first], (double) xCtrlPts[second], (double) yCtrlPts[second], (double) xCtrlPts[third], (double) yCtrlPts[third]); } /** * Check that the selection region is valid; regions with zero * area are invalid. * * @return flag indicating whether this region is valid */ public boolean isValidSelection() { return (visible) && (yCtrlPts[4]!=yCtrlPts[5]) && (xCtrlPts[0]!=xCtrlPts[3]); } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/graphics/RotatedRectangleSelectionPanel.java0000644012010301201030000003274710466735775034016 0ustar mascellanimascellani// Charles A. Loomis, Jr., and University of California, Santa Cruz, // Copyright (c) 2000 package org.freehep.swing.graphics; import java.awt.Color; import java.awt.Cursor; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.util.Arrays; import org.freehep.swing.images.FreeHepImage; /** * A panel which selects a rectangular region on the screen which can * be arbitrarily rotated. * * @author Charles Loomis * @author Mark Donszelmann * @version $Id: RotatedRectangleSelectionPanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class RotatedRectangleSelectionPanel extends AbstractRegionSelectionPanel { /** * The initial starting width of the first and last sides. */ final private static int STARTING_WIDTH = 25; /** * Creates a RotatedRectangleSelectionPanel. */ public RotatedRectangleSelectionPanel() { super(); } /** * The number of control points is 6---the four corners and the * centerpoints of the first and last sides. * * @return 6 the number of control points */ public int getNumberOfControlPoints() { return 6; } public Cursor getControlPointCursor(int index) { int k; String type; switch(index) { case 0: case 3: k = 4; type = "Resize"; break; case 1: case 2: k = 5; type = "Resize"; break; case 4: k = 5; type = "Rotation"; break; case 5: k = 4; type = "Rotation"; break; default: return FreeHepImage.getCursor("RotatedRectangleCursor"); } return compassCursor(type, xCtrlPts[index] - xCtrlPts[k], yCtrlPts[index] - yCtrlPts[k], 8, true); } /** * Initialize the control points given the starting point (x,y). * * @param x x-coordinate of the starting point * @param y y-coordinate of the starting point */ public void initializeControlPoints(int x, int y) { // Set the fifth control point to be the active one and // initialize all of the coordinates. activeCtrlPt = 5; Arrays.fill(yCtrlPts,y); xCtrlPts[0] = x-STARTING_WIDTH; xCtrlPts[1] = x-STARTING_WIDTH; xCtrlPts[2] = x+STARTING_WIDTH; xCtrlPts[3] = x+STARTING_WIDTH; xCtrlPts[4] = x; xCtrlPts[5] = x; } /** * Move the active control point to the point (x,y). * * @param x x-coordinate of the new point * @param y y-coordinate of the new point */ public void updateActiveControlPoint(int x, int y) { // Bring the location within bounds. x = forceXCoordinateWithinBounds(x); y = forceYCoordinateWithinBounds(y); // Change what is done depending on which control point is // active. int dx; int dy; int deltax; int deltay; double angle; double radius; switch (activeCtrlPt) { case 0: // Determine the radius of the corners from the middle of // the control sides. radius = getRadius(x,y,4); // Get the angle of the rotated rectangle. angle = getAngle(); deltax = x - xCtrlPts[4]; deltay = y - yCtrlPts[4]; dx = (int) -Math.round(radius*Math.sin(angle)); dy = (int) Math.round(radius*Math.cos(angle)); if (deltax*dx+deltay*dy < 0) { dx = -dx; dy = -dy; } // Update the other control points. xCtrlPts[0] = xCtrlPts[4]+dx; yCtrlPts[0] = yCtrlPts[4]+dy; xCtrlPts[3] = xCtrlPts[4]-dx; yCtrlPts[3] = yCtrlPts[4]-dy; xCtrlPts[1] = xCtrlPts[5]+dx; yCtrlPts[1] = yCtrlPts[5]+dy; xCtrlPts[2] = xCtrlPts[5]-dx; yCtrlPts[2] = yCtrlPts[5]-dy; break; case 1: // Determine the radius of the corners from the middle of // the control sides. radius = getRadius(x,y,5); // Get the angle of the rotated rectangle. angle = getAngle(); deltax = x - xCtrlPts[5]; deltay = y - yCtrlPts[5]; dx = (int) -Math.round(radius*Math.sin(angle)); dy = (int) Math.round(radius*Math.cos(angle)); if (deltax*dx+deltay*dy < 0) { dx = -dx; dy = -dy; } // Update the other control points. xCtrlPts[0] = xCtrlPts[4]+dx; yCtrlPts[0] = yCtrlPts[4]+dy; xCtrlPts[3] = xCtrlPts[4]-dx; yCtrlPts[3] = yCtrlPts[4]-dy; xCtrlPts[1] = xCtrlPts[5]+dx; yCtrlPts[1] = yCtrlPts[5]+dy; xCtrlPts[2] = xCtrlPts[5]-dx; yCtrlPts[2] = yCtrlPts[5]-dy; break; case 2: // Determine the radius of the corners from the middle of // the control sides. radius = getRadius(x,y,5); // Get the angle of the rotated rectangle. angle = getAngle(); deltax = x - xCtrlPts[5]; deltay = y - yCtrlPts[5]; dx = (int) -Math.round(radius*Math.sin(angle)); dy = (int) Math.round(radius*Math.cos(angle)); if (deltax*dx+deltay*dy < 0) { dx = -dx; dy = -dy; } // Update the other control points. xCtrlPts[0] = xCtrlPts[4]-dx; yCtrlPts[0] = yCtrlPts[4]-dy; xCtrlPts[3] = xCtrlPts[4]+dx; yCtrlPts[3] = yCtrlPts[4]+dy; xCtrlPts[1] = xCtrlPts[5]-dx; yCtrlPts[1] = yCtrlPts[5]-dy; xCtrlPts[2] = xCtrlPts[5]+dx; yCtrlPts[2] = yCtrlPts[5]+dy; break; case 3: // Determine the radius of the corners from the middle of // the control sides. radius = getRadius(x,y,4); // Get the angle of the rotated rectangle. angle = getAngle(); deltax = x - xCtrlPts[4]; deltay = y - yCtrlPts[4]; dx = (int) -Math.round(radius*Math.sin(angle)); dy = (int) Math.round(radius*Math.cos(angle)); if (deltax*dx+deltay*dy < 0) { dx = -dx; dy = -dy; } // Update the other control points. xCtrlPts[0] = xCtrlPts[4]-dx; yCtrlPts[0] = yCtrlPts[4]-dy; xCtrlPts[3] = xCtrlPts[4]+dx; yCtrlPts[3] = yCtrlPts[4]+dy; xCtrlPts[1] = xCtrlPts[5]-dx; yCtrlPts[1] = yCtrlPts[5]-dy; xCtrlPts[2] = xCtrlPts[5]+dx; yCtrlPts[2] = yCtrlPts[5]+dy; break; case 4: /* Fall through! */ case 5: // Determine the radius of the corners from the middle of // the control sides. radius = getRadius(xCtrlPts[0], yCtrlPts[0], 4); // Update the active control point. xCtrlPts[activeCtrlPt] = x; yCtrlPts[activeCtrlPt] = y; // Get the angle of the rotated rectangle. angle = getAngle(); dx = (int) -Math.round(radius*Math.sin(angle)); dy = (int) Math.round(radius*Math.cos(angle)); // Update the other control points. xCtrlPts[0] = xCtrlPts[4]+dx; yCtrlPts[0] = yCtrlPts[4]+dy; xCtrlPts[3] = xCtrlPts[4]-dx; yCtrlPts[3] = yCtrlPts[4]-dy; xCtrlPts[1] = xCtrlPts[5]+dx; yCtrlPts[1] = yCtrlPts[5]+dy; xCtrlPts[2] = xCtrlPts[5]-dx; yCtrlPts[2] = yCtrlPts[5]-dy; break; default: break; } repaintPanel(); } /** * A utility routine to get the radius from one of the control * points. */ private double getRadius(int x, int y, int ctrlPt) { int dx = x - xCtrlPts[ctrlPt]; int dy = y - yCtrlPts[ctrlPt]; return Math.sqrt((double) (dx*dx+dy*dy)); } /** * A utility routine to get the angle of the rotated rectangle. */ private double getAngle() { // Get the angle of the rotated rectangle. double deltax = xCtrlPts[5] - xCtrlPts[4]; double deltay = yCtrlPts[5] - yCtrlPts[4]; if (deltax!=0 || deltay!=0) { return Math.atan2(deltay,deltax); } else { return 0.; } } public void paintComponent(Graphics g) { // Allow parent to draw any custom painting. super.paintComponent(g); // If the selection region is visible, paint it. if (visible) { // Make a 2D graphics context. Graphics2D g2d = (Graphics2D) g; // Draw a rectangle on top the the image. g2d.setStroke(thickStroke); g.setColor(Color.black); g.drawPolygon(xCtrlPts, yCtrlPts, 4); if (visibleGuides) { g.drawLine(xCtrlPts[4], yCtrlPts[4], xCtrlPts[5], yCtrlPts[5]); } g2d.setStroke(thinStroke); g.setColor(Color.white); g.drawPolygon(xCtrlPts, yCtrlPts, 4); if (visibleGuides) { g.drawLine(xCtrlPts[4], yCtrlPts[4], xCtrlPts[5], yCtrlPts[5]); } if (activeCtrlPt >= 0) { // Draw the active control point. g.setColor(Color.black); g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize-1, yCtrlPts[activeCtrlPt]-ctrlPtSize-1, 2*ctrlPtSize+3, 2*ctrlPtSize+3); g.setColor(Color.white); g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize, yCtrlPts[activeCtrlPt]-ctrlPtSize, 2*ctrlPtSize+1, 2*ctrlPtSize+1); } } } /** * Make the affine transform which corresponds to this rectangular * selection. * * @return AffineTransform which describes the selected region */ public AffineTransform makeAffineTransform() { // Find first the upper, left-hand point. int first = 0; int savedValue = xCtrlPts[0]*xCtrlPts[0]+yCtrlPts[0]*yCtrlPts[0]; for (int i=1; i<4; i++) { int value = xCtrlPts[i]*xCtrlPts[i]+yCtrlPts[i]*yCtrlPts[i]; if (value0) second = (first+3)%4; // Get the appropriate radius. int centerIndex = (first==0 || first==3) ? 4 : 5; double radius = getRadius(xCtrlPts[first], yCtrlPts[first], centerIndex); double angle = getAngle(); // Calculate the delta-x and delta-y for the points. double dx = Math.abs(radius*Math.sin(angle)); double dy = Math.abs(radius*Math.cos(angle)); // Get the sign of the offsets from the control points. double sdx; double sdy; // The point closest to the origin. centerIndex = (first==0 || first==3) ? 4 : 5; sdx = ((xCtrlPts[first]-xCtrlPts[centerIndex])>0) ? 1. : -1.; sdy = ((yCtrlPts[first]-yCtrlPts[centerIndex])>0) ? 1. : -1.; double x0 = xCtrlPts[centerIndex]+sdx*dx; double y0 = yCtrlPts[centerIndex]+sdy*dy; // The next point clockwise. centerIndex = (second==0 || second==3) ? 4 : 5; sdx = ((xCtrlPts[second]-xCtrlPts[centerIndex])>0) ? 1. : -1.; sdy = ((yCtrlPts[second]-yCtrlPts[centerIndex])>0) ? 1. : -1.; double x1 = xCtrlPts[centerIndex]+sdx*dx; double y1 = yCtrlPts[centerIndex]+sdy*dy; // The next point clockwise. centerIndex = (third==0 || third==3) ? 4 : 5; sdx = ((xCtrlPts[third]-xCtrlPts[centerIndex])>0) ? 1. : -1.; sdy = ((yCtrlPts[third]-yCtrlPts[centerIndex])>0) ? 1. : -1.; double x2 = xCtrlPts[centerIndex]+sdx*dx; double y2 = yCtrlPts[centerIndex]+sdy*dy; // The control points are in the correct order, so we can just // call the utility function of the parent. return makeTransform(x0,y0,x1,y1,x2,y2); } /** * Check that the area of the selection is non-zero. * * @return flag indicating whether the selection is valid */ public boolean isValidSelection() { return (visible) && (xCtrlPts[4]!=xCtrlPts[5] || yCtrlPts[4]!=yCtrlPts[5]) && (xCtrlPts[0]!=xCtrlPts[3] || yCtrlPts[0]!=yCtrlPts[3]); } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/graphics/RectangularSelectionPanel.java0000644012010301201030000001266610466735775033034 0ustar mascellanimascellani// Charles A. Loomis, Jr., and University of California, Santa Cruz, // Copyright (c) 2000 package org.freehep.swing.graphics; import java.awt.Color; import java.awt.Cursor; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.util.Arrays; import org.freehep.swing.images.FreeHepImage; /** * Selects a rectangular screen region. The sides of the rectangle * are parallel to the x and y-axes. * * @author Charles Loomis * @author Mark Donszelmann * @version $Id: RectangularSelectionPanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class RectangularSelectionPanel extends AbstractRegionSelectionPanel { /** * Creates a RectangularSelectionPanel. */ public RectangularSelectionPanel() { super(); } /** * Returns the number of control points for the rectangle (4). * * @return 4, the control points at the corner of the rectangle */ public int getNumberOfControlPoints() { return 4; } public Cursor getControlPointCursor(int index) { if (index >= 0) { int k = (index+2) % 4; return compassCursor("Resize", xCtrlPts[index] - xCtrlPts[k], yCtrlPts[index] - yCtrlPts[k], 4, true); } return FreeHepImage.getCursor("RectangularCursor"); } /** * Initialize the control points based on the given starting point * (x,y). * * @param x x-coordinate (in pixels) of the starting point * @param y y-coordinate (in pixels) fo the starting point */ public void initializeControlPoints(int x, int y) { activeCtrlPt = 2; Arrays.fill(xCtrlPts,x); Arrays.fill(yCtrlPts,y); } /** * Move the active control point to the point (x,y). * * @param x x-coordinate of the new point * @param y y-coordinate of the new point */ public void updateActiveControlPoint(int x, int y) { // Bring the location within bounds. x = forceXCoordinateWithinBounds(x); y = forceYCoordinateWithinBounds(y); // Update the active control point. xCtrlPts[activeCtrlPt] = x; yCtrlPts[activeCtrlPt] = y; // Get the opposite control point. int oppCtrlPt = (activeCtrlPt+2)%nCtrlPts; int xOpp = xCtrlPts[oppCtrlPt]; int yOpp = yCtrlPts[oppCtrlPt]; // Now choose the next control point so that we maintain a // clockwise order to the points. int otherCtrlPt = ((xyOpp)||(x>xOpp && y= 0) { // Draw the active control point. g.setColor(Color.black); g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize-1, yCtrlPts[activeCtrlPt]-ctrlPtSize-1, 2*ctrlPtSize+3, 2*ctrlPtSize+3); g.setColor(Color.white); g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize, yCtrlPts[activeCtrlPt]-ctrlPtSize, 2*ctrlPtSize+1, 2*ctrlPtSize+1); } } } /** * Make the affine transform which corresponds to this rectangular * selection. * * @return AffineTransform which describes the selected region */ public AffineTransform makeAffineTransform() { int second = 0; int third = 0; // Find first the upper, left-hand point. int first = 0; int savedValue = xCtrlPts[0]*xCtrlPts[0]+yCtrlPts[0]*yCtrlPts[0]; for (int i=1; i<4; i++) { int value = xCtrlPts[i]*xCtrlPts[i]+yCtrlPts[i]*yCtrlPts[i]; if (value= 0) { // Draw the active control point. g.setColor(Color.black); g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize-1, yCtrlPts[activeCtrlPt]-ctrlPtSize-1, 2*ctrlPtSize+3, 2*ctrlPtSize+3); g.setColor(Color.white); g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize, yCtrlPts[activeCtrlPt]-ctrlPtSize, 2*ctrlPtSize+1, 2*ctrlPtSize+1); } } } /** * Make the affine transform which corresponds to this slice of * the y-axis. * * @return AffineTransform which describes the selected region */ public AffineTransform makeAffineTransform() { // Sort out which are the three control points. int first = 1; int second = 2; int third = 3; if (yCtrlPts[0]= 0) { // Draw the active control point. g.setColor(Color.black); g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize-1, yCtrlPts[activeCtrlPt]-ctrlPtSize-1, 2*ctrlPtSize+3, 2*ctrlPtSize+3); g.setColor(Color.white); g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize, yCtrlPts[activeCtrlPt]-ctrlPtSize, 2*ctrlPtSize+1, 2*ctrlPtSize+1); } } } /** * Make the affine transform which corresponds to this slice of * the x-axis. * * @return AffineTransform which describes the selected region */ public AffineTransform makeAffineTransform() { // Sort out which are the three control points. int first = 0; int second = 1; int third = 2; if (xCtrlPts[1]=0; j--) { setLayer(comps[j],layer++); } } } } /** * Add an interaction component. Initially the component is * inactive (invisible). */ public void addGraphicalSelectionPanel(GraphicalSelectionPanel panel) { panel.setVisible(false); add(panel, INTERACTION_LAYER); } /** * Remove an interaction component. */ public void removeGraphicalSelectionPanel(GraphicalSelectionPanel panel) { remove(panel); } /** * Make the GraphicalSelectionPanel of the given class active. */ public void activateGraphicalSelectionPanelOfClass(Class c) throws InstantiationException, IllegalAccessException { // Make sure that the class given is a type of // GraphicalSelectionPanel. if (!(GraphicalSelectionPanel.class).isAssignableFrom(c)) { throw new IllegalArgumentException(NEED_GRAPHICAL_SELECTION_PANEL); } // Get an array of interaction components. Component[] components = getComponentsInLayer(INTERACTION_LAYER.intValue()); // Loop over components and see if one if of the correct // class. boolean create = true; for (int i=0; iother.layer) { return 1; } else { if (position>other.position) { return -1; } else if (position *
  • arrow keys: move the active control point in the specified * direction. *
  • backspace key: reset selection region (make invisible). *
  • delete key: reset selection region (make invisible). *
  • escape key: leave selection mode (make component invisible). *
  • enter key: accept selection region (send off region * selected event) * * Normally, the arrow keys move the cursor by 2 pixels per key * release; however if the shift key is pressed simultaneously, * then the arrow keys move the cursor by 1 pixel. * * @author Charles Loomis * @version $Id: PointSelectionPanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class PointSelectionPanel extends GraphicalSelectionPanel { final private static int cursorSize=10; Rectangle oldBounds = new Rectangle(); Rectangle lastDrawnRect = new Rectangle(); Rectangle updateRect = new Rectangle(); // Private class variables. private Point currentPoint = new Point(); // The maximum and minimum values of the coordinates. private int xmin, xmax; private int ymin, ymax; // Flag to indicate whether or not the crosshair cursor is // visible. private boolean cursorVisible; // This is a custom system cursor which is invisible. Used when a // drag is active to avoid the system cursor from obscuring the // crosshairs. private static Cursor invisibleCursor; // Temporary variable to save old cursor so that it can be // restored after the cursor drag has been completed. private Cursor savedCursor; /** * Construct a PointSelectionPanel. Initially the cursor is not * visible. */ public PointSelectionPanel() { cursorVisible = false; setSelectionActionsEnabled(false); BufferedImage cursorImage = new BufferedImage(16,16,BufferedImage.TYPE_INT_ARGB); Graphics g = cursorImage.getGraphics(); g.setColor(new Color(0,0,0,0)); g.fillRect(0,0,16,16); Toolkit toolKit = Toolkit.getDefaultToolkit(); invisibleCursor = toolKit.createCustomCursor(cursorImage, new Point(0,0), "InvisibleCursor"); setCursor(FreeHepImage.getCursor("PointCursor")); } /** * Process key-released events. This allow the selection panel to * move the cursor with the keyboard arrows. * *
      *
    • arrow keys: move the active control point in the specified * direction. *
    • backspace key: reset selection region (make invisible). *
    • delete key: reset selection region (make invisible). *
    • escape key: leave selection mode (make component invisible). *
    • tab key: next selection mode (next component made visible). *
    • enter key: accept selection region (send off region * selected event) *
    • spacebar: accept selection region (send off region * selected event) *
    * Normally, the arrow keys move the cursor by 2 pixels per key * release; however if the shift key is pressed simultaneously, * then the arrow keys move the cursor by 1 pixel. * * @param e KeyEvent describing the key which has been released */ public void keyReleased(KeyEvent e) { // Change the size of the increment in the given direction. int increment = (e.isShiftDown()) ? 1 : 2; switch (e.getKeyCode()) { case KeyEvent.VK_UP: updatePosition(currentPoint.x,currentPoint.y-increment); break; case KeyEvent.VK_DOWN: updatePosition(currentPoint.x,currentPoint.y+increment); break; case KeyEvent.VK_RIGHT: updatePosition(currentPoint.x+increment,currentPoint.y); break; case KeyEvent.VK_LEFT: updatePosition(currentPoint.x-increment,currentPoint.y); break; default: super.keyReleased(e); break; } } /** * The crosshair cursor will begin to follow the system pointer; * the system pointer is made invisible. * * @param e the mouse pressed event to which to respond */ public void mousePressed(MouseEvent e) { if (!isProcessingPopup(e)) { cursorVisible = true; setSelectionActionsEnabled(true); savedCursor = getCursor(); setCursor(invisibleCursor); updatePosition(e.getX(),e.getY()); } } /** * The crosshair cursor will stop following the system pointer * when the mouse is released. The system pointer will again be * visible. * * @param e the mouse release event to which to respond */ public void mouseReleased(MouseEvent e) { if (!isProcessingPopup(e)) { setCursor(savedCursor); updatePosition(e.getX(),e.getY()); } } /** * The crosshair cursor follows the system pointer during a mouse * drag event. * * @param e the mouse drag event to which to respond */ public void mouseDragged(MouseEvent e) { if (!isProcessingPopup(e)) { updatePosition(e.getX(),e.getY()); } } /** * This method updates the position of the crosshair cursor. * Normally this is called internally; however, it can be called * programatically by other object, for example, to move the * cursor on top of a selected object. * * @param x the x coordinate for the cursor (in pixels in the * PointSelectionPanel's coordinate system) * @param y the y coordinate for the cursor (in pixels in the * PointSelectionPanel's coordinate system) */ public void updatePosition(int x, int y) { if (cursorVisible) { // Get the current boundries. xmin = 1; xmax = getWidth()-1; ymin = 1; ymax = getHeight()-1; // Bring the location within bounds. x = Math.max(Math.min(x,xmax),xmin); y = Math.max(Math.min(y,ymax),ymin); currentPoint.setLocation(x,y); // Update the current bounds to be the new position. int xLow = currentPoint.x-cursorSize; int yLow = currentPoint.y-cursorSize; // Repaint the new bounds. updateRect.setBounds(lastDrawnRect); updateRect = SwingUtilities.computeUnion(xLow, yLow, 2*cursorSize, 2*cursorSize, updateRect); repaint(updateRect); } } /** * Set the visiblility of the crosshair cursor. * * @param visible boolean indicating whether or not the crosshair * cursor should be visible */ public void setCursorVisible(boolean visible) { if (cursorVisible!=visible) { cursorVisible = visible; setSelectionActionsEnabled(cursorVisible); repaint(); } } /** * Get the visibility of the crosshair cursor. * * @return boolean indicating whether or not the crosshair cursor * is visible */ public boolean getCursorVisible() { return cursorVisible; } /** * Reset the selection; this remove the crosshair cursor from the * screen. */ public void resetSelection() { cursorVisible = false; updateRect.setBounds(lastDrawnRect); setSelectionActionsEnabled(false); repaint(updateRect); } public void paintComponent(Graphics g) { // Allow parent to draw any custom painting. super.paintComponent(g); if (cursorVisible) { // Make a 2D graphics context. Graphics2D g2d = (Graphics2D) g; // Get the limits. int xLow = currentPoint.x-cursorSize; int xHigh = currentPoint.x+cursorSize; int yLow = currentPoint.y-cursorSize; int yHigh = currentPoint.y+cursorSize; // Paint the crosshairs. g2d.setStroke(thickStroke); g.setColor(Color.black); g.drawLine(currentPoint.x, yLow, currentPoint.x, yHigh); g.drawLine(xLow, currentPoint.y, xHigh, currentPoint.y); g2d.setStroke(thinStroke); g.setColor(Color.white); g.drawLine(currentPoint.x, yLow, currentPoint.x, yHigh); g.drawLine(xLow, currentPoint.y, xHigh, currentPoint.y); // Update the last drawn rectangle. lastDrawnRect.setRect(xLow-1,yLow-1,2*cursorSize+3,2*cursorSize+3); } } /** * Make the affine transform which will center the display on the * current point if applied. * * @return AffineTransform will center the current point */ public AffineTransform makeAffineTransform() { return new AffineTransform(1.,0.,0.,1., getWidth()/2.-currentPoint.x, getHeight()/2.-currentPoint.y); } /** * A utility function which creates an appropriate selection event * when the user accepts the current selection. */ protected void makeSelectionEvent(int actionCode) { switch (actionCode) { case GraphicalSelectionEvent.DEFAULT_MODE: resetSelection(); setVisible(false); fireGraphicalSelectionMade(new GraphicalSelectionEvent(this, GraphicalSelectionEvent.DEFAULT_MODE, null,null)); break; case GraphicalSelectionEvent.NEXT_MODE: resetSelection(); setVisible(false); fireGraphicalSelectionMade(new GraphicalSelectionEvent(this, GraphicalSelectionEvent.NEXT_MODE, null,null)); break; case GraphicalSelectionEvent.PREVIOUS_MODE: resetSelection(); setVisible(false); fireGraphicalSelectionMade(new GraphicalSelectionEvent(this, GraphicalSelectionEvent.PREVIOUS_MODE, null,null)); break; case GraphicalSelectionEvent.ZOOM: case GraphicalSelectionEvent.ZOOM_NEW_VIEW: // For all of the zooming just center the selected point in the // view. if (cursorVisible) { fireGraphicalSelectionMade(new PointSelectionEvent(this,actionCode, currentPoint, makeAffineTransform())); } resetSelection(); break; case GraphicalSelectionEvent.PICK: case GraphicalSelectionEvent.PICK_ADD: case GraphicalSelectionEvent.UNPICK: // For all of the picking modify the transform to center the // selected point on the view, but also to zoom into the n x n // region around this point. if (cursorVisible) { // Get the centering transform. AffineTransform trans = makeAffineTransform(); // Now get the transform which maintains the center of the // view but scales so that +-size pixels fill the view. double size = 20.; double halfWidth = getWidth()/2.; double sx = halfWidth/size; double halfHeight = getHeight()/2.; double sy = halfHeight/size; AffineTransform scaling = new AffineTransform(sx,0.,0.,sy, halfWidth*(1.-sx), halfHeight*(1.-sy)); trans.preConcatenate(scaling); fireGraphicalSelectionMade(new PointSelectionEvent(this,actionCode,currentPoint,trans)); } resetSelection(); break; } } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/graphics/RegionSelectionEvent.java0000644012010301201030000000242310466735775032020 0ustar mascellanimascellani// Charles A. Loomis, Jr., and University of California, Santa Cruz, // Copyright (c) 2000 package org.freehep.swing.graphics; import java.awt.Polygon; import java.awt.geom.AffineTransform; /** * Instances of this class are created when the user graphically * selects a region on the screen. This event gives the object which * generated this event, as well as a polygon describing the outline * of the region and an AffineTransform which can be used to zoom into * the selected region. * * @author Charles Loomis * @version $Id: RegionSelectionEvent.java 8584 2006-08-10 23:06:37Z duns $ */ public class RegionSelectionEvent extends GraphicalSelectionEvent { /** * The constructor requires the source object, the selection type, * and the actual selection. * * @param source the Object which generates this event * @param selection a Polygon describing the outline of the region * @param transform an AffineTransform appropriate for zooming * into the selected region */ public RegionSelectionEvent(Object source, int actionCode, Polygon selection, AffineTransform transform) { super(source,actionCode,selection,transform); } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/graphics/PointSelectionEvent.java0000644012010301201030000000250410466735775031666 0ustar mascellanimascellani// Charles A. Loomis, Jr., and University of California, Santa Cruz, // Copyright (c) 2000 package org.freehep.swing.graphics; import java.awt.Point; import java.awt.geom.AffineTransform; /** * Instances of this class are created when the user graphically * selects a point on the screen. This event gives the object which * generated this event, as well as a polygon describing the outline * of the region and an AffineTransform which can be used to zoom into * the selected region. * * @author Charles Loomis * @version $Id: PointSelectionEvent.java 8584 2006-08-10 23:06:37Z duns $ */ public class PointSelectionEvent extends GraphicalSelectionEvent { /** * The constructor requires the source object and the actual * point selected. The transform should be the one which will * center the display on this point if applied. * * @param source the Object generating this event * @param selection the Point which is selected * @param transform the AffineTransform which will center the * display on the selected point */ public PointSelectionEvent(Object source, int actionCode, Point selection, AffineTransform transform) { super(source,actionCode,selection,transform); } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/graphics/PanelArtistUtilities.java0000644012010301201030000002613410466735775032054 0ustar mascellanimascellani// Charles A. Loomis, Jr., and University of California, Santa Cruz, // Copyright (c) 2000 package org.freehep.swing.graphics; import java.awt.Container; import java.awt.Insets; import java.awt.Rectangle; import java.awt.geom.AffineTransform; import java.awt.geom.RectangularShape; /** * This class is a collection of static methods which are useful for * implementations of the PanelArtist interface. Most methods return * an AffineTransform which will perform some common operation on a * window. * * @author Charles Loomis * @version $Id: PanelArtistUtilities.java 8584 2006-08-10 23:06:37Z duns $ */ public class PanelArtistUtilities { /** * This returns an affine transform which is appropriate for * modifying an existing one for a change in the window size. * (NOTE: that this transform should be pre-concatenated with the * existing one!) The returned transform will satisfy the * following constraints: the centerpoint of the old window will * map to the center point of the new window, a uniform scaling * will be used in both the x and y-directions, the entire visible * region of in the old window will be visible in the new * window. */ public static AffineTransform getResizeTransform(int oldWidth, int oldHeight, int newWidth, int newHeight) { // First calculate the scaling which is necessary. double scale = Math.min((double) newWidth/(double) oldWidth, (double) newHeight/(double) oldHeight); // Now calculate the translation which is necessary. double tx = 0.5*(newWidth-scale*oldWidth); double ty = 0.5*(newHeight-scale*oldHeight); // Now create the transform and return it. return new AffineTransform(scale,0.,0.,scale,tx,ty); } /** * This returns an affine transform which is appropriate for * modifying an existing one for a change in the window size. * (NOTE: that this transform should be pre-concatenated with the * existing one!) The final transform will map the four corners * of the old window to the four corners of the new window. In * general, the scaling in the x and y direction will be * different. */ public static AffineTransform getStretchTransform(int oldWidth, int oldHeight, int newWidth, int newHeight) { // First calculate the scaling which is necessary. double scaleX = (double) newWidth/(double) oldWidth; double scaleY = (double) newHeight/(double) oldHeight; // Now create the transform and return it. return new AffineTransform(scaleX,0.,0.,scaleY,0.,0.); } /** * This returns an affine transform which will keep the center point in * the center and scale the x- and y-directions uniformly by the factor * given. Note that a value of 1 corresponds to the identify transform, * values less than 1 will "zoom out," and values greater than 1 will * "zoom in." (NOTE: that this transform should be pre-concatenated with * the existing one!) */ public static AffineTransform getZoomTransform(double zoomFactor, int width, int height) { double tx = width/2.*(1.-zoomFactor); double ty = height/2.*(1-zoomFactor); return new AffineTransform(zoomFactor,0.,0.,zoomFactor,tx,ty); } /** * This returns an affine transform which will flip the horizontal * axis around. (NOTE: that this transform should be * pre-concatenated with the existing one!) The returned * transform will maintain the centerpoint of the window and flip * the direction of the x-axis. */ public static AffineTransform getXFlipTransform(int width) { return new AffineTransform(-1.,0.,0.,1.,(double) width,0.); } /** * This returns an affine transform which will flip the vertical * axis around. (NOTE: that this transform should be * pre-concatenated with the existing one!) The returned * transform will maintain the centerpoint of the window and flip * the direction of the y-axis. */ public static AffineTransform getYFlipTransform(int height) { return new AffineTransform(1.,0.,0.,-1.,0.,(double) height); } /** * This returns an affine transform which will center the given * point in the window. (NOTE: that this transform should be * pre-concatenated with the existing one!) The returned * transform will move the given point to the center and maintain * the x and y scales. */ public static AffineTransform getCenteringTransform(int newX, int newY, int width, int height) { return new AffineTransform(1.,0.,0.,1., width/2.-newX, height/2.-newY); } /** * This returns an affine transform which will rotate the contents * of the window by 90 degrees. (NOTE: that this transform should * be pre-concatenated with the existing one!) The returned * transform will rotate the contents of the window by 90 degrees * while keeping the centerpoint the same. The x and y-scaling * will be adjusted to keep the same area visible. */ public static AffineTransform getCCWRotateTransform(int width, int height) { return new AffineTransform(0., -((double) height)/width, ((double) width)/height, 0., 0., (double) height); } /** * This returns an affine transform which will rotate the contents * of the window by -90 degrees. (NOTE: that this transform should * be pre-concatenated with the existing one!) The returned * transform will rotate the contents of the window by -90 degrees * while keeping the centerpoint the same. The x and y-scaling * will be adjusted to keep the same area visible. */ public static AffineTransform getCWRotateTransform(int width, int height) { return new AffineTransform(0., ((double) height)/width, -((double) width)/height, 0., (double) width, 0.); } /** * This modifies the supplied affine transform so that the * rectangle given by realBounds will fit inside of the rectangle * given by windowBounds. The center of the realBounds rectangle * will coincide with that of the windowBounds rectangle. * * NOTE: THIS ONLY CORRECTLY HANDLES THE CASE WHEN THE USER SPACE * RECTANGLE IS CENTERED ON THE ORIGIN. * * @param transform the transform which will be modified * @param realBounds the user space rectangle * @param windowBounds the window to map the user rectangle to */ public static void getFittingTransform(AffineTransform transform, RectangularShape realBounds, RectangularShape windowBounds) { if (realBounds==null || windowBounds==null) { transform.setToIdentity(); } else { // Get the dimensions of the windows. double realWidth = realBounds.getWidth(); double realHeight = realBounds.getHeight(); double windowWidth = windowBounds.getWidth(); double windowHeight = windowBounds.getHeight(); if (realWidth>0 && realHeight>0) { // Get the necessary scaling factor. double scaleWidth = windowWidth/realWidth; double scaleHeight = windowHeight/realHeight; double scale = Math.min(scaleWidth,scaleHeight); transform.setTransform(scale,0.,0.,-scale, windowWidth/2.,windowHeight/2.); } else { transform.setToIdentity(); } } } /** * This modifies the supplied affine transform so that the * rectangle given by realBounds will fit exactly inside the * rectangle given by windowBounds. The origins of the realBounds * and the windowBounds coincide; the opposite corner corresponds * to (x0+dx,y0-dy) for the real coordinates. * * @param transform the transform which will be modified * @param realBounds the user space rectangle * @param windowBounds the window to map the user rectangle to */ public static void getFillingTransform(AffineTransform transform, RectangularShape realBounds, RectangularShape windowBounds) { if (realBounds==null || windowBounds==null) { transform.setToIdentity(); } else { // Get the dimensions of the windows. double realWidth = realBounds.getWidth(); double realHeight = realBounds.getHeight(); double windowWidth = windowBounds.getWidth(); double windowHeight = windowBounds.getHeight(); if (realWidth>0 && realHeight>0) { // Get the necessary scaling factor. double scaleWidth = windowWidth/realWidth; double scaleHeight = windowHeight/realHeight; transform.setTransform(scaleWidth,0.,0.,-scaleHeight, -scaleWidth*realBounds.getX(), scaleHeight*realBounds.getY()); } else { transform.setToIdentity(); } } } /** * This returns the "local" bounds of a component. This does the * same calculation as the method of the same name in * SwingUtilities, but this doesn't create a new Rectangle, but * instead overwrites the one passed in. * * @param bounds rectangle to modify with the given component's * bounds (will create new Rectangle if this is null) * @param c component to get the bounds from * * @return convenience reference to the rectangle passed in (or * the created rectangle) */ public static Rectangle getLocalBounds(Rectangle bounds, Container c) { // Create a new Rectangle only if necessary. if (bounds==null) bounds = new Rectangle(); // Get the insets of the components. Insets insets = c.getInsets(); // Set the origin to (0,0) and the width and height to those // of the given component. bounds.setBounds(0,0, c.getWidth()-(insets.left+insets.right), c.getHeight()-(insets.top+insets.bottom)); // Return the given rectangle (or the created one if this was // necessary). return bounds; } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/graphics/ParallelogramSelectionPanel.java0000644012010301201030000002164410466735775033343 0ustar mascellanimascellani// Charles A. Loomis, Jr., and University of California, Santa Cruz, // Copyright (c) 2000 package org.freehep.swing.graphics; import java.awt.Color; import java.awt.Cursor; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.util.Arrays; import org.freehep.swing.images.FreeHepImage; /** * Selects a screen region shaped like a parallelogram. * * @author Charles Loomis * @author Mark Donszelmann * @version $Id: ParallelogramSelectionPanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class ParallelogramSelectionPanel extends AbstractRegionSelectionPanel { /** * The initial starting width (in pixels) of the first and last * sides. */ final private static int STARTING_WIDTH = 25; /** * Creates a ParallelogramSelectionPanel. */ public ParallelogramSelectionPanel() { super(); } /** * The number of control points is 6 for the parallelogram. The * four corners and two at the centerpoints of the first and last * sides. * * @return 6 the number of control points */ public int getNumberOfControlPoints() { return 6; } public Cursor getControlPointCursor(int index) { int k; switch(index) { case 0: case 3: case 5: k = 4; break; case 1: case 2: case 4: k = 5; break; default: return FreeHepImage.getCursor("ParallelogramCursor"); } return compassCursor("Rotation", xCtrlPts[index] - xCtrlPts[k], yCtrlPts[index] - yCtrlPts[k], 8, true); } /** * Initialize the control points for this selection given the * initial starting point (x,y). * * @param x the initial x-coordinate * @param y the initial y-coordinate */ public void initializeControlPoints(int x, int y) { // Set the fifth control point to be the active one and // initialize all of the coordinates. activeCtrlPt = 5; Arrays.fill(yCtrlPts,y); xCtrlPts[0] = x-STARTING_WIDTH; xCtrlPts[1] = x-STARTING_WIDTH; xCtrlPts[2] = x+STARTING_WIDTH; xCtrlPts[3] = x+STARTING_WIDTH; xCtrlPts[4] = x; xCtrlPts[5] = x; } /** * Move the active control point to the point (x,y). * * @param x x-coordinate of the new point * @param y y-coordinate of the new point */ public void updateActiveControlPoint(int x, int y) { // Bring the location within bounds. x = forceXCoordinateWithinBounds(x); y = forceYCoordinateWithinBounds(y); // Change what is done depending on which control point is // active. int dx; int dy; switch (activeCtrlPt) { case 4: // Determine the delta-x and delta-y. dx = xCtrlPts[0] - xCtrlPts[4]; dy = yCtrlPts[0] - yCtrlPts[4]; // Update the active control point. xCtrlPts[activeCtrlPt] = x; yCtrlPts[activeCtrlPt] = y; // Update the control points on either side. xCtrlPts[0] = x+dx; yCtrlPts[0] = y+dy; xCtrlPts[3] = x-dx; yCtrlPts[3] = y-dy; break; case 5: // Determine the delta-x and delta-y. dx = xCtrlPts[1] - xCtrlPts[5]; dy = yCtrlPts[1] - yCtrlPts[5]; // Update the active control point. xCtrlPts[activeCtrlPt] = x; yCtrlPts[activeCtrlPt] = y; // Update the control points on either side. xCtrlPts[1] = x+dx; yCtrlPts[1] = y+dy; xCtrlPts[2] = x-dx; yCtrlPts[2] = y-dy; break; case 0: case 3: // Update the active control point. xCtrlPts[activeCtrlPt] = x; yCtrlPts[activeCtrlPt] = y; // Determine the delta-x and delta-y. dx = xCtrlPts[activeCtrlPt] - xCtrlPts[4]; dy = yCtrlPts[activeCtrlPt] - yCtrlPts[4]; if (activeCtrlPt==3) { dx = -dx; dy = -dy; } xCtrlPts[1] = xCtrlPts[5]+dx; yCtrlPts[1] = yCtrlPts[5]+dy; xCtrlPts[2] = xCtrlPts[5]-dx; yCtrlPts[2] = yCtrlPts[5]-dy; xCtrlPts[0] = xCtrlPts[4]+dx; yCtrlPts[0] = yCtrlPts[4]+dy; xCtrlPts[3] = xCtrlPts[4]-dx; yCtrlPts[3] = yCtrlPts[4]-dy; break; case 1: case 2: // Update the active control point. xCtrlPts[activeCtrlPt] = x; yCtrlPts[activeCtrlPt] = y; // Determine the delta-x and delta-y. dx = xCtrlPts[activeCtrlPt] - xCtrlPts[5]; dy = yCtrlPts[activeCtrlPt] - yCtrlPts[5]; if (activeCtrlPt==2) { dx = -dx; dy = -dy; } xCtrlPts[1] = xCtrlPts[5]+dx; yCtrlPts[1] = yCtrlPts[5]+dy; xCtrlPts[2] = xCtrlPts[5]-dx; yCtrlPts[2] = yCtrlPts[5]-dy; xCtrlPts[0] = xCtrlPts[4]+dx; yCtrlPts[0] = yCtrlPts[4]+dy; xCtrlPts[3] = xCtrlPts[4]-dx; yCtrlPts[3] = yCtrlPts[4]-dy; break; default: break; } repaintPanel(); } /** * Repaint this component. * * @param g Graphics context in which to draw */ public void paintComponent(Graphics g) { // Allow parent to draw any custom painting. super.paintComponent(g); // If the selection region is visible, paint it. if (visible) { // Make a 2D graphics context. Graphics2D g2d = (Graphics2D) g; // Draw a rectangle on top the the image. g2d.setStroke(thickStroke); g.setColor(Color.black); g.drawPolygon(xCtrlPts, yCtrlPts, 4); if (visibleGuides) { g.drawLine(xCtrlPts[4], yCtrlPts[4], xCtrlPts[5], yCtrlPts[5]); } g2d.setStroke(thinStroke); g.setColor(Color.white); g.drawPolygon(xCtrlPts, yCtrlPts, 4); if (visibleGuides) { g.drawLine(xCtrlPts[4], yCtrlPts[4], xCtrlPts[5], yCtrlPts[5]); } if (activeCtrlPt >= 0) { // Draw the active control point. g.setColor(Color.black); g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize-1, yCtrlPts[activeCtrlPt]-ctrlPtSize-1, 2*ctrlPtSize+3, 2*ctrlPtSize+3); g.setColor(Color.white); g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize, yCtrlPts[activeCtrlPt]-ctrlPtSize, 2*ctrlPtSize+1, 2*ctrlPtSize+1); } } } /** * Make the affine transform which corresponds to this * paralleogram-shaped selection. * * @return AffineTransform which describes the selected region */ public AffineTransform makeAffineTransform() { // Find first the upper, left-hand point. int first = 0; int savedValue = xCtrlPts[0]*xCtrlPts[0]+yCtrlPts[0]*yCtrlPts[0]; for (int i=1; i<4; i++) { int value = xCtrlPts[i]*xCtrlPts[i]+yCtrlPts[i]*yCtrlPts[i]; if (value0) second = (first+3)%4; // Now call the utility function of the parent. return makeTransform((double) xCtrlPts[first], (double) yCtrlPts[first], (double) xCtrlPts[second], (double) yCtrlPts[second], (double) xCtrlPts[third], (double) yCtrlPts[third]); } /** * Returns a boolean indicating whether or not the selected region * is valid. It is valid only if the region has a non-zero area. * * @return flag indicating whether the region is valid */ public boolean isValidSelection() { return (makeAffineTransform()!=null); } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/graphics/package.html0000644012010301201030000000012110470537377027325 0ustar mascellanimascellani Swing graphics extensions: extra panels with interaction managers. freehep-swing-2.0.3/src/main/java/org/freehep/swing/graphics/GraphicalSelectionListener.java0000644012010301201030000000171510466735775033176 0ustar mascellanimascellani// Charles A. Loomis, Jr., and University of California, Santa Cruz, // Copyright (c) 2000 package org.freehep.swing.graphics; import java.util.EventListener; /** * This listener interface is intended for objects which wish to be * notified of specific graphical selections made by the user. The * "graphical selection" is a general term which should be made * appropriately concrete by subclasses of GraphicalSelectionEvent and * of GraphicalSelectionPanel. * * @author $Author: duns $ * @version $Id: GraphicalSelectionListener.java 8584 2006-08-10 23:06:37Z duns $ */ public interface GraphicalSelectionListener extends EventListener { /** * Called when the user makes a graphical selection. The * graphical selection is an abstract idea which should be make * specific by subclasses of the GraphicalSelectionEvent and of * GraphicalSelectionPanel. */ public void graphicalSelectionMade(GraphicalSelectionEvent gsEvent); } freehep-swing-2.0.3/src/main/java/org/freehep/swing/graphics/GraphicalSelectionEvent.java0000644012010301201030000001004410466735775032465 0ustar mascellanimascellani// Charles A. Loomis, Jr., and University of California, Santa Cruz, // Copyright (c) 2000 package org.freehep.swing.graphics; import java.awt.geom.AffineTransform; /** * GraphicalSelectionEvent is an event which is generated when an user * makes a graphical selection. This event contains information about * the source, the type of selection which was made, and the selection * type. * * @author Charles Loomis * @version $Id: GraphicalSelectionEvent.java 8584 2006-08-10 23:06:37Z duns $ */ public class GraphicalSelectionEvent extends java.util.EventObject { /** * This action code indicates no action. */ final static public int NO_ACTION = -1; /** * This action code indicates that the view should be zoomed with the * given parameters in the same view. */ final static public int ZOOM = 0; /** * This action code indicates that the view should be cloned and the zoom * applied to the clone. */ final static public int ZOOM_NEW_VIEW = 1; /** * This indicates that the selection should be used to select event * objects. These objects should replace any previously selected * objects. */ final static public int PICK = 2; /** * This indicates that the selection should be used to select event * objects and that these objects should be selected in addition to any * previously selected objects. */ final static public int PICK_ADD = 3; /** * This indicates that the selection should be used to select event * objects and that these objects should be deselected. */ final static public int UNPICK = 4; /** * This indicates that the component should switch to the next selection * mode. */ final static public int NEXT_MODE = 10; /** * This indicates that the component should switch to the previous * selection mode. */ final static public int PREVIOUS_MODE = 11; /** * This indicates that the component should switch to the default * selection mode. */ final static public int DEFAULT_MODE = 13; /** * An integer which describes what should be done with this selection. */ protected int actionCode; /** * The Object which describes the graphical selection which has * been made. */ protected Object selection; /** * The associated AffineTransform to be used if zooming into the * selected region is desired. */ private AffineTransform transform; /** * The constructor requires the source object, the selection type, * and the actual selection. * * @param source the Object which generates this event * @param selection the selection itself * @param actionCode integer giving action to be done * @param transform an AffineTransform which will, for example, * zoom into a selected region */ public GraphicalSelectionEvent(Object source, int actionCode, Object selection, AffineTransform transform) { super(source); this.actionCode = actionCode; this.selection = selection; this.transform = transform; } /** * Get the Object which describes the graphical selection. * * @return Object which describes the selection */ public Object getSelection() { return selection; } /** * Return an AffineTransform which is appropriate for this * selection. For a point, the transform might center the display * on this point. For a region, the transform might zoom into the * selected region. * * @return the appropriate AffineTransform */ public AffineTransform getTransform() { if (transform!=null) { return (AffineTransform) transform.clone(); } else { return null; } } /** * Return the action code for this event. * * @return an integer describing the action which should be taken */ public int getActionCode() { return actionCode; } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/graphics/XSkewSelectionPanel.java0000644012010301201030000002077610466735775031627 0ustar mascellanimascellani// Charles A. Loomis, Jr., and University of California, Santa Cruz, // Copyright (c) 2000 package org.freehep.swing.graphics; import java.awt.Color; import java.awt.Cursor; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.util.Arrays; import org.freehep.swing.images.FreeHepImage; /** * A panel which selects a parallogram-shaped region in which two * sides are parallel to the y-axis and the other two are skewed with * respect to the x-axis. * * @author Charles Loomis * @author Mark Donszelmann * @version $Id: XSkewSelectionPanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class XSkewSelectionPanel extends AbstractRegionSelectionPanel { /** * The initial starting width of the skewed parallogram. */ final private static int STARTING_WIDTH = 25; /** * Creates a XSkewSelectionPanel. */ public XSkewSelectionPanel() { super(); } /** * Return the number of control points 6---the four corners and * the centerpoints of the two sides parallel to the y-axis. * * @return 6 the number of control points */ public int getNumberOfControlPoints() { return 6; } public Cursor getControlPointCursor(int index) { int k; switch(index) { case 0: case 3: k = 4; break; case 1: case 2: k = 5; break; case 4: case 5: return FreeHepImage.getCursor("0_MoveCursor", 16, 16); default: return FreeHepImage.getCursor("XSkewCursor"); } return compassCursor("Resize", xCtrlPts[index] - xCtrlPts[k], yCtrlPts[index] - yCtrlPts[k], 4, false); } /** * Initialize the control points based in the starting point * (x,y). * * @param x x-coordinate of starting point * @param y y-coordinate of starting point */ public void initializeControlPoints(int x, int y) { // Set the fifth control point to be the active one and // initialize all of the coordinates. activeCtrlPt = 5; Arrays.fill(xCtrlPts,x); yCtrlPts[0] = y-STARTING_WIDTH; yCtrlPts[1] = y-STARTING_WIDTH; yCtrlPts[2] = y+STARTING_WIDTH; yCtrlPts[3] = y+STARTING_WIDTH; yCtrlPts[4] = y; yCtrlPts[5] = y; } /** * Move the active control point to the point (x,y). * * @param x x-coordinate of the new point * @param y y-coordinate of the new point */ public void updateActiveControlPoint(int x, int y) { // Bring the location within bounds. x = forceXCoordinateWithinBounds(x); y = forceYCoordinateWithinBounds(y); // Change what is done depending on which control point is // active. int width; switch (activeCtrlPt) { case 0: width = y-yCtrlPts[4]; yCtrlPts[0] = yCtrlPts[4]+width; yCtrlPts[1] = yCtrlPts[5]+width; yCtrlPts[2] = yCtrlPts[5]-width; yCtrlPts[3] = yCtrlPts[4]-width; break; case 1: width = y-yCtrlPts[5]; yCtrlPts[0] = yCtrlPts[4]+width; yCtrlPts[1] = yCtrlPts[5]+width; yCtrlPts[2] = yCtrlPts[5]-width; yCtrlPts[3] = yCtrlPts[4]-width; break; case 2: width = y-yCtrlPts[5]; yCtrlPts[0] = yCtrlPts[4]-width; yCtrlPts[1] = yCtrlPts[5]-width; yCtrlPts[2] = yCtrlPts[5]+width; yCtrlPts[3] = yCtrlPts[4]+width; break; case 3: width = y-yCtrlPts[4]; yCtrlPts[0] = yCtrlPts[4]-width; yCtrlPts[1] = yCtrlPts[5]-width; yCtrlPts[2] = yCtrlPts[5]+width; yCtrlPts[3] = yCtrlPts[4]+width; break; case 4: // Determine the width. width = yCtrlPts[4] - yCtrlPts[0]; // Update the active control point. xCtrlPts[activeCtrlPt] = x; yCtrlPts[activeCtrlPt] = y; // Update the control points on either side. xCtrlPts[0] = x; yCtrlPts[0] = y-width; xCtrlPts[3] = x; yCtrlPts[3] = y+width; break; case 5: // Determine the width. width = yCtrlPts[4] - yCtrlPts[0]; // Update the active control point. xCtrlPts[activeCtrlPt] = x; yCtrlPts[activeCtrlPt] = y; // Update the control points on either side. xCtrlPts[1] = x; yCtrlPts[1] = y-width; xCtrlPts[2] = x; yCtrlPts[2] = y+width; break; default: break; } repaintPanel(); } public void paintComponent(Graphics g) { // Allow parent to draw any custom painting. super.paintComponent(g); // If the selection region is visible, paint it. if (visible) { // Make a 2D graphics context. Graphics2D g2d = (Graphics2D) g; // Draw a rectangle on top the the image. g2d.setStroke(thickStroke); g.setColor(Color.black); g.drawPolygon(xCtrlPts, yCtrlPts, 4); if (visibleGuides) { g.drawLine(xCtrlPts[4], yCtrlPts[4], xCtrlPts[5], yCtrlPts[5]); } g2d.setStroke(thinStroke); g.setColor(Color.white); g.drawPolygon(xCtrlPts, yCtrlPts, 4); if (visibleGuides) { g.drawLine(xCtrlPts[4], yCtrlPts[4], xCtrlPts[5], yCtrlPts[5]); } if (activeCtrlPt >= 0) { // Draw the active control point. g.setColor(Color.black); g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize-1, yCtrlPts[activeCtrlPt]-ctrlPtSize-1, 2*ctrlPtSize+3, 2*ctrlPtSize+3); g.setColor(Color.white); g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize, yCtrlPts[activeCtrlPt]-ctrlPtSize, 2*ctrlPtSize+1, 2*ctrlPtSize+1); } } } /** * Make the affine transform which corresponds to this skewed * region. * * @return AffineTransform which describes the selected region */ public AffineTransform makeAffineTransform() { // Find first the upper, left-hand point. This is the one // with the smallest x-value and then the smallest y-value. int first = 0; int xSavedValue = xCtrlPts[first]; int ySavedValue = yCtrlPts[first]; for (int i=1; i<4; i++) { int xValue = xCtrlPts[i]; int yValue = yCtrlPts[i]; if (xValue0) second = (first+3)%4; // Now call the utility function of the parent. return makeTransform((double) xCtrlPts[first], (double) yCtrlPts[first], (double) xCtrlPts[second], (double) yCtrlPts[second], (double) xCtrlPts[third], (double) yCtrlPts[third]); } /** * Check that the selection is valid; regions with a zero area are * invalid. * * @return flag indicating whether the region is valid */ public boolean isValidSelection() { return (visible) && (xCtrlPts[4]!=xCtrlPts[5]) && (yCtrlPts[0]!=yCtrlPts[3]); } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/ColorConverter.java0000644012010301201030000002315510502412004027040 0ustar mascellanimascellanipackage org.freehep.swing; import java.awt.Color; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.StringTokenizer; import javax.swing.JColorChooser; /** A utility class for converting strings to color's. * @author Tony Johnson * @author M.Donszelmann * @version $Id: ColorConverter.java 8981 2006-09-15 02:46:28Z serbo $ */ public class ColorConverter { private static ColorConverter defaultInstance = new ColorConverter(true); private Map colorToString; private Map stringToColor; /** Creates an instance of ColorConverter with the default color conversions */ public ColorConverter() { this(false); } private ColorConverter(boolean init) { if (init) { colorToString = new HashMap(); stringToColor = new HashMap(); init(); } else { colorToString = new HashMap(defaultInstance.colorToString); stringToColor = new HashMap(defaultInstance.stringToColor); } } private void init() { //first we look for the special named Java colors addEntry(Color.black, "Black"); addEntry(Color.blue, "Blue"); addEntry(Color.cyan, "Cyan"); addEntry(Color.darkGray, "Dark Gray"); addEntry(Color.gray, "Gray"); addEntry(Color.green, "Green"); addEntry(Color.lightGray, "Light Gray"); addEntry(Color.magenta, "Magenta"); addEntry(Color.orange, "Orange"); addEntry(Color.pink, "Pink"); addEntry(Color.red, "Red"); addEntry(Color.white, "White"); addEntry(Color.yellow, "Yellow"); //now we look for the HTML3.2 colors (we look for all of them since //we don't want to depend on the RGB values of Java and HTML3.2 colors //being the same) addEntry(new Color(0, 0, 0), "Black"); addEntry(new Color(192, 192, 192), "Silver"); addEntry(new Color(128, 128, 128), "Gray"); addEntry(new Color(255, 255, 255), "White"); addEntry(new Color(128, 0, 0), "Maroon"); addEntry(new Color(255, 0, 0), "Red"); addEntry(new Color(128, 0, 128), "Purple"); addEntry(new Color(255, 0, 255), "Fuchsia"); addEntry(new Color(0, 128, 0), "Green"); addEntry(new Color(0, 255, 0), "Lime"); addEntry(new Color(128, 128, 0), "Olive"); addEntry(new Color(255, 255, 0), "Yellow"); addEntry(new Color(0, 0, 128), "Navy"); addEntry(new Color(0, 0, 255), "Blue"); addEntry(new Color(0, 128, 128), "Teal"); addEntry(new Color(0, 255, 255), "Aqua"); //now we look for the "all hail Crayola" colors :) //(we don't look for those which are also Java named colors) addEntry(new Color(0.1f, 0.1f, 0.1f), "Gray 10%"); addEntry(new Color(0.2f, 0.2f, 0.2f), "Gray 20%"); addEntry(new Color(0.3f, 0.3f, 0.3f), "Gray 30%"); addEntry(new Color(0.4f, 0.4f, 0.4f), "Gray 40%"); addEntry(new Color(0.5f, 0.5f, 0.5f), "Gray 50%"); addEntry(new Color(0.6f, 0.6f, 0.6f), "Gray 60%"); addEntry(new Color(0.7f, 0.7f, 0.7f), "Gray 70%"); addEntry(new Color(0.8f, 0.8f, 0.8f), "Gray 80%"); addEntry(new Color(0.9f, 0.9f, 0.9f), "Gray 90%"); addEntry(new Color(255, 136, 28), "Orange"); addEntry(new Color(120, 62, 27), "Brown"); addEntry(new Color(0, 125, 32), "Forest Green"); addEntry(new Color(11, 157, 150), "Turquoise"); addEntry(new Color(109, 0, 168), "Purple"); addEntry(new Color(168, 0, 126), "Magenta"); addEntry(new Color(164, 207, 255), "Sky Blue"); addEntry(new Color(225, 170, 255), "Violet"); addEntry(new Color(255, 170, 210), "Light Magenta"); } /** * Creates new JColorChooser with extra panel that allows to choose * Color by name */ public static JColorChooser getColorChooser() { JColorChooser chooser = new JColorChooser(); chooser.addChooserPanel(new ColorNameChooserPanel()); return chooser; } /** Convert a color to a string, using the default ColorConverter * @param color The color to convert * @return The resulting String */ public static String get(Color color) { return defaultInstance.colorToString(color); } /** Converts a string to a color, using the default ColorConverter * @param name The string to convert * @return The resulting color * @throws ColorConversionException Thrown if the given string cannot be converted to a color */ public static Color get(String name) throws ColorConversionException { return defaultInstance.stringToColor(name); } /** Returns array of all Color names that are added, each name is unique * @return Array of names for all colors, each name is unique */ public static String[] getNames() { return defaultInstance.colorNames(); } /** Returns array of all Color names that are added, each name is unique * @return Array of names for all colors, each name is unique */ public String[] colorNames() { ArrayList list = new ArrayList(colorToString.size()); Iterator it = colorToString.values().iterator(); while(it.hasNext()) { String name = (String) it.next(); if (!list.contains(name)) list.add(name); } Collections.sort(list); String[] names = new String[list.size()]; names = (String[]) list.toArray(names); return names; } /** Add an entry to the color converter map * @param c The color to add * @param name The name corresponding to the color */ public void addEntry(Color c, String name) { stringToColor.put(name.toLowerCase(), c); colorToString.put(c, name); } /** Clear all the mappings from the color converter */ public void clear() { stringToColor.clear(); colorToString.clear(); } /** Convert the given color to a string. * @param color The color to be converted * @return Teh resulting string */ public String colorToString(Color color) { String name = (String) colorToString.get(color); return (name != null) ? name : getRGBName(color); } /** this method returns a Color. Colors are supposedly immutable * and are returned from the same table. * The supported formats are: *
        *      by name:          "yellow"                      , where alpha is always 1.0
        *      by int r,g,b,a:   "128, 255, 64, 255"           , where alpha (a) is optional
        *      by float r,g,b,a: "0.5, 1.0, 0.25, 1.0"         , where alpha (a) is optional
        *      by single number: "64637" or "0x0FFF08"         , where alpha is always 1.0
        * 
    * @param name name/number of the color * @return requested Color or defaulting to white in case of a invalid name (message is printed). * @throws ColorConversionException Thrown if the given string cannot be converted to a color */ public Color stringToColor(String name) throws ColorConversionException { name = name.toLowerCase(); // first look up if its name exists in the table Color c = (Color) stringToColor.get(name); if (c == null) { try { // check if the format is r,g,b,a if (name.indexOf(',') > 0) { StringTokenizer st = new StringTokenizer(name, ","); int[] i = new int[4]; float[] f = new float[4]; String red = st.nextToken().trim(); String green = st.nextToken().trim(); String blue = st.nextToken().trim(); String alpha = st.hasMoreTokens() ? st.nextToken().trim() : null; try { i[0] = Integer.parseInt(red); i[1] = Integer.parseInt(green); i[2] = Integer.parseInt(blue); i[3] = (alpha != null) ? Integer.parseInt(alpha) : 255; c = createColor(i[0], i[1], i[2], i[3]); } catch (NumberFormatException nfe1) { f[0] = Float.parseFloat(red); f[1] = Float.parseFloat(green); f[2] = Float.parseFloat(blue); f[3] = (alpha != null) ? Float.parseFloat(alpha) : 1.0f; c = createColor(f[0], f[1], f[2], f[3]); } } else { // the format should be rgb in a single number c = Color.decode(name); } } catch (Throwable t) { throw new ColorConversionException(name, t); } } return c; } /** * Return a color for the given values. * Subclasses may override this to tweak colors. */ protected Color createColor(int red, int green, int blue, int alpha) { return new Color(red, green, blue, alpha); } /** * Return a color for the given values. * Subclasses may override this to tweak colors. */ protected Color createColor(float red, float green, float blue, float alpha) { return new Color(red, green, blue, alpha); } private static String getRGBName(Color color) { return color.getRed() + ", " + color.getGreen() + ", " + color.getBlue() + ", " + color.getAlpha(); } /** An exception thrown if a given string cannot be converted to a Color */ public static class ColorConversionException extends Exception { ColorConversionException(String value, Throwable cause) { super("Cannot convert " + value + " to Color"); initCause(cause); } } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/table/0000755012010301201030000000000011275634131024327 5ustar mascellanimascellanifreehep-swing-2.0.3/src/main/java/org/freehep/swing/table/SortableTableModel.java0000644012010301201030000000241510630324340030670 0ustar mascellanimascellanipackage org.freehep.swing.table; import javax.swing.table.TableModel; /** * An interface to be implemented by table models which are sortable. * @see org.freehep.swing.table.TableSorter * @author Tony Johnson * @version $Id: SortableTableModel.java 10766 2007-06-02 17:29:04Z tonyj $ */ public interface SortableTableModel extends TableModel { public final static int UNSORTED = -1; /** * Sort the table model using the given column. Once this method * has been called the table model should reorder its rows so that * they are sorted using the given column. The table model should * generate appropriate change events to reflect any changes made * to the model as a result of the sort. If the table data is modified * after sort has been called, the table model should continue to sort * the data using the given column. * @param column The index of the column to sort on, or UNSORTED if no sort is necessary. * @param ascending If true sort in ascending order, else sort in descending order. */ void sort(int column, boolean ascending); public boolean isSortAscending(); /** * Returns the sort column, or UNSORTED if no sort currently in effect. */ public int getSortOnColumn(); }freehep-swing-2.0.3/src/main/java/org/freehep/swing/table/TableColumnHeaderListener.java0000644012010301201030000000353010466735775032240 0ustar mascellanimascellani// Copyright 2004, FreeHEP. package org.freehep.swing.table; import java.awt.Rectangle; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JTable; import javax.swing.table.JTableHeader; import javax.swing.table.TableColumnModel; /** * Abstract class listens for clicks on a table column header. * * @author Mark Donszelmann * @version $Id: TableColumnHeaderListener.java 8584 2006-08-10 23:06:37Z duns $ */ public abstract class TableColumnHeaderListener extends MouseAdapter { public void mouseClicked(MouseEvent evt) { JTable table = ((JTableHeader)evt.getSource()).getTable(); TableColumnModel colModel = table.getColumnModel(); // The index of the column whose header was clicked int vColIndex = colModel.getColumnIndexAtX(evt.getX()); int mColIndex = table.convertColumnIndexToModel(vColIndex); // Return if not clicked on any column header if (vColIndex == -1) { return; } // Determine if mouse was clicked between column heads Rectangle headerRect = table.getTableHeader().getHeaderRect(vColIndex); if (vColIndex == 0) { headerRect.width -= 3; // Hard-coded constant } else { headerRect.grow(-3, 0); // Hard-coded constant } if (!headerRect.contains(evt.getX(), evt.getY())) { // Mouse was clicked between column heads // vColIndex is the column head closest to the click // vLeftColIndex is the column head to the left of the click int vLeftColIndex = vColIndex; if (evt.getX() < headerRect.x) { vLeftColIndex--; } } else { headerClicked(table, mColIndex); } } public abstract void headerClicked(JTable table, int col); } freehep-swing-2.0.3/src/main/java/org/freehep/swing/table/TableSorter.java0000644012010301201030000001363010630324340027413 0ustar mascellanimascellani// Copyright 2004, FreeHEP. package org.freehep.swing.table; import java.awt.Component; import java.awt.Graphics; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.Icon; import javax.swing.JLabel; import javax.swing.JTable; import javax.swing.table.JTableHeader; import javax.swing.table.TableModel; import org.freehep.swing.table.TableColumnHeaderListener; import org.freehep.swing.table.TableHeaderCellRenderer; /** * Utility to add a sorter for columns to a JTable which has a SortableTableModel. *

    * Example of use: *

     *  TableModel model = ...
     *  DefaultSortableTableModel sm = new DefaultSortableTableModel(model);
     *  JTable table = new JTable(sm);
     *  TableSorter sorter = new TableSorter(table);
     * 
    * @author Mark Donszelmann * @author Tony Johnson * @version $Id: TableSorter.java 10766 2007-06-02 17:29:04Z tonyj $ * @see org.freehep.swing.table.SortableTableModel */ public class TableSorter { private static Icon downTriangle = new Triangle(false); private static Icon upTriangle = new Triangle(true); private SortableTableModel model; private JTableHeader header; /** * Create a TableSorter. The table will initially be unsorted. * @param table The table to be sorted */ public TableSorter(JTable table) { table.addPropertyChangeListener("model",new ModelChangeListener()); modelChanged(table.getModel()); header = table.getTableHeader(); header.addMouseListener(new HeaderListener()); header.setDefaultRenderer(new HeaderRenderer()); } /** * Create a TableSorter. The table will initially be sorted in ascending order by the given column. * @param table The table to be sorted. * @param column The column on which to sort, or SortableTableModel.UNSORTED */ public TableSorter(JTable table, int column) { this(table, column, true); } /** * Create a TableSorter specifiying initial sorting parameters. * @param table The table to be sorted. * @param column The column on which to sort, or SortableTableModel.UNSORTED * @param ascending true for ascending order, false for descending order */ public TableSorter(JTable table, int column, boolean ascending) { this(table); sort(column,ascending); } /** * Find the current sort column. * @return The current sort column, or SortableTableModel.UNSORTED */ public int getSortOnColumn() { return model == null ? SortableTableModel.UNSORTED : model.getSortOnColumn(); } /** * Set the sort column. * @param column The column on which to sort, or SortableTableModel.UNSORTED */ public void setSortOnColumn(int column) { if (model != null) model.sort(column,true); } /** * Get the current sort order. * @return true if ascending order, false for descending order. */ public boolean isSortAscending() { return model == null ? true : model.isSortAscending(); } /** * Set the current sort order. * @param ascending true for ascending order, false for descending order */ public void setSortAscending(boolean ascending) { if (model != null) model.sort(model.getSortOnColumn(),ascending); } private void sort(int sortOnColumn, boolean sortAscending) { if (model != null) { model.sort(sortOnColumn, sortAscending); header.resizeAndRepaint(); } } private void modelChanged(TableModel model) { this.model = model instanceof SortableTableModel ? (SortableTableModel) model : null; } private class ModelChangeListener implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent evt) { modelChanged((TableModel) evt.getNewValue()); } } private class HeaderListener extends TableColumnHeaderListener { public void headerClicked(JTable table, int col) { if (model != null) { if (col != model.getSortOnColumn()) { sort(col, true); } else { sort(model.getSortOnColumn(), !model.isSortAscending()); } } } } private class HeaderRenderer extends TableHeaderCellRenderer { public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) { JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col); if (model != null && table.convertColumnIndexToModel(col) == model.getSortOnColumn()) { label.setIcon(model.isSortAscending() ? downTriangle : upTriangle); } else { label.setIcon(null); } return label; } } private static class Triangle implements Icon { private boolean up; private static final int size = 16; private static final int[] xxdown = { 3 , 12, 7 }; private static final int[] yydown = { 5 , 5, 10 }; private static final int[] xxup = { 2 , 12, 7 }; private static final int[] yyup = { 10 , 10, 4 }; Triangle(boolean up) { this.up = up; } public int getIconHeight() { return size; } public int getIconWidth() { return size; } public void paintIcon(Component c, Graphics g, int x, int y) { int[] xp = new int[3]; int[] yp = new int[3]; for (int i=0; i<3; i++) { xp[i] = x + (up ? xxup[i] : xxdown[i]); yp[i] = y + (up ? yyup[i] : yydown[i]); } g.setColor(c.getForeground()); g.fillPolygon(xp,yp,3); } } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/table/TableColumnSelector.java0000644012010301201030000001553310466735775031130 0ustar mascellanimascellani// Copyright 2004, FreeHEP. package org.freehep.swing.table; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.BitSet; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import javax.swing.JPopupMenu; import javax.swing.event.EventListenerList; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.TableModel; /** * Allows the user to select which columns are visible in a table. *

    * Example of usage: *

     *    TableModel model = ...
     *    TableColumnSelector selector = new TableColumnSelector(model);
     *    JTable table = new JTable(selector.getFilteredTableModel());
     *    table.addMouseListener(new PopupListener(selector.createPopupMenu()));
     * 
    * @author Tony Johnson */ public class TableColumnSelector { private BitSet hidden = new BitSet(); private TableModel source; private TableModel result; private EventListenerList listeners = new EventListenerList(); private TableModelListener internalListener = new InternalTableModelListener(); /** * Create a TableColumnSelector. * @param model The source table model. */ public TableColumnSelector(TableModel model) { this.source = model; this.result = new InternalTableModel(); } private int mapFromFilter(int columnIndex) { int result = columnIndex; if (!hidden.isEmpty()) { for (int i=0; columnIndex >= 0 ;i++ ) { if (!hidden.get(i)) columnIndex--; else result++; } } return result; } private int mapToFilter(int columnIndex) { int result = columnIndex; if (!hidden.isEmpty()) { for (int i=0; itrue hides this column */ public void setHideColumn(int columnIndex, boolean hide) { if (hide != hidden.get(columnIndex)) { hidden.set(columnIndex,hide); if (listeners.getListenerCount() != 0) { int type = hide ? TableModelEvent.DELETE : TableModelEvent.INSERT; int column = mapToFilter(columnIndex); TableModelEvent event = new TableModelEvent(result,TableModelEvent.HEADER_ROW,TableModelEvent.HEADER_ROW,column,type); fireTableChanged(event); } } } /** * Notifies all listeners of a change to the filtered TableModel. * @param event The event to be sent to the listeners. */ protected void fireTableChanged(TableModelEvent event) { TableModelListener[] l = (TableModelListener[]) listeners.getListeners(TableModelListener.class); for (int i=0; itrue if this column is hidden */ public boolean isHideColumn(int columnIndex) { return hidden.get(columnIndex); } /** * Get the resulting table model. This is the table model that should actually be installed. * @return The filtered table mode. */ public TableModel getFilteredTableModel() { return result; } private class InternalTableModel implements TableModel { public void addTableModelListener(TableModelListener l) { if (listeners.getListenerCount() == 0) source.addTableModelListener(internalListener); listeners.add(TableModelListener.class, l); } public Class getColumnClass(int columnIndex) { return source.getColumnClass(mapFromFilter(columnIndex)); } public int getColumnCount() { return source.getColumnCount() - hidden.cardinality(); } public String getColumnName(int columnIndex) { return source.getColumnName(mapFromFilter(columnIndex)); } public int getRowCount() { return source.getRowCount(); } public Object getValueAt(int rowIndex, int columnIndex) { return source.getValueAt(rowIndex,mapFromFilter(columnIndex)); } public boolean isCellEditable(int rowIndex, int columnIndex) { return source.isCellEditable(rowIndex,mapFromFilter(columnIndex)); } public void removeTableModelListener(TableModelListener l) { listeners.remove(TableModelListener.class, l); if (listeners.getListenerCount() == 0) source.removeTableModelListener(internalListener); } public void setValueAt(Object aValue, int rowIndex, int columnIndex) { source.setValueAt(aValue, rowIndex, mapFromFilter(columnIndex)); } } private class InternalTableModelListener implements TableModelListener { public void tableChanged(TableModelEvent e) { int column = e.getColumn(); if (column == TableModelEvent.ALL_COLUMNS || !hidden.get(column)) { int first = e.getFirstRow(); int last = e.getLastRow(); int type = e.getType(); if (column != TableModelEvent.ALL_COLUMNS) column = mapToFilter(column); TableModelEvent ee = new TableModelEvent(result,first,last,column,type); fireTableChanged(ee); } } } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/table/DefaultSortableTableModel.java0000644012010301201030000003527110632701433032207 0ustar mascellanimascellanipackage org.freehep.swing.table; import java.util.Comparator; import javax.swing.event.EventListenerList; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.TableModel; /** * Converts any TableModel to a SortableTableModel. * @author Tony Johnson * @version $Id: DefaultSortableTableModel.java 12627 2007-06-10 04:50:35Z tonyj $ */ public class DefaultSortableTableModel implements SortableTableModel { private Comparator comparator = new DefaultComparator(); private TableModel source; private EventListenerList listeners = new EventListenerList(); private TableModelListener internalListener = new InternalTableModelListener(); private int sortColumn = UNSORTED; private boolean ascending = true; private int[] rowMap; private int[] reverseMap; boolean reverseMapValid = false; private int nRows; /** * Creates a new instance of DefaultTableSorter * @param source The table model to be converted. */ public DefaultSortableTableModel(TableModel source) { this.source = source; } private int mapFromSorted(int rowIndex) { return rowMap == null ? rowIndex : rowMap[rowIndex]; } private int mapToSorted(int rowIndex) { if (rowMap != null && !reverseMapValid) { if (reverseMap == null || reverseMap.length < nRows) { reverseMap = new int[rowMap.length]; } for (int i=0; i= row) rowMap[i]++; } rowMap[nRows] = row; // Do a binary search to find out where the new row should go int insertPoint = binarySearch(nRows,0,nRows); if (insertPoint != nRows) { System.arraycopy(rowMap,insertPoint, rowMap, insertPoint+1,nRows-insertPoint); rowMap[insertPoint] = row; } nRows++; reverseMapValid = false; return insertPoint; } private int binarySearch(int newRow, int start, int end) { if (start-end < 5) { for (int i=start; i> 1; int result = compare(newRow,mid); if (result == 0) return mid; else if (result > 0) return binarySearch(newRow,mid,end); else return binarySearch(newRow,start,mid); } private int rowWasDeleted(int row) { int sortedRow = mapToSorted(row); System.arraycopy(rowMap,sortedRow+1,rowMap,sortedRow,nRows-sortedRow-1); nRows--; for (int i=0; i row) rowMap[i]--; } reverseMapValid = false; return sortedRow; } private Object get(int index) { return source.getValueAt(rowMap[index], sortColumn); } private int compare(int i, int j) { return comparator.compare(get(i),get(j)) * (ascending ? 1 : -1); } private int compare(Object o, int j) { return comparator.compare(o,get(j)) * (ascending ? 1 : -1); } private void swap(int i, int j) { int tmp = rowMap[i]; rowMap[i] = rowMap[j]; rowMap[j] = tmp; } private int med3(int a, int b, int c) { return compare(a,b)<0 ? compare(b,c)<0 ? b : compare(a,c)<0 ? c : a : compare(b,c)>0 ? b : compare(a,c)>0 ? c : a; } private void vecswap(int a, int b, int n) { for (int i=0; ioff && compare(j-1,j)>0; j--) swap(j, j-1); return; } // Choose a partition element, v int m = off + (len >> 1); // Small arrays, middle element if (len > 7) { int l = off; int n = off + len - 1; if (len > 40) // Big arrays, pseudomedian of 9 { int s = len/8; l = med3(l, l+s, l+2*s); m = med3(m-s, m, m+s); n = med3(n-2*s, n-s, n); } m = med3(l, m, n); // Mid-size, med of 3 } Object v = get(m); // Establish Invariant: v* (v)* v* int a = off, b = a, c = off + len - 1, d = c; int comp; while(true) { while (b <= c && (comp = compare(v,b)) >= 0) { if (comp == 0) swap(a++, b); b++; } while (c >= b && (comp = compare(v,c)) <= 0) { if (comp == 0) swap(c, d--); c--; } if (b > c) break; swap(b++, c--); } // Swap partition elements back to middle int s, n = off + len; s = Math.min(a-off, b-a ); vecswap(off, b-s, s); s = Math.min(d-c, n-d-1); vecswap(b, n-s, s); // Recursively sort non-partition-elements if ((s = b-a) > 1) sort1(off, s); if ((s = d-c) > 1) sort1(n-s, s); } /** * Notifies all listeners of a change to the sorted TableModel. * @param event The event to be sent to the listeners. */ protected void fireTableChanged(TableModelEvent event) { TableModelListener[] l = (TableModelListener[]) listeners.getListeners(TableModelListener.class); for (int i=0; i 0) && (totalPreferredWidth > table.getWidth())) { setWidth(columns, table.getWidth()); } } } // Tries to distribute the widths in the given columns. Each column // gets its preferredWidth if that would fit. The remaining space is // again distributed over the remaining columns, using this method // recursively. If no columns have preferredWidths below the // calculated column width, the remaining width is just divided // over the remaining columns and the recursion ends. private void setWidth(List/**/ columns, int width) { List remainingColumns = new ArrayList(); int colSize = width / columns.size(); for (Iterator i=columns.iterator(); i.hasNext(); ) { TableColumn col = (TableColumn)i.next(); int prefWidth = col.getPreferredWidth(); if (prefWidth < colSize) { // pref width is ok width -= prefWidth; } else { // pref widh too large in this iteration remainingColumns.add(col); } } if (remainingColumns.size() <= 0) return; if (remainingColumns.size() < columns.size()) { // fewer columns setWidth(remainingColumns, width); } else { // all columns wider than colSize for (Iterator i = remainingColumns.iterator(); i.hasNext(); ) { TableColumn col = (TableColumn)i.next(); col.setPreferredWidth(colSize); } } } // Sets the preferred width of the visible column specified by vColIndex. The column // will be just wide enough to show the column head and the widest cell in the column. // margin pixels are added to the left and right // (resulting in an additional width of 2*margin pixels). private int preferredWidth(JTable table, TableColumn col, int vColIndex) { int width = 0; // Get maximum width of column data // To save time we dont scan all rows, instead we scan the first and last MAXSCAN rows int rowCount = table.getRowCount(); int stop = maxscan > 0 ? Math.min(maxscan,rowCount) : 0; int start = maxscan > 0 ? Math.max(rowCount-maxscan,stop) : rowCount; for (int r=0; r Utilities for dealing with Swing tables. freehep-swing-2.0.3/src/main/java/org/freehep/swing/print/0000755012010301201030000000000011275634131024374 5ustar mascellanimascellanifreehep-swing-2.0.3/src/main/java/org/freehep/swing/print/table/0000755012010301201030000000000011275634131025463 5ustar mascellanimascellanifreehep-swing-2.0.3/src/main/java/org/freehep/swing/print/table/PrintableTableModel.java0000644012010301201030000000264010466735775032222 0ustar mascellanimascellanipackage org.freehep.swing.print.table; /** Used to provide table data for printing */ public interface PrintableTableModel { /** Get the cell printer to be used for the table body * @return The cell printer for this column * @param column The column index */ CellPrinter getCellPrinter(int column); /** Get the cell printer to be used for the table header * @return The cell printer to use for this column's header * @param column The column index */ CellPrinter getHeaderPrinter(int column); /** Get the title for the document * @return The title. */ String getTitle(); /** Get the header for a column * @return The header text for this column * @param i The column index. */ Object headerForColumn(int i); /** Allows some columns to be skipped when printing * @return true if this column should be skipped * @param i The column index */ boolean hideColumn(int i); /** Total number of columns (including hidden columns) * @return The number of columns */ int numberOfColumns(); /** Total number of rows * @return The number of rows */ int numberOfRows(); /** Get the data to be printed in a certain cell. * @return The object representing the data at the referenced cell * @param i The column index * @param j The row index */ Object valueAt(int i, int j); }freehep-swing-2.0.3/src/main/java/org/freehep/swing/print/table/CellPrinter.java0000644012010301201030000000203410466735775030571 0ustar mascellanimascellanipackage org.freehep.swing.print.table; import java.awt.Font; import java.awt.Graphics; import java.awt.font.FontRenderContext; import java.awt.geom.Rectangle2D.Float; /** An interface to be implemented by cell printers */ public interface CellPrinter { /** Sets the font to be used * @param fm The font to be used */ void setFont(Font fm); /** The height of one column * @return The hieght of each column of the table * @param frc The font render context to be used for calculating font sizes. */ float getHeight(FontRenderContext frc); /** Sets the value of the cell to print * @param o The object to be printed */ void setValue(Object o); /** Gets the width of the current current value. * @return The width needed to print the current value. * @param frc The font render context to be used. */ float getWidth(FontRenderContext frc); /** Print this cell * @param g The graphics into which to print * @param r */ void print(Graphics g, Float r); }freehep-swing-2.0.3/src/main/java/org/freehep/swing/print/table/PrintModelAdapter.java0000644012010301201030000000312710466735775031730 0ustar mascellanimascellanipackage org.freehep.swing.print.table; import javax.swing.table.TableModel; /** * Converts a TableModel to a PrintableTableModel * @author tonyj * @version $Id: PrintModelAdapter.java 8584 2006-08-10 23:06:37Z duns $ */ public class PrintModelAdapter implements PrintableTableModel { private TableModel model; private String title; private CellPrinter headerPrinter = new DefaultCellPrinter(DefaultCellPrinter.ALIGN_CENTER); private CellPrinter textPrinter = new DefaultCellPrinter(DefaultCellPrinter.ALIGN_LEFT); private CellPrinter numberPrinter = new NumberCellPrinter(); /** Creates a new instance of PrintModelAdapter * @param model The table model to convert * @param title The title for the generater PrintableTableModel */ public PrintModelAdapter(TableModel model, String title) { this.model = model; this.title = title; } public CellPrinter getCellPrinter(int column) { return Number.class.isAssignableFrom(model.getColumnClass(column)) ? numberPrinter : textPrinter; } public CellPrinter getHeaderPrinter(int column) { return headerPrinter; } public String getTitle() { return title; } public Object headerForColumn(int i) { return model.getColumnName(i); } public boolean hideColumn(int i) { return false; } public int numberOfColumns() { return model.getColumnCount(); } public int numberOfRows() { return model.getRowCount(); } public Object valueAt(int i, int j) { return model.getValueAt(i,j); } } freehep-swing-2.0.3/src/main/java/org/freehep/swing/print/table/package.html0000644012010301201030000000005410470537377027755 0ustar mascellanimascellani Utilities for printing tables freehep-swing-2.0.3/src/main/java/org/freehep/swing/print/table/DefaultCellPrinter.java0000644012010301201030000000343610466735775032105 0ustar mascellanimascellanipackage org.freehep.swing.print.table; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.font.FontRenderContext; import java.awt.geom.Rectangle2D.Float; /** A default implementation of CellPrinter */ public class DefaultCellPrinter implements CellPrinter { public static final int ALIGN_LEFT = 0; public static final int ALIGN_CENTER = 1; public static final int ALIGN_RIGHT = 2; protected String value; private Float rect; private Font font; private int align; DefaultCellPrinter(int align) { this.align = align; } public void setFont(Font font) { this.font = font; } public float getHeight(FontRenderContext frc) { if (rect == null) { rect = (Float) font.getStringBounds(value, frc); } return rect.height; } public void setValue(Object o) { value = format(o); rect = null; } public float getWidth(FontRenderContext frc) { if (rect == null) { rect = (Float) font.getStringBounds(value, frc); } return rect.width; } public void print(Graphics g, Float r) { if (value == null) { return; } Graphics2D g2 = (Graphics2D) g; FontRenderContext frc = g2.getFontRenderContext(); if (rect == null) { rect = (Float) font.getStringBounds(value, frc); } float y = r.y - rect.y; float x = r.x; if (align == ALIGN_RIGHT) { x += (r.width - getWidth(frc)); } else if (align == ALIGN_CENTER) { x += ((r.width - getWidth(frc)) / 2); } g2.setFont(font); g2.drawString(value, x, y); } protected String format(Object o) { return (o == null) ? "" : o.toString(); } }freehep-swing-2.0.3/src/main/java/org/freehep/swing/print/table/TablePrinter.java0000644012010301201030000001434410466735775030750 0ustar mascellanimascellanipackage org.freehep.swing.print.table; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.font.FontRenderContext; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D.Float; import java.awt.print.PageFormat; import java.awt.print.Pageable; import java.awt.print.Printable; import javax.swing.table.TableModel; /** Utility for printing tables. */ public class TablePrinter implements Pageable, Printable { private Font cellFont; private Font headerFont; private FontRenderContext lastFontRenderContext; private PageFormat pf; private PrintableTableModel model; private float[] widths; private float headerHeight; private float rowHeight; private int nPages = UNKNOWN_NUMBER_OF_PAGES; private int rowsPerPage; /** Create a TablePrinter from a PrintableTableModel * @param model The table model to print * @param pf The page format to use for printing * @param headerFont The font to be used for the table header * @param cellFont The font to be used for the cells in the body of the table. * @param frc The font render context for the printing device */ public TablePrinter(PrintableTableModel model, PageFormat pf, Font headerFont, Font cellFont, FontRenderContext frc) { this.pf = pf; this.model = model; this.headerFont = headerFont; this.cellFont = cellFont; calculateTableSize(pf, frc); } /** Create a TablePrinter from a TableModel * @param model The table model to print * @param title The title to use for the print job * @param pf The page format to use for printing * @param headerFont The font to be used for the table header * @param cellFont The font to be used for the cells in the body of the table. * @param frc The font render context for the printing device */ public TablePrinter(TableModel model, String title, PageFormat pf, Font headerFont, Font cellFont, FontRenderContext frc) { this(new PrintModelAdapter(model, title),pf,headerFont,cellFont,frc); } public int getNumberOfPages() { return nPages; } public PageFormat getPageFormat(int p1) { return pf; } public Printable getPrintable(int p1) { return this; } public int print(Graphics g, PageFormat pf, int page) { Graphics2D g2 = (Graphics2D) g; FontRenderContext frc = g2.getFontRenderContext(); if (!frc.equals(lastFontRenderContext)) { calculateTableSize(pf, frc); } if (page >= nPages) { return NO_SUCH_PAGE; } g2.setColor(Color.black); g2.setStroke(new BasicStroke(0)); float xx = (float) pf.getImageableX(); float yy = (float) pf.getImageableY(); float totalWidth = 4; for (int i = 0; i < widths.length; i++) { if (widths[i] > 0) { totalWidth += (widths[i] + 3); } } float y = 4 + xx; float x = 4 + yy; Float rect = new Float(); for (int c = 0; c < model.numberOfColumns(); c++) { if (widths[c] == 0) { continue; } rect.setRect(x, y, widths[c], headerHeight); CellPrinter cp = model.getHeaderPrinter(c); cp.setFont(headerFont); cp.setValue(model.headerForColumn(c)); cp.print(g, rect); x += (widths[c] + 3); } y += (headerHeight + 1); Line2D line = new java.awt.geom.Line2D.Float(); for (int r = page * rowsPerPage; r < ((page + 1) * rowsPerPage); r++) { if (r >= model.numberOfRows()) { break; } x = 4 + xx; for (int c = 0; c < model.numberOfColumns(); c++) { if (widths[c] == 0) { continue; } rect.setRect(x, y, widths[c], rowHeight); CellPrinter cp = model.getCellPrinter(c); cp.setFont(cellFont); cp.setValue(model.valueAt(r, c)); cp.print(g, rect); x += (widths[c] + 3); } line.setLine(xx, y - 1, xx + totalWidth, y - 1); g2.draw(line); y += (rowHeight + 1); } x = xx + 2; for (int c = 0; c < (model.numberOfColumns() - 1); c++) { if (widths[c] == 0) { continue; } x += (widths[c] + 3); line.setLine(x, yy + 1, x, y); g2.draw(line); } g2.setStroke(new BasicStroke(2)); rect.setRect(xx + 1, yy + 2, totalWidth, y - yy); g2.draw(rect); String footer = "Page " + (page + 1) + " of " + nPages; // +" header="+headerFont+" cell="+cellFont; g2.drawString(footer, xx, (yy + (float) pf.getImageableHeight()) - g.getFontMetrics().getDescent()); return PAGE_EXISTS; } private void calculateTableSize(PageFormat pf, FontRenderContext frc) { lastFontRenderContext = frc; double height = pf.getImageableHeight(); widths = new float[model.numberOfColumns()]; headerHeight = 0; rowHeight = 0; for (int c = 0; c < model.numberOfColumns(); c++) { if (model.hideColumn(c)) { continue; } CellPrinter hp = model.getHeaderPrinter(c); hp.setFont(headerFont); hp.setValue(model.headerForColumn(c)); widths[c] = hp.getWidth(frc); float h = hp.getHeight(frc); if (h > headerHeight) { headerHeight = h; } CellPrinter cp = model.getCellPrinter(c); cp.setFont(cellFont); for (int r = 0; r < model.numberOfRows(); r++) { cp.setValue(model.valueAt(r, c)); float w = cp.getWidth(frc); if (w > widths[c]) { widths[c] = w; } h = cp.getHeight(frc); if (h > rowHeight) { rowHeight = h; } } } int nRows = model.numberOfRows(); double effectiveHeight = height - headerHeight - 6 - rowHeight; // leave room for header rowsPerPage = (int) Math.floor(effectiveHeight / (rowHeight + 1)); nPages = 1 + ((nRows - 1) / rowsPerPage); } }freehep-swing-2.0.3/src/main/java/org/freehep/swing/print/table/NumberCellPrinter.java0000644012010301201030000000104010466735775031736 0ustar mascellanimascellanipackage org.freehep.swing.print.table; import java.text.Format; import java.text.NumberFormat; /** A cell printer used for printing cells containing numeric values. */ public class NumberCellPrinter extends DefaultCellPrinter { private static Format format = NumberFormat.getInstance(); NumberCellPrinter() { super(ALIGN_RIGHT); } /** Prints the given object * @param o The object to print * @return The string to print. */ protected String format(Object o) { return format.format(o); } }freehep-swing-2.0.3/src/main/java/org/freehep/swing/todo.txt0000644012010301201030000000015410470537377024760 0ustar mascellanimascellaniTriState - tristates with icons seem to show no tickmark (problem in JDK?) - tristates do all use Metal L&F freehep-swing-2.0.3/src/main/java/org/freehep/swing/TriState.java0000644012010301201030000000051610466735775025665 0ustar mascellanimascellani// Copyright 2000, CERN, Geneva, Switzerland. package org.freehep.swing; /** * @author Mark Donszelmann * @version $Id: TriState.java 8584 2006-08-10 23:06:37Z duns $ */ public interface TriState { public int getTriState(); public void setTriState(int state); public void setTriState(boolean state); } freehep-swing-2.0.3/src/main/java/org/freehep/swing/RecentFileList.java0000644012010301201030000001124510466735775027003 0ustar mascellanimascellanipackage org.freehep.swing; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.Properties; import java.util.Vector; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.event.EventListenerList; /** * A class for maintaining a "Recent File List". * The recent file list can be stored between program invocations in * a properties file. One or more RecentFileLists can easily * be embedded in a JMenu. * * @author Tony Johnson (tonyj@slac.stanford.edu) * @version $Id: RecentFileList.java 8584 2006-08-10 23:06:37Z duns $ */ public class RecentFileList implements ActionListener { /** * Create a RecentFileList */ public RecentFileList() { this(null); } /** * Create a RecentFileList with a given maximum length * @param size the maximum number of files to remember */ public RecentFileList(int size) { this(null,size); } /** * Create a recent file list. The type parameter is used to * prefix entries in the properties file, so that multiple * RecentFileLists can be used in an application. * @param type The prefix to use */ public RecentFileList(String type) { this(type,4); } /** * Create a recent file list with a given type and size * @param type The prefix to use * @param size the maximum number of files to remember */ public RecentFileList(String type, int size) { files = new Vector(size); this.size = size; this.type = type; used = 0; } public void addActionListener(ActionListener l) { listenerList.add(ActionListener.class, l); } public void removeActionListener(ActionListener l) { listenerList.remove(ActionListener.class, l); } /** * An action event is fired when the user selects one of the * files from a menu. The "actionCommand" in the event will be * set to the name of the selected file. */ protected void fireActionPerformed(ActionEvent e) { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==ActionListener.class) { ((ActionListener)listeners[i+1]).actionPerformed(e); } } } public void actionPerformed(ActionEvent e) { fireActionPerformed(e); } /** * Save the recent file list in a Properties set * @param props The Properties set to save the files in */ public void save(Properties props) { String key = "RecentFile_" + (type!=null ? type+"_" : "" ); for (int i=0; i 0) { files.removeElementAt(pos); files.insertElementAt(name,0); } else if (pos != 0) { if (used == size) files.removeElementAt(size-1); else used++; files.insertElementAt(name,0); } } /** * Remove a file from the list * @param name The name of the file to remove */ public void remove(String name) { if (files.removeElement(name)) used--; } /** * Adds the recent file list to a menu. * The files will be added at the end of the menu, with a * separator before the files (if there are >0 files in the list) */ public void buildMenu(JMenu menu) { if (used > 0) { menu.addSeparator(); for (int i=0; i