alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.openide.nodes;

import org.openide.util.WeakListeners;
import java.awt.*;
import java.awt.dnd.*;
import java.awt.datatransfer.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeListener;
import java.io.IOException;

import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;

import org.openide.ErrorManager;
import org.openide.util.NbBundle;
import org.openide.util.datatransfer.ExTransferable;

/** A dialog for reordering nodes. This dialog can reorder
* nodes for all implementors of the {@link Index} cookie.
* The dialog can invoke reorder actions on a given Index
* implementation immediatelly, or these actions can be accumulated
* and invoked at once, when the dialog is closed.
*
* 

This class is final only for performance reasons. * * @author Jan Jancura, Ian Formanek, Dafe Simonek * @deprecated Better to use Index.Support.showIndexedCustomizer which behaves better * with the window system. */ public final class IndexedCustomizer extends JDialog implements java.beans.Customizer { // variables ..................................................................................... /** The actual JList control */ private JList control; /** Buttons */ private JButton buttonUp, buttonDown, buttonClose; /** index to sort */ private Index index; private Node[] nodes; /** Whether or not change the order immediatelly */ private boolean immediateReorder = true; /** Permutation array, which stores moves in case when * immediateReorder property is false */ private int[] permutation; /** Listener to the changes in the nodes */ private ChangeListener nodeChangesL; // initializations ................................................................................ static final long serialVersionUID =-8731362267771694641L; /** Construct a new customizer. */ public IndexedCustomizer () { this(null, true); } /** Construct a dummy customizer. * Might not actually be used as a JDialog, however its GUI * layout and logic will be used. * Cf. #9323. * @param c a container on which to draw the GUI * @param closeButton if true, add a Close button and other dialog logic, else no */ IndexedCustomizer(Container p, boolean closeButton) { super (TMUtil.mainWindow (), true); GridBagConstraints constraints; if (closeButton) { setDefaultCloseOperation (javax.swing.JDialog.DISPOSE_ON_CLOSE); // attach cancel also to Escape key getRootPane().registerKeyboardAction( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { setVisible (false); dispose (); } }, javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_ESCAPE, 0, true), javax.swing.JComponent.WHEN_IN_FOCUSED_WINDOW ); setTitle(Node.getString("LAB_order")); } // closeButton if (p == null) p = getContentPane (); p.setLayout (new GridBagLayout()); JLabel l = new JLabel (Node.getString("LAB_listOrder")); l.setDisplayedMnemonic(Node.getString("LAB_listOrder_Mnemonic").charAt(0)); constraints = new GridBagConstraints(); constraints.gridx = 0; constraints.gridy = 0; constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(12, 12, 2, 12); p.add(l, constraints); control = new AutoscrollJList(); l.setLabelFor(control); control.addListSelectionListener (new ListSelectionListener () { public void valueChanged(ListSelectionEvent e) { if (control.isSelectionEmpty ()) { buttonUp.setEnabled (false); buttonDown.setEnabled (false); } else { int i = control.getSelectedIndex (); if (i > 0) //PENDING - jeste testovat, jestli jsou OrderedCookie.Child buttonUp.setEnabled (true); else buttonUp.setEnabled (false); if (i < (nodes.length - 1)) buttonDown.setEnabled (true); else buttonDown.setEnabled (false); } } } ); control.setCellRenderer (new IndexedListCellRenderer ()); control.setVisibleRowCount (15); control.setSelectionMode (javax.swing.ListSelectionModel.SINGLE_SELECTION); // list has to be scrolling constraints = new GridBagConstraints(); constraints.gridx = 0; constraints.gridy = 1; constraints.fill = GridBagConstraints.BOTH; constraints.weightx = 1.0; constraints.weighty = 1.0; constraints.insets = new Insets(0, 12, 11, 11); p.add(new JScrollPane(control), constraints); JPanel bb = new JPanel (); if (closeButton) { buttonClose = new JButton (Node.getString("Button_close")); buttonClose.setMnemonic(Node.getString("Button_close_Mnemonic").charAt(0)); } buttonUp = new JButton (Node.getString("Button_up")); buttonUp.setMnemonic(Node.getString("Button_up_Mnemonic").charAt(0)); buttonDown = new JButton (Node.getString("Button_down")); buttonDown.setMnemonic(Node.getString("Button_down_Mnemonic").charAt(0)); bb.setLayout(new GridBagLayout()); constraints = new GridBagConstraints(); constraints.gridx = 0; constraints.gridy = 0; constraints.anchor = GridBagConstraints.NORTH; constraints.fill = GridBagConstraints.HORIZONTAL; constraints.insets = new Insets(0, 0, 5, 11); bb.add(buttonUp, constraints); constraints = new GridBagConstraints(); constraints.gridx = 0; constraints.gridy = 1; constraints.anchor = GridBagConstraints.NORTH; constraints.fill = GridBagConstraints.HORIZONTAL; constraints.weighty = 1.0; constraints.insets = new Insets(0, 0, 0, 11); bb.add(buttonDown, constraints); if (closeButton) { constraints = new GridBagConstraints(); constraints.gridx = 0; constraints.gridy = 2; constraints.anchor = GridBagConstraints.SOUTH; constraints.fill = GridBagConstraints.HORIZONTAL; constraints.insets = new Insets(0, 0, 11, 11); bb.add(buttonClose, constraints); } buttonUp.addActionListener (new ActionListener () { public void actionPerformed (ActionEvent e) { int i = control.getSelectedIndex (); moveUp (i); updateList (); control.setSelectedIndex (i - 1); control.ensureIndexIsVisible(i - 1); control.repaint (); } }); buttonDown.addActionListener (new ActionListener () { public void actionPerformed (ActionEvent e) { int i = control.getSelectedIndex (); moveDown (i); updateList (); control.setSelectedIndex (i + 1); control.ensureIndexIsVisible(i + 1); control.repaint (); } }); if (closeButton) { buttonClose.addActionListener (new ActionListener () { public void actionPerformed (ActionEvent e) { doClose(); dispose (); } }); } buttonUp.setEnabled (false); buttonDown.setEnabled (false); constraints = new GridBagConstraints(); constraints.gridx = 1; constraints.gridy = 1; constraints.fill = GridBagConstraints.VERTICAL; p.add(bb, constraints); // disable drag support, as DnD crashes all environment // under current implementation of VMs on unixes, ans causes // some deadlocks on windows... //dragSupport = new IndexedDragSource(control); //dropSupport = new IndexedDropTarget(this, dragSupport); if (closeButton) { pack(); setBounds(org.openide.util.Utilities.findCenterBounds(getSize())); buttonClose.requestFocus (); // to get shortcuts to work buttonClose.getAccessibleContext().setAccessibleDescription(Node.getString("ACSD_Button_close")); } buttonUp.getAccessibleContext().setAccessibleDescription(Node.getString("ACSD_Button_up")); buttonDown.getAccessibleContext().setAccessibleDescription(Node.getString("ACSD_Button_down")); control.getAccessibleContext().setAccessibleDescription(Node.getString("ACSD_ListOrder")); p.getAccessibleContext().setAccessibleDescription(Node.getString("ACSD_IndexedCustomizer")); getAccessibleContext().setAccessibleDescription(Node.getString("ACSD_IndexedCustomizer")); } /** Simulate behavior of the Close button, minus actual dialog disposal. * Might do the same as setImmediateReorder(true), but I am not sure. */ void doClose() { if ((!immediateReorder) && (index != null) && (permutation != null)) { int[] realPerm = new int[permutation.length]; for (int i = 0; i < realPerm.length; i++) { realPerm[permutation[i]] = i; //System.out.println (i + "-->" + permutation[i]); // NOI18N } index.reorder(realPerm); } } // other methods ................................................................................ /** Called when an explored context changes and the list needs to be * recreated. */ private void updateList () { if (index == null) return; Node[] localNodes = index.getNodes(); //System.out.println ("Nodes taken, size: " + localNodes.length); // NOI18N // obtain nodes with help from permutation array, if // conditions met if (!immediateReorder) { getPermutation(); int origLength = permutation.length; int newLength = localNodes.length; if (origLength < newLength) { // some nodes added, we must synchronize the permutation nodes = new Node[newLength]; int[] newPerm = new int[newLength]; System.arraycopy(newPerm, 0, permutation, 0, origLength); for (int i = 0; i < newLength; i++) { if (i < origLength) nodes[i] = localNodes[permutation[i]]; else { // added nodes.... nodes[i] = localNodes[i]; newPerm[i] = i; } } permutation = newPerm; } else if (origLength > newLength) { // some nodes removed, we must re-initialize the permutation nodes = new Node[newLength]; permutation = new int[newLength]; for (int i = 0; i < newLength; i++) { nodes[i] = localNodes[i]; permutation[i] = i; } } else { // node count is the same, only permute the nodes nodes = new Node[newLength]; for (int i = 0; i < newLength; i++) nodes[i] = localNodes[permutation[i]]; } } else { nodes = (Node[])localNodes.clone(); } control.setListData (nodes); if (nodes.length > 0 && control.getSelectedIndex () == -1) { control.setSelectedIndex (0); } } public Dimension getPreferredSize () { return new Dimension (300, super.getPreferredSize ().height); } /** Will reorders be reflected immediately? * @return true if so */ public boolean isImmediateReorder () { return immediateReorder; } /** Set whether reorders will take effect immediately. * @param immediateReorder true if so */ public void setImmediateReorder (boolean immediateReorder) { if (this.immediateReorder == immediateReorder) return; this.immediateReorder = immediateReorder; if (immediateReorder) { if (permutation != null) { index.reorder(permutation); permutation = null; updateList(); } } } // implementation of Customizer ............................................................ /** Set the nodes to reorder. * @param bean must implement {@link Index} * @throws IllegalArgumentException if not */ public void setObject (Object bean) { if (bean instanceof Index) { index = (Index)bean; // add weak listener to the Index nodeChangesL = new ChangeListener() { public void stateChanged (ChangeEvent ev) { SwingUtilities.invokeLater(new Runnable() { public void run () { updateList(); } }); } }; updateList (); control.invalidate(); validate(); index.addChangeListener(org.openide.util.WeakListeners.change (nodeChangesL, index)); } else { throw new IllegalArgumentException (); } } // I don't change any property... public void addPropertyChangeListener(PropertyChangeListener listener) { } public void removePropertyChangeListener(PropertyChangeListener listener) { } /** Moves up. Performs differently according to * immediateReorder property value. */ private void moveUp (final int position) { if (index == null) return; if (immediateReorder) { index.moveUp(position); } else { getPermutation(); int temp = permutation[position]; permutation[position] = permutation[position - 1]; permutation[position - 1] = temp; } } /** Moves down. Performs differently according to * immediateReorder property value. */ private void moveDown (final int position) { if (index == null) return; if (immediateReorder) { index.moveDown(position); } else { getPermutation(); int temp = permutation[position]; permutation[position] = permutation[position + 1]; permutation[position + 1] = temp; } } /** Safe getter for permutation. * Initializes permutation to identical permutation if it is null.
* index variable must not be null when this method called */ private int[] getPermutation () { if (permutation == null) { if (nodes == null) nodes = (Node[])index.getNodes().clone(); permutation = new int[nodes.length]; for (int i = 0; i < nodes.length; permutation[i] = i++); } return permutation; } /** Permute the list as given permutation dictates. * Sets selection to the given selected index. * Called from dropSupport as result of succesfull DnD operation. */ void performReorder (int[] perm, int selected) { if (immediateReorder) { index.reorder(perm); } else { // merge current and reversed given permutation // (reverse given permutation first) int[] reversed = new int[perm.length]; for (int i = 0; i < reversed.length; i++) reversed[perm[i]] = i; int[] orig = getPermutation(); permutation = new int[orig.length]; for (int i = 0; i < orig.length; i++) { permutation[i] = orig[reversed[i]]; // System.out.println(permutation[i] + " ----> " + i); // NOI18N } } updateList(); control.setSelectedIndex(selected); control.repaint(); } /** Implementation of drag functionality in * reorder dialog. */ private static final class IndexedDragSource implements DragGestureListener, DragSourceListener { /** Asociated JList component where the drag will * take place */ JList comp; /** User gesture that initiated the drag */ DragGestureEvent dge; /** Out data flavor used to transfer the index */ DataFlavor myFlavor; /** Creates drag source with asociated list where drag * will take place. * Also creates the default gesture and asociates this with * given component */ IndexedDragSource (JList comp) { this.comp = comp; // initialize gesture DragSource ds = DragSource.getDefaultDragSource(); ds.createDefaultDragGestureRecognizer( comp, DnDConstants.ACTION_MOVE, this); } /** Initiating the drag */ public void dragGestureRecognized(DragGestureEvent dge) { // check allowed actions if ((dge.getDragAction() & DnDConstants.ACTION_MOVE) == 0) return; // prepare transferable and start the drag int index = comp.locationToIndex(dge.getDragOrigin()); // no index, then no dragging... if (index < 0) return; // System.out.println("Starting drag..."); // NOI18N // create our flavor for transferring the index myFlavor = new DataFlavor(String.class, NbBundle.getBundle(IndexedCustomizer.class). getString("IndexedFlavor")); try { dge.startDrag(DragSource.DefaultMoveDrop, new IndexTransferable(myFlavor, index), this); // remember the gesture this.dge = dge; } catch (InvalidDnDOperationException exc) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, exc); // PENDING notify user - cannot start the drag } } public void dragEnter(DragSourceDragEvent dsde) { } public void dragOver(DragSourceDragEvent dsde) { } public void dropActionChanged(DragSourceDragEvent dsde) { } public void dragExit(DragSourceEvent dse) { } public void dragDropEnd(DragSourceDropEvent dsde) { } /** Utility accessor */ DragGestureEvent getDragGestureEvent () { return dge; } } // end of IndexedDragSource /** Implementation of drop functionality in * reorder dialog. */ private static final class IndexedDropTarget implements DropTargetListener { /** Asociated JList component for dropping */ JList comp; /** Cell renderer which renders the list items */ IndexedListCellRenderer cellRenderer; /** Indexed dialog */ IndexedCustomizer dialog; /** Drag source support instance */ IndexedDragSource ids; /** last index dragged over */ int lastIndex = -1; /** Creates the instance, makes given component active for * drop operation. */ IndexedDropTarget (IndexedCustomizer dialog, IndexedDragSource ids) { this.dialog = dialog; this.comp = dialog.control; this.cellRenderer = (IndexedListCellRenderer)this.comp.getCellRenderer(); this.ids = ids; new DropTarget(comp, DnDConstants.ACTION_MOVE, this, true); } /** User is starting to drag over us */ public void dragEnter(DropTargetDragEvent dtde) { if (!checkConditions(dtde)) dtde.rejectDrag(); else { lastIndex = comp.locationToIndex(dtde.getLocation()); cellRenderer.draggingEnter(lastIndex, ids.getDragGestureEvent().getDragOrigin(), dtde.getLocation()); comp.repaint(comp.getCellBounds(lastIndex, lastIndex)); } } /** User drag over us */ public void dragOver(DropTargetDragEvent dtde) { if (!checkConditions(dtde)) { dtde.rejectDrag(); if (lastIndex >= 0) { cellRenderer.draggingExit(); comp.repaint(comp.getCellBounds(lastIndex, lastIndex)); lastIndex = -1; } } else { dtde.acceptDrag(DnDConstants.ACTION_MOVE); int index = comp.locationToIndex(dtde.getLocation()); if (lastIndex == index) cellRenderer.draggingOver(index, ids.getDragGestureEvent().getDragOrigin(), dtde.getLocation()); else { if (lastIndex < 0) lastIndex = index; cellRenderer.draggingExit(); cellRenderer.draggingEnter(index, ids.getDragGestureEvent().getDragOrigin(), dtde.getLocation()); comp.repaint(comp.getCellBounds(lastIndex, index)); lastIndex = index; } } } public void dropActionChanged(DropTargetDragEvent dtde) { } /** User exits the dragging */ public void dragExit(DropTargetEvent dte) { if (lastIndex >= 0) { cellRenderer.draggingExit(); comp.repaint(comp.getCellBounds(lastIndex, lastIndex)); } } /** Takes given index transferable and reorders * the items as appropriate (and if possible) */ public void drop(DropTargetDropEvent dtde) { // reject all but local moves if ((DnDConstants.ACTION_MOVE != dtde.getDropAction()) || !dtde.isLocalTransfer()) dtde.rejectDrop(); int target = comp.locationToIndex(dtde.getLocation()); if (target < 0) { dtde.rejectDrop(); return; } Transferable t = dtde.getTransferable(); // System.out.println("Dropping..."); // NOI18N dtde.acceptDrop(DnDConstants.ACTION_MOVE); try { int source = Integer.parseInt( (String)t.getTransferData(ids.myFlavor)); if (source != target) { performReorder(source, target); dtde.dropComplete(true); } else dtde.dropComplete(false); } catch (IOException exc) { dtde.dropComplete(false); } catch (UnsupportedFlavorException exc) { dtde.dropComplete(false); } catch (NumberFormatException exc) { dtde.dropComplete(false); } } /** Actually performs the reordering which results from * succesfull drag-drop operation. * @param source */ void performReorder (int source, int target) { int[] myPerm = new int[comp.getModel().getSize()]; // positions will change only between source and target // indexes, the rest remains the same for (int i = 0; i < Math.min(source, target); i++) myPerm[i] = i; for (int i = Math.max(source, target) + 1; i < myPerm.length; i++) myPerm[i] = i; // reorder the rest myPerm[source] = target; if (source > target) { // dragging was up the list for (int i = target; i < source; i++) myPerm[i] = i + 1; } else { // dragging was down the list for (int i = source + 1; i < target + 1; i++) myPerm[i] = i - 1; } // and finally perform the reordering dialog.performReorder(myPerm, target); } /** @return True if conditions to continue with DnD * operation were satisfied */ boolean checkConditions (DropTargetDragEvent dtde) { int index = comp.locationToIndex(dtde.getLocation()); return DnDConstants.ACTION_MOVE == dtde.getDropAction() && index >= 0; } } // end of IndexedDropTarget /** This class takes responsibility of presenting the * asociated index as transferable object. */ private static final class IndexTransferable extends ExTransferable.Single { /** Index to transfer */ int index; /** Creates transferable of given index */ IndexTransferable (DataFlavor flavor, int index) { super(flavor); this.index = index; } /* Returns string representation of index */ protected Object getData () throws IOException, UnsupportedFlavorException { return String.valueOf(index); } } // end of IndexTransferable /** Implements drag and drop visual feedback * support for node list cell rendeder. */ private static final class IndexedListCellRenderer implements javax.swing.ListCellRenderer { /** delegate to use for rendering. Usually NodeRenderer, but if run * without explorer, then it uses DefaultListCellRenderer */ private javax.swing.ListCellRenderer delegate = TMUtil.findListCellRenderer (); /** Index of currently drag under cell in parent list */ int dragIndex; static final long serialVersionUID =-5526451942677242944L; protected static Border hasFocusBorder; static { hasFocusBorder = new LineBorder(UIManager.getColor("List.focusCellHighlight")); // NOI18N } /** Creates new renderer */ IndexedListCellRenderer () { dragIndex = -1; } /** DnD operation enters, update visual * presentation to the drag under state */ public void draggingEnter (int index, Point startingLoc, Point currentLoc) { // System.out.println("Entering index: " + index); // NOI18N this.dragIndex = index; } /** DnD operation dragging over. */ public void draggingOver (int index, Point startingLoc, Point currentLoc) { } /** DnD operation exits, reset visual state * back to the normal */ public void draggingExit () { dragIndex = -1; } public Component getListCellRendererComponent ( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { JComponent result = (JComponent)delegate.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus); if (index == dragIndex) { // System.out.println("Drawing...."); // NOI18N result.setBorder(hasFocusBorder); } return result; } } // end of IndexedListCellRenderer /** Implements autoscrolling support for JList. * However, JList must be contained in some JViewport. */ private static class AutoscrollJList extends JList implements Autoscroll { /** Autoscroll insets */ Insets scrollInsets; /** Insets for the autoscroll method to decide * whether really perform or not */ Insets realInsets; /** Viewport we are in */ JViewport viewport; AutoscrollJList() {} static final long serialVersionUID =5495776972406885734L; /** notify the Component to autoscroll */ public void autoscroll (Point cursorLoc) { JViewport viewport = getViewport(); Point viewPos = viewport.getViewPosition(); int viewHeight = viewport.getExtentSize().height; if ((cursorLoc.y - viewPos.y) <= realInsets.top) // scroll up viewport.setViewPosition(new Point(viewPos.x, Math.max(viewPos.y - realInsets.top, 0))); else if ((viewPos.y + viewHeight - cursorLoc.y) <= realInsets.bottom) // scroll down viewport.setViewPosition(new Point(viewPos.x, Math.min(viewPos.y + realInsets.bottom, this.getHeight() - viewHeight))); } /** @return the Insets describing the autoscrolling * region or border relative to the geometry of the * implementing Component. */ public Insets getAutoscrollInsets () { if (scrollInsets == null) { int height = this.getHeight(); scrollInsets = new Insets(height, 0, height, 0); // compute also autoscroll insets for viewport //Rectangle rect = getViewport().getViewRect(); realInsets = new Insets(15, 0, 15, 0); } return scrollInsets; } /** Asociates given viewport with this list. * (Viewport is usually parent containing this component) */ JViewport getViewport () { if (viewport == null) { Component comp = this; while (!(comp instanceof JViewport) && (comp != null)) { comp = comp.getParent(); } viewport = (JViewport)comp; } return viewport; } } // end of AutoscrollJViewport }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.