1 | // Copyright 2004-2007 Jean-Francois Poilpret |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | package net.sourceforge.hiveboard.dialog; |
16 | |
17 | import java.awt.Color; |
18 | import java.awt.Dimension; |
19 | import java.awt.GridBagConstraints; |
20 | import java.awt.GridBagLayout; |
21 | import java.awt.Image; |
22 | import java.awt.Insets; |
23 | import java.util.HashMap; |
24 | import java.util.Map; |
25 | |
26 | import javax.swing.Icon; |
27 | import javax.swing.JScrollPane; |
28 | import javax.swing.border.LineBorder; |
29 | |
30 | import org.jdesktop.application.Action; |
31 | import org.jdesktop.application.Task; |
32 | |
33 | import net.sourceforge.hiveboard.Board; |
34 | import net.sourceforge.hiveboard.Snapshot; |
35 | import net.sourceforge.hiveboard.WhiteBoardUserService; |
36 | import net.sourceforge.hiveboard.command.AbstractTask; |
37 | import net.sourceforge.hiveboard.command.ActionHelper; |
38 | import net.sourceforge.hiveboard.event.EventsPriorities; |
39 | import net.sourceforge.hiveboard.util.RGBImageHolder; |
40 | import net.sourceforge.hiveevents.PersistentConsumer; |
41 | import net.sourceforge.hivegui.application.ApplicationContextHolder; |
42 | import net.sourceforge.hivegui.component.Thumbnail; |
43 | import net.sourceforge.hivegui.table.BeanTable; |
44 | import net.sourceforge.hivegui.table.DefaultDataListModel; |
45 | import net.sourceforge.hivegui.table.TableContribution; |
46 | |
47 | // CSOFF: ClassDataAbstractionCouplingCheck |
48 | public class ListSnapshotsPanel extends AbstractBoardPanel |
49 | { |
50 | static private final String NAME = "snapshots-list"; |
51 | |
52 | public ListSnapshotsPanel( TableContribution snapshotsTableContrib, |
53 | WhiteBoardUserService service, |
54 | ApplicationContextHolder holder, |
55 | Board board, |
56 | Snapshot[] snapshots) |
57 | { |
58 | super(NAME); |
59 | setLayout(new GridBagLayout()); |
60 | _board = board; |
61 | _service = service; |
62 | |
63 | DefaultDataListModel<Snapshot> model = |
64 | new DefaultDataListModel<Snapshot>(Snapshot.class); |
65 | model.setRows(snapshots); |
66 | _tblSnapshots = new BeanTable<Snapshot>(model, snapshotsTableContrib, holder); |
67 | _tblSnapshots.setName(NAME + "-snapshots-list"); |
68 | _tblSnapshots.setPreferredScrollableViewportSize( |
69 | new Dimension(VIEWPORT_SIZE, VIEWPORT_SIZE)); |
70 | |
71 | GridBagConstraints constraints; |
72 | constraints = new GridBagConstraints( 0, 0, 1, 1, 1.0, 1.0, |
73 | GridBagConstraints.WEST, |
74 | GridBagConstraints.BOTH, |
75 | new Insets(2, 2, 2, 2), 0, 0); |
76 | |
77 | add(new JScrollPane(_tblSnapshots), constraints); |
78 | _thumbnail.setName(NAME + "-thumbnail"); |
79 | _thumbnail.setBorder(new LineBorder(Color.GRAY)); |
80 | |
81 | constraints.gridx = 1; |
82 | constraints.weightx = 0.0; |
83 | constraints.weighty = 0.0; |
84 | constraints.fill = GridBagConstraints.NONE; |
85 | add(_thumbnail, constraints); |
86 | |
87 | _tblSnapshots.clearSelection(); |
88 | int priority = EventsPriorities.DEFAULT_PRIORITY; |
89 | _tblSnapshots.addSelectionConsumer(priority, new PersistentConsumer() |
90 | { |
91 | public void push(Object event) |
92 | { |
93 | if (event != null) |
94 | { |
95 | setAcceptEnabled(true); |
96 | _snapshot = (Snapshot) event; |
97 | updateSnapshot(_snapshot.getId()); |
98 | } |
99 | else |
100 | { |
101 | setAcceptEnabled(false); |
102 | _currentId = -1; |
103 | _current = null; |
104 | _snapshot = null; |
105 | _thumbnail.setIcon((Icon) null); |
106 | } |
107 | } |
108 | }); |
109 | } |
110 | |
111 | @Override public void reset() |
112 | { |
113 | setAcceptEnabled(false); |
114 | _tblSnapshots.setDoubleClickCommand(getAction("accept")); |
115 | } |
116 | |
117 | private void updateSnapshot(int idSnapshot) |
118 | { |
119 | _currentId = idSnapshot; |
120 | Icon icon = _cache.get(_currentId); |
121 | _current = null; |
122 | if (icon != null) |
123 | { |
124 | _thumbnail.setIcon(icon); |
125 | } |
126 | else |
127 | { |
128 | // Get loadThumbnail action and execute it asynchroneously |
129 | ActionHelper.execute(getAction("loadThumbnail"), this); |
130 | } |
131 | } |
132 | |
133 | private void updateCurrentImage() |
134 | { |
135 | byte[] content = _service.getSnapshot(_currentId); |
136 | RGBImageHolder holder = new RGBImageHolder(); |
137 | holder.setImage(_board.getWidth(), _board.getHeight(), content); |
138 | _current = holder.getImage(); |
139 | } |
140 | |
141 | @Action |
142 | public Task loadThumbnail() |
143 | { |
144 | return new AbstractThumbnailLoadTask() |
145 | { |
146 | @Override protected void succeeded(Void result) |
147 | { |
148 | updateCurrentImage(); |
149 | _thumbnail.setIcon(_current); |
150 | Icon icon = _thumbnail.getThumbnailIcon(); |
151 | _cache.put(_currentId, icon); |
152 | _thumbnail.setIcon(icon); |
153 | } |
154 | }; |
155 | } |
156 | |
157 | @Action(enabledProperty = "acceptEnabled", block = Task.BlockingScope.ACTION) |
158 | public Task accept() |
159 | { |
160 | if (_current != null) |
161 | { |
162 | // Now _current contains the full-size image |
163 | SnapshotDetailPanel detail = new SnapshotDetailPanel(_board, _snapshot, _current); |
164 | // Open new dialog to display image in real size |
165 | _application.showDialog(detail); |
166 | return null; |
167 | } |
168 | |
169 | return new AbstractThumbnailLoadTask() |
170 | { |
171 | @Override protected void succeeded(Void result) |
172 | { |
173 | // Now _current contains the full-size image |
174 | SnapshotDetailPanel detail = |
175 | new SnapshotDetailPanel(_board, _snapshot, _current); |
176 | // Open new dialog to display image in real size |
177 | _application.showDialog(detail); |
178 | } |
179 | }; |
180 | } |
181 | |
182 | abstract private class AbstractThumbnailLoadTask extends AbstractTask<Void, Void> |
183 | { |
184 | protected AbstractThumbnailLoadTask() |
185 | { |
186 | super(ListSnapshotsPanel.this._application, _parent); |
187 | } |
188 | |
189 | @Override protected Void doInBackground() throws Exception |
190 | { |
191 | updateCurrentImage(); |
192 | return null; |
193 | } |
194 | } |
195 | |
196 | static final private int THUMBNAIL_SIZE = 200; |
197 | static final private int VIEWPORT_SIZE = 300; |
198 | |
199 | private final Map<Integer, Icon> _cache = new HashMap<Integer, Icon>(); |
200 | private final WhiteBoardUserService _service; |
201 | private final BeanTable<Snapshot> _tblSnapshots; |
202 | private final Thumbnail _thumbnail = new Thumbnail(THUMBNAIL_SIZE); |
203 | private int _currentId; |
204 | private Snapshot _snapshot; |
205 | private Image _current; |
206 | } |
207 | // CSON: ClassDataAbstractionCouplingCheck |