View Javadoc

1   /*
2    * Copyright (c) 2007 Creative Sphere Limited.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Eclipse Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/epl-v10.html
7    *
8    * Contributors:
9    *
10   *   Creative Sphere - initial API and implementation
11   *
12   */
13  package org.abstracthorizon.aequo.gui;
14  
15  import java.awt.Point;
16  import java.awt.Rectangle;
17  import java.awt.event.MouseEvent;
18  import java.awt.event.MouseListener;
19  import java.awt.event.MouseMotionListener;
20  
21  import javax.swing.JList;
22  import javax.swing.JPopupMenu;
23  import javax.swing.ListSelectionModel;
24  import javax.swing.event.MouseInputListener;
25  
26  import org.abstracthorizon.aequo.CompareModel;
27  import org.abstracthorizon.aequo.ListModelAdapter;
28  
29  /**
30   * Extension of {@link JList} class that provides mouse handling and ties it with {@link CompareModel}.
31   *
32   * @author Daniel Sendula
33   */
34  public class CompareList extends JList {
35  
36      /** Model */
37      protected CompareModel<?, ?> model;
38      
39      /** Focused index */
40      protected int focusedIndex;
41  
42      /**
43       * Constructor
44       * @param model model
45       */
46      public CompareList(final CompareModel<?, ?> model) {
47          super(new ListModelAdapter(model));
48          adjustMouseListeners();
49      }
50      
51      /**
52       * Returns focused index
53       * @return focused index
54       */
55      public int getFocusedIndex() {
56          return focusedIndex;
57      }
58      
59      /**
60       * Returns compare model
61       * @return compare model
62       */
63      public CompareModel<?, ?> getCompareModel() {
64          return model;
65      }
66      
67      /**
68       * This method adjusts mouse listeners of the component - it removes existing and
69       * adds own.
70       */
71      protected void adjustMouseListeners() {
72          MouseListener[] mls = getMouseListeners();
73          for (MouseListener ml : mls) {
74              removeMouseListener(ml);
75          }
76          MouseMotionListener[] mmls = getMouseMotionListeners();
77          for (MouseMotionListener mml : mmls) {
78              removeMouseMotionListener(mml);
79          }
80          MouseHandler mouseInputHandler = new MouseHandler();
81          addMouseListener(mouseInputHandler);
82          addMouseMotionListener(mouseInputHandler);
83      }
84  
85      /**
86       * Mouse handler that deals with selecting rows and popup menu. 
87       */
88      public class MouseHandler implements MouseInputListener {
89          
90          private int startIndex = -1;
91          private int lastIndex = -1;
92          private int[] startIndices;
93          private boolean select = false;
94  
95          public MouseHandler() {
96          }
97          
98          public void mouseClicked(MouseEvent e) {}
99  
100         public void mouseEntered(MouseEvent e) {}
101 
102         public void mouseExited(MouseEvent e) {}
103 
104         public void mousePressed(MouseEvent e) {
105             int i = selectedIndex(e.getPoint());
106             focusedIndex = i;
107             if ((e.getButton() == MouseEvent.BUTTON1) || ((i >= 0) && !isSelectedIndex(i))) {
108                 startIndex = i;
109                 lastIndex = -1;
110                 if (e.isControlDown()) {
111                     if (isSelectedIndex(i)) {
112                         select = false;
113                         removeSelectionInterval(i, i);
114                     } else {
115                         select = true;
116                         getSelectionModel().addSelectionInterval(i, i);
117                     }
118                     startIndices = getSelectedIndices();
119                 } else {
120                     select = true;
121                     startIndices = null;
122                     setSelectedIndex(i);
123                 }
124             } else if ((e.getButton() == MouseEvent.BUTTON2) && !isSelectedIndex(i)) {
125                 getSelectionModel().addSelectionInterval(i, i);
126             } else {
127                 startIndex = -1;
128             }
129             e.getComponent().requestFocus();
130         }
131 
132 
133         public void mouseDragged(MouseEvent e) {
134             int i = selectedIndex(e.getPoint());
135             focusedIndex = i;
136 
137             // TODO - starting selection upwards doesn't work properly!
138             ListSelectionModel selectionModel = getSelectionModel();
139             if (i >= 0) {
140                 boolean ok = false;
141                 if (lastIndex < 0) {
142                     if (select) {
143                         selectionModel.addSelectionInterval(startIndex, i);
144                     } else {
145                         selectionModel.removeSelectionInterval(startIndex, i);
146                     }
147                     ok = true;
148                 } else if (startIndex <= lastIndex) {
149                     if (lastIndex < i) {
150                         if (select) {
151                             selectionModel.addSelectionInterval(lastIndex, i);
152                         } else {
153                             selectionModel.removeSelectionInterval(lastIndex, i);
154                         }
155                     } else if (i < lastIndex) {
156                         restoreSelection(i + 1, lastIndex);
157                     }
158                     ok = true;
159                 } else if (lastIndex < startIndex) {
160                     if (i < lastIndex) {
161                         if (select) {
162                             selectionModel.addSelectionInterval(i, lastIndex);
163                         } else {
164                             selectionModel.removeSelectionInterval(i, lastIndex);
165                         }
166                     } else if (lastIndex < i) {
167                         restoreSelection(lastIndex, i - 1);
168                     }
169                     ok = true;
170                 }
171                 
172                 
173                 lastIndex = i;
174                 if (ok) {
175                     scrollRectToVisible(getUI().getCellBounds(CompareList.this, i, i));
176                 }
177             }
178         }
179 
180         public void mouseMoved(MouseEvent e) {
181         }
182 
183         public void mouseReleased(MouseEvent e) {
184             startIndex = -1;
185             startIndices = null;
186             if (e.getButton() == MouseEvent.BUTTON3) {
187                 JPopupMenu menu = getComponentPopupMenu();
188                 if (menu != null) {
189                     Point p = getPopupLocation(e);
190                     if (p != null) {
191                         menu.show(CompareList.this, p.x, p.y);
192                     }
193                 }
194             }
195         }
196      
197         /**
198          * Returns list of selected indexes
199          * @return list of selected indexes
200          */
201         protected int[] getSelectedIndices() {
202             ListSelectionModel selectionModel = getSelectionModel();
203             int min = selectionModel.getMinSelectionIndex();
204             int max = selectionModel.getMaxSelectionIndex();
205 
206             if ((min >= 0) && (max >= 0)) {
207         
208                 int size = 0;
209                 int[] res = new int[(max - min) + 1];
210                 for (int i = min; i <= max; i++) {
211                     if (selectionModel.isSelectedIndex(i)) {
212                         res[size] = i;
213                         size = size + 1;
214                     }
215                 }
216                 int[] r = new int[size];
217                 System.arraycopy(res, 0, r, 0, size);
218                 return r;
219             } else {
220                 return null;
221             }
222         }
223         
224         /**
225          * Restores selection
226          * @param from from index
227          * @param to to index
228          */
229         protected void restoreSelection(int from, int to) {
230             if (startIndices == null) {
231                 removeSelectionInterval(from, to);
232             } else {
233                 // TODO 
234                 
235                 ListSelectionModel selectionModel = getSelectionModel();
236                 selectionModel.setValueIsAdjusting(true);
237                 selectionModel.removeSelectionInterval(from, to);
238                 
239                 int i = 0;
240                 while ((i < startIndices.length) && (startIndices[i] <= to)) {
241                     int ind = startIndices[i];
242                     if (ind >= from) {
243                         selectionModel.addSelectionInterval(ind,ind);
244                     }
245                     i = i + 1;
246                 }
247                 selectionModel.setValueIsAdjusting(false);
248             }
249         }
250 
251     }
252 
253     /**
254      * Returns an index of selected entry from given point. 
255      * 
256      * @param p point 
257      * @return index or -1 if outside of extries
258      */
259     public int selectedIndex(Point p) {
260         int i = getUI().locationToIndex(CompareList.this, p);
261         Rectangle r = getUI().getCellBounds(CompareList.this, i,  i);
262         if (r != null) {
263             if (r.contains(p)) {
264                 return i;
265             }
266         }
267         return -1;
268     }
269 }