1 package com.explosion.expf.menusandtools.menu.segmented;
2
3 import java.awt.Component;
4 import java.awt.Container;
5 import java.util.ArrayList;
6 import java.util.HashMap;
7 import java.util.List;
8 import java.util.Map;
9
10 import javax.swing.JPopupMenu;
11
12 import com.explosion.expf.menusandtools.menu.ExpMenuItem;
13 import com.explosion.expf.menusandtools.menu.InvalidOrUnknownSegmentException;
14 import com.explosion.expf.menusandtools.menu.MenuException;
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 /***
37 * Code hole for duplicate code between menu components with incompatible heirarchies
38 * @author Stephen Cowx
39 * Created on 09-Mar-2005
40 */
41 public class SegmentedMenuHelper
42 {
43 private static org.apache.log4j.Logger log = org.apache.log4j.LogManager.getLogger(SegmentedMenuHelper.class);
44
45 private boolean firstTaken = false;
46 private boolean lastTaken = false;
47 private List segments = new ArrayList();
48 private Map segmentIndexes = new HashMap();
49 private Map segmentItemCounts = new HashMap();
50 private ExpSegmentedMenu theMenu;
51 private Container menuComponent;
52
53 /***
54 * @param theMenu
55 * @param menuComponent
56 */
57 public SegmentedMenuHelper(ExpSegmentedMenu expSegmentedMenu, Container jMenuComponent)
58 {
59 super();
60 this.theMenu = expSegmentedMenu;
61 this.menuComponent = jMenuComponent;
62 }
63 /***
64 * Creates a new segment in this menu, and adds a separator unless it is the first or only segment in which case it doesn;t add a separator
65 * The separator for each segment always comes BEFORE the items in the segment with the exception of the Top segment, which has no separator
66 * If they are
67 */
68 public ExpMenuSegment createNewSegment(int relativePositionOfSegmentOnMenu) throws Exception
69 {
70 ExpMenuSegment segment = new ExpMenuSegment(theMenu);
71 segmentItemCounts.put(segment, new Integer(0));
72 int segmentIndex = 0;
73
74 if (relativePositionOfSegmentOnMenu == ExpMenuSegment.ALWAYS_FIRST_SEGMENT)
75 {
76 if (firstTaken)
77 throw new MenuException("Relative position ALWAYS_FIRST_SEGMENT is already being used on menu " + menuComponent.getName() + ".");
78
79 firstTaken = true;
80 segmentIndex = 0;
81 }
82 else if (relativePositionOfSegmentOnMenu == ExpMenuSegment.ANY_POSITION)
83 {
84 if (segments.size() == 0)
85 {
86 segmentIndex = 0;
87 }
88 else if (segments.size() == 1)
89 {
90 if (lastTaken)
91 {
92 segmentIndex = 0;
93 }
94 else
95 {
96 segmentIndex = 1;
97 }
98 }
99 else if (segments.size() > 1)
100 {
101 if (lastTaken)
102 {
103 segmentIndex = segments.size()-1;
104 }
105 else
106 {
107 segmentIndex = segments.size();
108 }
109 }
110 }
111 else if (relativePositionOfSegmentOnMenu == ExpMenuSegment.ALWAYS_LAST_SEGMENT)
112 {
113 if (lastTaken)
114 throw new MenuException("Relative position ALWAYS_LAST_SEGMENT is already being used on menu " + menuComponent.getName() + ".");
115
116 lastTaken = true;
117 if (segments.size() == 0)
118 {
119 segmentIndex = 0;
120 }
121 else if (segments.size() == 1)
122 {
123 segmentIndex = 1;
124 }
125 else
126 {
127 segmentIndex = segments.size();
128 }
129 }
130
131
132 segmentIndexes.put(segment, new Integer(segmentIndex));
133 segments.add(segmentIndex,segment);
134
135
136
137
138 log.debug("Segment "+segment.hashCode() + " added : " + relativePositionOfSegmentOnMenu + " to " + this.hashCode());
139 ExpMenuSegment segmentToSeparate= null;
140 for (int i=0;i<segments.size();i++)
141 {
142 ExpMenuSegment theSegment = (ExpMenuSegment) segments.get(i);
143 int theSegmentIndex = ((Integer) segmentIndexes.get(theSegment)).intValue();
144 log.debug("Changing " + theSegment.hashCode() + " position from "+theSegmentIndex+" to "+ i);
145 segmentIndexes.put(theSegment, new Integer(i));
146
147 if ( theSegmentIndex == 0 && i == 1)
148 {
149 segmentToSeparate = theSegment;
150 }
151
152 }
153
154 if (segmentToSeparate != null)
155 {
156 addElementToSegment(segmentToSeparate, null, true);
157 }
158
159 /***
160 * Add in the separator if it is not the first component
161 * The separator for each segment always comes BEFORE the items in the segment
162 */
163 if (relativePositionOfSegmentOnMenu != ExpMenuSegment.ALWAYS_FIRST_SEGMENT && segmentIndex != 0)
164 addElementToSegment(segment, null);
165
166 return segment;
167 }
168
169 /***
170 * Inserts and element at the end of the segment
171 * @see com.explosion.expf.menusandtools.menu.segmented.ExpSegmentedMenu#addItemToSegment(com.explosion.expf.menusandtools.menu.ExpMenuSegment, java.awt.Component)
172 * @param segment
173 * @param item
174 * @throws InvalidOrUnknownSegmentException
175 */
176 public void addElementToSegment(ExpMenuSegment segment, Component item) throws InvalidOrUnknownSegmentException
177 {
178 addElementToSegment(segment, item, true);
179 }
180
181 /***
182 * Inserts and element at the end of the segment if atEnd is true otherwise it inserts it at the beginning
183 * @see com.explosion.expf.menusandtools.menu.segmented.ExpSegmentedMenu#addItemToSegment(com.explosion.expf.menusandtools.menu.ExpMenuSegment, java.awt.Component)
184 * @param segment
185 * @param item
186 * @throws InvalidOrUnknownSegmentException
187 */
188 private void addElementToSegment(ExpMenuSegment segment, Component item, boolean atEnd) throws InvalidOrUnknownSegmentException
189 {
190 int insertionIndex = getInsertionIndex(segment, atEnd);
191
192 log.debug("Segment " + segment.hashCode() + " is number " +(Integer) segmentIndexes.get(segment)
193 + " of " + segments.size() + " in "+this.hashCode()+", it has "
194 +(Integer) segmentItemCounts.get(segment)
195 +" items and "+(item != null && item instanceof ExpMenuItem ? ((ExpMenuItem)item).getText() : "item") +" will be inserted at "+insertionIndex);
196
197 if (item != null)
198 menuComponent.add(item,insertionIndex);
199 else
200 menuComponent.add(new JPopupMenu.Separator(), insertionIndex);
201
202
203 int segmentItemCount = ((Integer) segmentItemCounts.get(segment)).intValue();
204 segmentItemCounts.put(segment,new Integer(segmentItemCount+1));
205 }
206
207 /***
208 * Returns the insertionIndex for this new item
209 */
210 private int getInsertionIndex(ExpMenuSegment segment, boolean atEnd) throws InvalidOrUnknownSegmentException
211 {
212 int insertionIndex = 0;
213 Integer segmentIndex = (Integer) segmentIndexes.get(segment);
214
215 if (segmentIndex == null)
216 throw new InvalidOrUnknownSegmentException("The ExpMenuSegment you are using was not created using this menu. You cannot use segments from another ExpSegmented menu in the context of this one");
217
218 log.debug("Building up insertion index");
219 for (int i=0;i<=segmentIndex.intValue();i++)
220 {
221 if (!atEnd && i==segmentIndex.intValue())
222 {
223 insertionIndex += 1;
224 break;
225 }
226 ExpMenuSegment theSegment = (ExpMenuSegment) segments.get(i);
227 Integer segmentItemCount = (Integer) segmentItemCounts.get(theSegment);
228 log.debug(theSegment.hashCode() + " has " + segmentItemCount.intValue() + " items");
229 insertionIndex += segmentItemCount.intValue();
230 }
231 log.debug("InsertionIndex is " + insertionIndex);
232 return insertionIndex;
233 }
234
235 /***
236 * Removes all the elements except the separator from this menu
237 * @param segment
238 * @param item
239 * @throws InvalidOrUnknownSegmentException
240 */
241 public void removeSegment(ExpMenuSegment segment) throws InvalidOrUnknownSegmentException
242 {
243 log.debug("Removing segment " + segment.hashCode());
244
245 int startIndex = getInsertionIndex(segment,true)-1;
246 int endIndex = startIndex - ((Integer) segmentItemCounts.get(segment)).intValue();
247 for (int i=startIndex; i>endIndex; i--)
248 {
249 int itemCount = ((Integer) segmentItemCounts.get(segment)).intValue();
250
251
252
253
254 this.menuComponent.remove(i);
255 segmentItemCounts.put(segment, new Integer(--itemCount));
256 }
257
258 this.segments.remove(segment);
259 this.segmentIndexes.remove(segment);
260 this.segmentItemCounts.remove(segment);
261
262 }
263
264 /***
265 * Returns the first segment in this helper or null if there isn't one
266 * @return
267 */
268 public ExpMenuSegment getFirstSegment()
269 {
270 if (segments == null)
271 return null;
272 if (segments.size() < 1)
273 return null;
274
275 return (ExpMenuSegment) segments.get(0);
276 }
277
278 /***
279 * Returns the last segment in this helper or null if there isn't one
280 * @return
281 */
282 public ExpMenuSegment getLastSegment()
283 {
284 if (segments == null)
285 return null;
286 if (segments.size() < 1)
287 return null;
288
289 return (ExpMenuSegment) segments.get(segments.size() -1);
290 }
291 }