OSDN Git Service

前回作業時のウィンドウサイズ、位置、ズーム、スクロールバーの位置の復元
[charactermanaj/CharacterManaJ.git] / src / main / java / charactermanaj / ui / util / ScrollPaneDragScrollSupport.java
1 package charactermanaj.ui.util;\r
2 \r
3 import java.awt.Cursor;\r
4 import java.awt.Dimension;\r
5 import java.awt.Point;\r
6 import java.awt.event.MouseAdapter;\r
7 import java.awt.event.MouseEvent;\r
8 import java.awt.event.MouseListener;\r
9 import java.awt.event.MouseMotionListener;\r
10 import java.awt.event.MouseWheelEvent;\r
11 import java.awt.event.MouseWheelListener;\r
12 \r
13 import javax.swing.JComponent;\r
14 import javax.swing.JScrollPane;\r
15 import javax.swing.JViewport;\r
16 import javax.swing.SwingUtilities;\r
17 \r
18 import charactermanaj.model.AppConfig;\r
19 \r
20 /**\r
21  * JScrollPaneでマウスによるドラッグスクロールをサポートするためのヘルパクラス.<br>\r
22  * @author seraphy\r
23  */\r
24 public class ScrollPaneDragScrollSupport {\r
25 \r
26         /**\r
27          * 対象となるスクロールペイン\r
28          */\r
29         private JScrollPane scrollPane;\r
30 \r
31         /**\r
32          * ホイールによるスクロールで移動する分割単位.<br>\r
33          * 表示されているエリアをn等分割したサイズごとにスクロールする.<br>\r
34          */\r
35         private int wheelDivider;\r
36 \r
37         /**\r
38          * JScrollPaneを指定して構築する.\r
39          * @param scrollPane\r
40          */\r
41         public ScrollPaneDragScrollSupport(JScrollPane scrollPane) {\r
42                 if (scrollPane == null) {\r
43                         throw new IllegalArgumentException();\r
44                 }\r
45                 this.scrollPane = scrollPane;\r
46 \r
47                 AppConfig appConfig = AppConfig.getInstance();\r
48                 wheelDivider = Math.max(2, appConfig.getWheelScrollUnit());\r
49         }\r
50 \r
51         /**\r
52          * ドラッグ開始位置を示す.<br>\r
53          * スクロールが調整されるたびに新しい座標にセットし直す.<br>\r
54          * ドラッグ中であれば非nullとなる.<br>\r
55          * ドラッグが完了した場合、もしくはドラッグが開始されていなければnullとなる.<br>\r
56          */\r
57         private Point dragPt;\r
58 \r
59         /**\r
60          * ドラッグによるスクロールが可能か?<br>\r
61          * 垂直・水平のいずれのスクロールバーがない状況ではドラッグは開始されない.<br>\r
62          * @return ドラッグによるスクロールが可能である場合はtrue\r
63          */\r
64         public boolean isDragScrollable() {\r
65                 JViewport vp = scrollPane.getViewport();\r
66                 Dimension viewSize = vp.getViewSize();\r
67                 Dimension visibleSize = vp.getExtentSize();\r
68                 if (viewSize.width <= visibleSize.width\r
69                                 && viewSize.height <= visibleSize.height) {\r
70                         // ビューポートにビューが全部表示されていればドラッグは開始されない.\r
71                         return false;\r
72                 }\r
73                 return true;\r
74         }\r
75 \r
76         /**\r
77          * 現在のドラッグ位置を取得する.<br>\r
78          * ドラッグが開始されていなければnullとなる.<br>\r
79          * @return ドラッグ位置\r
80          */\r
81         public Point getDragPt() {\r
82                 return dragPt;\r
83         }\r
84 \r
85         /**\r
86          * 現在ドラッグ中であるか?\r
87          * @return ドラッグ中であればtrue\r
88          */\r
89         public boolean isDragging() {\r
90                 return dragPt != null;\r
91         }\r
92 \r
93         /**\r
94          * カーソルを設定する.\r
95          * @param cursor カーソル\r
96          */\r
97         protected void setCursor(Cursor cursor) {\r
98                 scrollPane.setCursor(cursor);\r
99         }\r
100 \r
101         /**\r
102          * ドラッグの開始または終了を行う.<br>\r
103          * すでに開始済みで開始要求するか、開始されておらず停止要求した場合は何もしない.<br>\r
104          * @param start 開始する場合はtrue、終了する場合はfalse\r
105          * @param mousePt 開始位置\r
106          */\r
107         public void drag(boolean start, Point mousePt) {\r
108                 if (start) {\r
109                         if (dragPt == null) {\r
110                                 JViewport vp = scrollPane.getViewport();\r
111                                 Dimension viewSize = vp.getViewSize();\r
112                                 Dimension visibleSize = vp.getExtentSize();\r
113                                 if (viewSize.width <= visibleSize.width\r
114                                                 && viewSize.height <= visibleSize.height) {\r
115                                         // ビューポートにビューが全部表示されていればドラッグは開始されない.\r
116                                         dragPt = null;\r
117                                         return;\r
118                                 }\r
119 \r
120                                 // ドラッグ中であることを示す\r
121                                 dragPt = mousePt;\r
122                                 setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));\r
123                         }\r
124 \r
125                 } else if (dragPt != null) {\r
126                         // ドラッグ中であれば解除する.\r
127                         // (ドラッグ解除済みであれば何もしない.)\r
128                         dragging(mousePt);\r
129                         setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));\r
130                         dragPt = null;\r
131                 }\r
132         }\r
133 \r
134         /**\r
135          * マウスによるドラッグによるスクロール.<br>\r
136          * 前回位置(初回なら開始位置)との差分からスクロール量を判定する.<br>\r
137          * @param mousePt 現在のマウス位置\r
138          */\r
139         public void dragging(Point mousePt) {\r
140                 if (dragPt == null || mousePt == null) {\r
141                         // 前回値がないか今回値がない場合は何もしない.\r
142                         return;\r
143                 }\r
144 \r
145                 // 前回座標との差分を求める\r
146                 int diff_x = dragPt.x - mousePt.x;\r
147                 int diff_y = dragPt.y - mousePt.y;\r
148 \r
149                 scroll(diff_x, diff_y);\r
150 \r
151                 // 現在位置を記録\r
152                 dragPt = mousePt;\r
153         }\r
154 \r
155         /**\r
156          * マウス座標単位で指定したオフセット分スクロールする.\r
157          * @param diff_x 水平方向スクロール数\r
158          * @param diff_y 垂直方向スクロール数\r
159          */\r
160         public void scroll(int diff_x, int diff_y) {\r
161                 if (diff_x == 0 && diff_y == 0) {\r
162                         return;\r
163                 }\r
164 \r
165                 JViewport vp = scrollPane.getViewport();\r
166                 Dimension viewSize = vp.getViewSize();\r
167                 Dimension visibleSize = vp.getExtentSize();\r
168 \r
169                 Point vpt = vp.getViewPosition();\r
170 \r
171                 vpt.x += diff_x;\r
172                 if (vpt.x < 0) {\r
173                         vpt.x = 0;\r
174 \r
175                 } else if (vpt.x + visibleSize.width > viewSize.width) {\r
176                         // はみ出た分を引く\r
177                         vpt.x -= (vpt.x + visibleSize.width - viewSize.width);\r
178                 }\r
179 \r
180                 vpt.y += diff_y;\r
181                 if (vpt.y < 0) {\r
182                         vpt.y = 0;\r
183 \r
184                 } else if (vpt.y + visibleSize.height > viewSize.height) {\r
185                         // はみ出た分を引く\r
186                         vpt.y -= (vpt.y + visibleSize.height - viewSize.height);\r
187                 }\r
188 \r
189                 vp.setViewPosition(vpt);\r
190         }\r
191 \r
192         /**\r
193          * ホイールによるスクロール量の分割数.<br>\r
194          * 表示されている領域に対してn等分割したサイズを\r
195          * 一回あたりのスクロール量とする.<br>\r
196          * @return スクロール量の分割数\r
197          */\r
198         public int getWheelDivider() {\r
199                 return wheelDivider;\r
200         }\r
201 \r
202         public void setWheelFactor(int wheelDivider) {\r
203                 this.wheelDivider = Math.max(2, wheelDivider);\r
204         }\r
205 \r
206         /**\r
207          * マウスホイールによる水平・垂直スクロールを行うためのコンビニエスとメソッド.<br>\r
208          * シフトキーで水平、それ以外は垂直とする.<br>\r
209          * @param e ホイールイベント\r
210          */\r
211         public void scrollByWheel(final MouseWheelEvent e) {\r
212                 if (e == null) {\r
213                         return;\r
214                 }\r
215 \r
216                 JViewport vp = scrollPane.getViewport();\r
217                 Dimension visibleSize = vp.getExtentSize();\r
218 \r
219                 int rotation = e.getWheelRotation();\r
220 \r
221                 int diff_x = 0;\r
222                 int diff_y = 0;\r
223 \r
224                 if (e.isShiftDown()) {\r
225                         // 水平スクロール\r
226                         int unit = visibleSize.width / getWheelDivider();\r
227                         diff_x = rotation * unit;\r
228 \r
229                 } else {\r
230                         // 垂直スクロール\r
231                         int unit = visibleSize.height / getWheelDivider();\r
232                         diff_y = rotation * unit;\r
233                 }\r
234 \r
235                 scroll(diff_x, diff_y);\r
236         }\r
237 \r
238 \r
239         /**\r
240          * セットアップしたリスナを保存するもの\r
241          */\r
242         private MouseListener mouseListener;\r
243 \r
244         /**\r
245          * セットアップしたリスナを保存するもの\r
246          */\r
247         private MouseMotionListener mouseMotionListener;\r
248 \r
249         /**\r
250          * セットアップしたリスナを保存するもの\r
251          */\r
252         private MouseWheelListener mouseWheelListener;\r
253 \r
254         /**\r
255          * リスナをセットアップしたコンポーネント\r
256          */\r
257         private JComponent installTarget;\r
258 \r
259         /**\r
260          * ドラッグの開始に相応しいボタンプレスであるか判定するためのインターフェイス.\r
261          * @author seraphy\r
262          */\r
263         public interface DragPridicator {\r
264 \r
265                 /**\r
266                  * このマウスイベントでドラッグ開始しても良いか?\r
267                  * @param e マウスイベント\r
268                  * @return ドラッグを開始しても良い場合はtrue\r
269                  */\r
270                 boolean isDraggable(MouseEvent e);\r
271 \r
272         }\r
273 \r
274 \r
275         /**\r
276          * マウスによるドラッグをサポートする、一般的なマウスリスナとマウスモーションリスナをセットアップする.<br>\r
277          * すでに登録済みであれば何もしない.<br>\r
278          * このメソッドはマウスリスナに特別な処理が必要ない場合に定型的な処理を代行するコンビニエスメソッドです.<br>\r
279          * @param comp マウスリスナをセットアップするターゲットのコンポーネント\r
280          * @param predicator マウスによるドラッグの開始を行うか判定するためのオブジェクト、nullの場合は不問\r
281          */\r
282         public void installDraggingListener(final JComponent comp, final DragPridicator predicator) {\r
283                 if (comp == null) {\r
284                         throw new IllegalArgumentException();\r
285                 }\r
286                 if (mouseListener == null) {\r
287                         mouseListener = new MouseAdapter() {\r
288                                 @Override\r
289                                 public void mousePressed(MouseEvent e) {\r
290                                         if (predicator == null || predicator.isDraggable(e)) {\r
291                                                 Point pt = SwingUtilities.convertPoint(\r
292                                                                 comp, e.getPoint(), scrollPane);\r
293                                                 drag(true, pt);\r
294                                         }\r
295                                 }\r
296                                 @Override\r
297                                 public void mouseReleased(MouseEvent e) {\r
298                                         if (predicator == null || predicator.isDraggable(e)) {\r
299                                                 Point pt = SwingUtilities.convertPoint(\r
300                                                                 comp, e.getPoint(), scrollPane);\r
301                                                 drag(false, pt);\r
302                                         }\r
303                                 }\r
304                         };\r
305                         // リスナを登録する.\r
306                         comp.addMouseListener(mouseListener);\r
307                 }\r
308                 if (mouseMotionListener == null) {\r
309                         mouseMotionListener = new MouseMotionListener() {\r
310                                 public void mouseMoved(MouseEvent e) {\r
311                                         // 何もしない.\r
312                                 }\r
313                                 public void mouseDragged(MouseEvent e) {\r
314                                         Point pt = SwingUtilities.convertPoint(\r
315                                                         comp, e.getPoint(), scrollPane);\r
316                                         dragging(pt);\r
317                                 }\r
318                         };\r
319                         // リスナを登録する.\r
320                         comp.addMouseMotionListener(mouseMotionListener);\r
321                 }\r
322 \r
323                 if (mouseWheelListener == null) {\r
324                         mouseWheelListener = new MouseWheelListener() {\r
325                                 public void mouseWheelMoved(MouseWheelEvent e) {\r
326                                         scrollByWheel(e);\r
327                                         e.consume();\r
328                                 }\r
329                         };\r
330                         // ホイールスクロールのデフォルト設定を解除する.\r
331                         scrollPane.setWheelScrollingEnabled(false);\r
332                         // リスナを登録する.\r
333                         comp.addMouseWheelListener(mouseWheelListener);\r
334                 }\r
335 \r
336                 installTarget = comp;\r
337         }\r
338 \r
339         /**\r
340          * セットアップしたリスナを解除する.<br>\r
341          * 登録されていない場合は何もしない.<br>\r
342          */\r
343         public void uninstallDraggingListener() {\r
344                 if (mouseListener != null && installTarget != null) {\r
345                         installTarget.removeMouseListener(mouseListener);\r
346                         mouseListener = null;\r
347                 }\r
348                 if (mouseMotionListener != null && installTarget != null) {\r
349                         installTarget.removeMouseMotionListener(mouseMotionListener);\r
350                         mouseMotionListener = null;\r
351                 }\r
352                 if (mouseWheelListener != null && installTarget != null) {\r
353                         installTarget.removeMouseWheelListener(mouseWheelListener);\r
354                         mouseWheelListener = null;\r
355                 }\r
356         }\r
357 }\r