001    package sale;
002    
003    import java.util.*;
004    
005    import javax.swing.*;
006    
007    /**
008     * A MenuSheet consisting of {@link MenuSheetObject MenuSheetObjects}.
009     *
010     * <p>MenuSheets represent menus, abstracting from the form they are being displayed in. A MenuSheet could be
011     * displayed as a JMenuBar as well as a JMenu or JPopUpMenu. Independently of this it will always behave in
012     * the same way from the point of view of the applicion developer.</p>
013     *
014     * @author Steffen Zschaler
015     * @version 2.0 20/05/1999
016     * @since v1.0
017     */
018    public class MenuSheet extends MenuSheetObject {
019    
020        /**
021             * ID for serialization.
022             */
023            private static final long serialVersionUID = -9113481311456989013L;
024    
025            /**
026         * The JMenu peer, if any.
027         */
028        protected transient JMenu m_jmPeer = null;
029    
030        /**
031         * The JMenuBar peer, if any.
032         */
033        protected transient JMenuBar m_jmbBarPeer = null;
034    
035        /**
036         * The monitor used to synchronize access to the peers.
037         */
038        private transient Object m_oPeerLock;
039        /**
040         * Return the monitor used to synchronized access to the peers.
041         *
042         * @override Never
043         */
044        protected final Object getPeerLock() {
045            if (m_oPeerLock == null) {
046                m_oPeerLock = new Object();
047            }
048    
049            return m_oPeerLock;
050        }
051    
052        /**
053         * The MenuSheet that has been merged into this one, if any.
054         *
055         * @serial
056         */
057        protected MenuSheet m_msMerged = null;
058    
059        /**
060         * The tag before which the merged menu was inserted.
061         *
062         * @serial
063         */
064        protected String m_sMergedBefore = null;
065    
066        /**
067         * The peer index at which the merged menu was inserted.
068         *
069         * @serial
070         */
071        protected int m_nMergedAt = -1;
072    
073        /**
074         * The MenuSheet into which this MenuSheet was merged, if any.
075         *
076         * @serial
077         */
078        protected MenuSheet m_msMergeParent = null;
079    
080        /**
081         * The items of this MenuSheet.
082         *
083         * @serial
084         */
085        protected LinkedList<MenuSheetObject> m_lmsoItems;
086    
087        /**
088         * The Images associated with the icons of this MenuSheet( [0]:DefaultImage, [1]:PressedImage,
089         * [2]:DisabledImage, [3]:PressedDiabledImage ).
090         *
091         * @serial
092         */
093        protected ImageIcon m_aiImages[] = null;
094    
095        /**
096         * The Mnemonic of this MenuSheet.
097         *
098         * @serial
099         */
100        protected char m_cMnemonic;
101    
102        /**
103         * The ToolTip of this MenuSheet.
104         *
105         * @serial
106         */
107        protected String m_sToolTip = "";
108    
109        private void writeObject(java.io.ObjectOutputStream oos) throws java.io.IOException {
110            util.Debug.print("Starting to write menu sheet: \"" + getCaption() + "\" <" + getTag() + ">", -1);
111    
112            oos.defaultWriteObject();
113    
114            util.Debug.print("Done writing menu sheet: \"" + getCaption() + "\" <" + getTag() + ">", -1);
115        }
116    
117        // Helpmethod for setting an ImageIcon
118        private void setIcon(ImageIcon iiImageIcon, int nIndex) {
119            if (m_aiImages == null) {
120                m_aiImages = new ImageIcon[4];
121    
122            }
123            m_aiImages[nIndex] = iiImageIcon;
124    
125            synchronized (getPeerLock()) {
126                if (m_jmPeer != null) {
127                    switch (nIndex) {
128                        case DEFAULT_IMAGE:
129                            m_jmPeer.setIcon(iiImageIcon);
130                            break;
131                        case SELECTED_IMAGE:
132                            m_jmPeer.setSelectedIcon(iiImageIcon);
133                            break;
134                        case DISABLED_IMAGE:
135                            m_jmPeer.setDisabledIcon(iiImageIcon);
136                            break;
137                        case DISABLED_SELECTED_IMAGE:
138                            m_jmPeer.setDisabledSelectedIcon(iiImageIcon);
139                            break;
140                    }
141    
142                    m_jmPeer.validate();
143                }
144            }
145        }
146    
147        /**
148         * Creates a new MenuSheet with caption, tag and mnemonic.
149         *
150         * @param sCaption the caption of the new MenuSheet.
151         * @param sTag the tag of the new MenuSheet. If <code>null</code> a default tag will be created.
152         * @param cMnemonic the mnemonic of the new MenuSheet.
153         */
154        public MenuSheet(String sCaption, String sTag, char cMnemonic) {
155            super(sCaption, sTag);
156            m_cMnemonic = cMnemonic;
157    
158            m_lmsoItems = new LinkedList<MenuSheetObject>();
159        }
160    
161        /**
162         * Creates a new MenuSheet with caption and tag.
163         *
164         * @param sCaption the caption of the new MenuSheet.
165         * @param sTag the tag of the new MenuSheet. If <code>null</code> a default tag will be created.
166         */
167        public MenuSheet(String sCaption, String sTag) {
168            this(sCaption, sTag, '\0');
169    
170            m_lmsoItems = new LinkedList<MenuSheetObject>();
171        }
172    
173        /**
174         * Creates a new MenuSheet with caption and a default tag.
175         *
176         * @param sCaption the caption of the new MenuSheet.
177         */
178        public MenuSheet(String sCaption) {
179            this(sCaption, null, '\0');
180        }
181    
182        /**
183         * Adds a MenuSheetObject to the end of this MenuSheet.
184         *
185         * <p>Should the MenuSheet currently be displayed, the new item will be displayed as
186         * well.</p>
187         *
188         * @override Never
189         *
190         * @param mso the new MenuSheetObject.
191         */
192        public synchronized void add(MenuSheetObject mso) {
193            if (m_msMergeParent == null) {
194                // we are not merged into some other MenuSheet, so we posess the peer.
195                synchronized (getPeerLock()) {
196                    // update peer
197    
198                    if (mso.isSeparator()) {
199                        if (m_jmPeer != null) {
200                            m_jmPeer.addSeparator();
201                            m_jmPeer.validate();
202                        }
203                    } else {
204                        if (m_jmPeer != null) {
205                            m_jmPeer.add(mso.getPeer());
206                            m_jmPeer.validate();
207                        }
208    
209                        if (m_jmbBarPeer != null) {
210                            JMenu jm = mso.getMenuPeer();
211                            m_jmbBarPeer.add(jm);
212                            if (HELP_MENU_TAG.equals(mso.getTag())) {
213                                m_jmbBarPeer.setHelpMenu(jm);
214                            }
215                            m_jmbBarPeer.validate();
216                        }
217                    }
218                }
219    
220                // insert MenuSheetObject
221                m_lmsoItems.addLast(mso); // Attention: Must be after peer update to make sure,
222                // we don't change the list while trying to create the
223                // peer.
224            } else {
225                // We are merged into another MenuSheet, so we don't manage the peer.
226    
227                m_lmsoItems.addLast(mso);
228    
229                // Tell merge parent to update peer.
230                if (!mso.isSeparator()) {
231                    int nIndex = m_lmsoItems.size() - 1; // nIndex == m_lmsoItems.indexOf (mso)
232    
233                    // index needs to be in peer "coordinates"
234                    for (Iterator<MenuSheetObject> i = m_lmsoItems.iterator(); i.hasNext(); ) {
235                        if (i.next().isSeparator()) {
236                            nIndex--;
237                        }
238                    }
239    
240                    m_msMergeParent.mergedAdd(mso, nIndex);
241                }
242            }
243    
244            // Tell new item about its new environment
245            mso.setParent(this);
246            mso.setVisible(isVisible());
247            mso.attach(m_spAttached);
248            mso.attach(m_pAttached);
249        }
250    
251        /**
252         * Internal method used for updating merged peers correctly.
253         *
254         * @override Never
255         *
256         * @param mso the MenuSheet that was added in the merged MenuSheet.
257         * @param nIndex the peer index at which the element was added into the merged MenuSheet.
258         */
259        synchronized void mergedAdd(MenuSheetObject mso, int nIndex) {
260            if (m_msMergeParent == null) {
261                synchronized (getPeerLock()) {
262                    if (m_jmbBarPeer != null) {
263                        m_jmbBarPeer.add(mso.getMenuPeer(), nIndex + m_nMergedAt);
264                        m_jmbBarPeer.validate();
265                    }
266                }
267            } else {
268                m_msMergeParent.mergedAdd(mso, nIndex + m_nMergedAt);
269            }
270        }
271    
272        /**
273         * Remove a tagged top level item from the MenuSheet.
274         *
275         * <p>If an item with the given tag is found among the top level items of this
276         * MenuSheet, it is removed and the removed item is returned. Otherwise, the call is
277         * ignored.</p>
278         *
279         * <p>If the MenuSheet is currently on display, the peer will reflect the changes.</p>
280         *
281         * @override Never
282         *
283         * @param sTag the tag of the item to be removed.
284         *
285         * @return the removed item
286         */
287        public MenuSheetObject remove(String sTag) {
288            MenuSheetObject msoRemove = getTaggedItem(sTag, true);
289    
290            return ((msoRemove != null) ? (remove(msoRemove)) : (null));
291        }
292    
293        /**
294         * Remove a MenuSheetObject from the MenuSheet.
295         *
296         * <p>If the MenuSheet is currently on display, the peer will reflect the changes.</p>
297         *
298         * @override Never
299         *
300         * @param mso the MenuSheetObject to be removed.
301         *
302         * @return the removed MenuSheetObject.
303         */
304        public synchronized MenuSheetObject remove(MenuSheetObject msoRemove) {
305            // find the index of the item
306            int nIndex = m_lmsoItems.indexOf(msoRemove);
307            if (nIndex == -1) {
308                // item not found
309                return null;
310            }
311    
312            if (m_msMergeParent == null) {
313                // We have the peer, so we update it.
314                synchronized (getPeerLock()) {
315                    if (m_jmPeer != null) {
316                        m_jmPeer.remove(nIndex); // Separators can only be removed via index
317                        m_jmPeer.validate();
318                    }
319    
320                    if (!msoRemove.isSeparator()) {
321                        if (m_jmbBarPeer != null) {
322                            m_jmbBarPeer.remove(msoRemove.getMenuPeer());
323                            m_jmbBarPeer.validate();
324                        }
325                    }
326                }
327            } else {
328                // inform MenuSheet into which we are merged
329                m_msMergeParent.mergedRemove(msoRemove);
330            }
331    
332            // remove item
333            m_lmsoItems.remove(msoRemove);
334    
335            // set item's environment.
336            msoRemove.attach((SalesPoint)null);
337            msoRemove.attach((SaleProcess)null);
338            msoRemove.setVisible(false);
339            msoRemove.setParent(null);
340    
341            return msoRemove;
342        }
343    
344        /**
345         * Internal method used to properly update merged peers.
346         *
347         * @override Never
348         *
349         * @param mso the MenuSheetObject that was removed from the merged MenuSheet.
350         */
351        synchronized void mergedRemove(MenuSheetObject mso) {
352            if (m_msMergeParent == null) {
353                synchronized (getPeerLock()) {
354                    if ((m_jmbBarPeer != null) && (!mso.isSeparator())) {
355                        m_jmbBarPeer.remove(mso.getMenuPeer());
356                        m_jmbBarPeer.validate();
357                    }
358                }
359            } else {
360                m_msMergeParent.mergedRemove(mso);
361            }
362        }
363    
364        /**
365         * Return a <i>fail-fast</i>, readonly iterator of the items in this MenuSheet.
366         *
367         * <p>Fail-fast means, that this iterator will throw a <code>ConcurrentModificationException</code> when a
368         * structural change occured to the underlying MenuSheet.</p>
369         *
370         * <p>Also, the <code>remove()</code> method will throw an <code>UnsupportedOperationException</code>, as
371         * this is a readonly iterator.</p>
372         *
373         * @override Never
374         *
375         * @see ConcurrentModificationException
376         */
377        public Iterator<MenuSheetObject> iterator() {
378            class I implements Iterator<MenuSheetObject> {
379                private Iterator<MenuSheetObject> m_i;
380    
381                public I(Iterator<MenuSheetObject> i) {
382                    m_i = i;
383                }
384    
385                public boolean hasNext() {
386                    return m_i.hasNext();
387                }
388    
389                public MenuSheetObject next() {
390                    return m_i.next();
391                }
392    
393                public void remove() {
394                    throw new UnsupportedOperationException(
395                            "Please use the MenuSheet's remove() methods, not the iterator's.");
396                }
397            }
398    
399            return new I(m_lmsoItems.iterator());
400        }
401    
402        /**
403         * Internal method used when merging peers.
404         *
405         * @override Never
406         */
407        synchronized void setMergeParent(MenuSheet msMergeParent) {
408            m_msMergeParent = msMergeParent;
409        }
410    
411        /**
412         * Merges the peers of two MenuSheets. If a MenuSheet is already merged into this one,
413         * it will be removed and marked invisible.
414         *
415         * <p>The peers of the top level MenuSheetObjects of the given MenuSheet are merged
416         * into the JMenuBar peer of this MenuSheet. They will be inserted into the JMenuBar
417         * peer before the MenuSheetpObject with the given tag. If no such MenuSheetObject can
418         * be found in the MenuSheet they are appended to the end of the peer.</p>
419         *
420         * <p>Merging can always only result in a JMenuBar peer. A JMenu peer cannot be merged.
421         * However, merging can be nested. I.e. it is legal, to merge a MenuSheet, into whose
422         * peer another MenuSheet's peer has been merged, into a third MenuSheet.</p>
423         *
424         * <p>Although the peers of the two MenuSheets are merged, they stay independent with
425         * respect to anything else. The MenuSheetObjects of the merged MenuSheet can still
426         * only be accessed through that MenuSheet and vice-vera. Also, the attached SalesPoint
427         * and SaleProcess stay independent.</p>
428         *
429         * <p>For merging to function correctly, you must set the created JMenuBar in your
430         * JFrame. Something like this will do the trick:</p>
431         * <pre>
432         *   setJMenuBar (ms.mergePeers (msToMerge, "MERGE_BEFORE_THIS"));
433         * </pre>
434         *
435         * <p>This method is usually not called directly.</p>
436         *
437         * @param msToMerge the MenuSheet to be merged into this one.
438         * @param sBeforeTag before which tag to merge in the MenuSheet.
439         *
440         * @override Never
441         */
442        public final JMenuBar mergePeers(MenuSheet msToMerge, String sBeforeTag) {
443            synchronized (getPeerLock()) {
444                boolean fVisible = isVisible();
445    
446                if (fVisible) {
447                    setVisible(false);
448                }
449    
450                if (m_msMerged != null) {
451                    m_msMerged.setMergeParent(null);
452                }
453    
454                m_msMerged = msToMerge;
455                m_sMergedBefore = sBeforeTag;
456                m_nMergedAt = -1;
457    
458                if (m_msMerged != null) {
459                    m_msMerged.setMergeParent(this);
460                }
461    
462                if (fVisible) {
463                    setVisible(true);
464                }
465                if (m_msMergeParent != null) {
466                    return m_msMergeParent.remergePeers();
467                } else {
468                    return getMenuBar();
469                }
470            }
471        }
472    
473        /**
474         * Internal method used for proper merging of peers.
475         *
476         * @override Never
477         */
478        JMenuBar remergePeers() {
479            return mergePeers(m_msMerged, m_sMergedBefore);
480        }
481    
482        /**
483         * Get a MenuSheetObject by its tag.
484         *
485         * <p>This will iterate over all MenuSheetObjects in this MenuSheet and return the
486         * first one, that has the given tag.</p>
487         *
488         * @override Never
489         *
490         * @param sTag the tag to search for.
491         * @param fTopLevelOnly if true, only the direct elements in this MenuSheet are searched.
492         *
493         * @exception ConcurrentModificationException if the structure of the MenuSheet changed
494         * during the search.
495         *
496         * @return the first MenuSheetObject that has the given tag, if any.
497         */
498        public MenuSheetObject getTaggedItem(String sTag, boolean fTopLevelOnly) {
499            MenuSheetObject msoReturn = super.getTaggedItem(sTag, fTopLevelOnly);
500            if (msoReturn != null) {
501                return msoReturn;
502            }
503    
504            for (Iterator<MenuSheetObject> i = iterator(); i.hasNext(); ) {
505                MenuSheetObject mso = i.next();
506    
507                if (fTopLevelOnly) {
508                    String sCurTag = mso.getTag();
509    
510                    if (sCurTag.equals(sTag)) {
511                        return mso;
512                    }
513                } else {
514                    msoReturn = mso.getTaggedItem(sTag, fTopLevelOnly);
515    
516                    if (msoReturn != null) {
517                        return msoReturn;
518                    }
519                }
520            }
521    
522            return null;
523        }
524    
525        /**
526         * Attach a SalesPoint to this MenuSheet.
527         *
528         * @override Never
529         */
530        public synchronized SalesPoint attach(SalesPoint sp) {
531            for (Iterator<MenuSheetObject> i = iterator(); i.hasNext(); ) {
532                i.next().attach(sp);
533            }
534    
535            return super.attach(sp);
536        }
537    
538        /**
539         * Attach a SaleProcess to this MenuSheet.
540         *
541         * @override Never
542         */
543        public synchronized SaleProcess attach(SaleProcess p) {
544            for (Iterator<MenuSheetObject> i = iterator(); i.hasNext(); ) {
545                i.next().attach(p);
546            }
547    
548            return super.attach(p);
549        }
550    
551        /**
552         * Mark this MenuSheet, all its descendants and merged peer MenuSheets visible or
553         * invisible.
554         *
555         * @override Never
556         */
557        public synchronized void setVisible(boolean fVisible) {
558            super.setVisible(fVisible);
559    
560            for (Iterator<MenuSheetObject> i = iterator(); i.hasNext(); ) {
561                i.next().setVisible(fVisible);
562            }
563    
564            if (m_msMerged != null) {
565                m_msMerged.setVisible(fVisible);
566            }
567    
568            if (!fVisible) {
569                synchronized (getPeerLock()) {
570                    if (m_jmbBarPeer != null) {
571                        m_jmbBarPeer.removeAll();
572                        m_jmbBarPeer = null;
573                    }
574    
575                    if (m_jmPeer != null) {
576                        m_jmPeer.removeAll();
577                        m_jmPeer = null;
578                    }
579                }
580            }
581        }
582    
583        /**
584         * Set the caption of this MenuSheet.
585         *
586         * <p>If there is a peer it will reflect the changes immediately.</p>
587         *
588         * @override Never
589         *
590         * @param sCaption the new caption.
591         */
592        public void setCaption(String sCaption) {
593            super.setCaption(sCaption);
594    
595            synchronized (getPeerLock()) {
596                if (m_jmPeer != null) {
597                    m_jmPeer.setText(sCaption);
598                    m_jmPeer.validate();
599                }
600            }
601        }
602    
603        /**
604         * Set the mnemonic of this MenuSheet.
605         *
606         * <p>If there is a peer it will reflect the changes immediately.</p>
607         *
608         * @override Never
609         *
610         * @param sMnemonic the new mnemonic.
611         */
612        public void setMnemonic(char cMnemonic) {
613            m_cMnemonic = cMnemonic;
614    
615            synchronized (getPeerLock()) {
616                if (m_jmPeer != null) {
617                    m_jmPeer.setMnemonic(cMnemonic);
618                    m_jmPeer.validate();
619                }
620            }
621        }
622    
623        /**
624         * Set the ToolTip of this MenuSheet.
625         *
626         * <p>If there is a peer it will reflect the changes immediately.</p>
627         *
628         * @override Never
629         *
630         * @param s the new ToolTip-Text.
631         */
632        public void setToolTipText(String s) {
633            m_sToolTip = s;
634    
635            synchronized (getPeerLock()) {
636                if (m_jmPeer != null) {
637                    m_jmPeer.setToolTipText(s);
638                    m_jmPeer.validate();
639                }
640            }
641        }
642    
643        /**
644         * Set the default icon of this MenuSheet.
645         *
646         * <p>If there is a peer it will reflect the changes immediately.</p>
647         *
648         * @override Never
649         *
650         * @param iiImageIcon the new icon.
651         */
652        public void setDefaultIcon(ImageIcon iiImageIcon) {
653            setIcon(iiImageIcon, DEFAULT_IMAGE);
654        }
655    
656        /**
657         * Set the selected icon of this MenuSheet.
658         *
659         * <p>If there is a peer it will reflect the changes immediately.</p>
660         *
661         * @override Never
662         *
663         * @param iiImageIcon the new icon.
664         */
665        public void setSelectedIcon(ImageIcon iiImageIcon) {
666            setIcon(iiImageIcon, SELECTED_IMAGE);
667        }
668    
669        /**
670         * Set the disabled icon of this MenuSheet.
671         *
672         * <p>If there is a peer it will reflect the changes immediately.</p>
673         *
674         * @override Never
675         *
676         * @param iiImageIcon the new icon.
677         */
678        public void setDisabledIcon(ImageIcon iiImageIcon) {
679            setIcon(iiImageIcon, DISABLED_IMAGE);
680        }
681    
682        /**
683         * Set the disabled selected icon of this MenuSheet.
684         *
685         * <p>If there is a peer it will reflect the changes immediately.</p>
686         *
687         * @override Never
688         *
689         * @param iiImageIcon the new icon.
690         */
691        public void setDisabledSelectedIcon(ImageIcon iiImageIcon) {
692            setIcon(iiImageIcon, DISABLED_SELECTED_IMAGE);
693        }
694    
695        /**
696         * The JMenuItem peer of a MenuSheet is, of course, a JMenu.
697         *
698         * @override Never
699         */
700        public JMenuItem getPeer() {
701            synchronized (getPeerLock()) {
702                if (m_jmPeer == null) {
703                    m_jmPeer = new JMenu(getCaption());
704    
705                    // add Mnemonic to JMenu if exists
706                    if (m_cMnemonic != '\0') {
707                        m_jmPeer.setMnemonic(m_cMnemonic);
708    
709                    }
710                    if (m_sToolTip.compareTo("") != 0) {
711                        m_jmPeer.setToolTipText(m_sToolTip);
712                    }
713    
714                    if (m_aiImages != null) {
715                        // add DefaultIcon, if any
716                        if (m_aiImages[DEFAULT_IMAGE] != null) {
717                            m_jmPeer.setIcon(m_aiImages[DEFAULT_IMAGE]);
718                            // add PressedIcon, if any
719                        }
720                        if (m_aiImages[SELECTED_IMAGE] != null) {
721                            m_jmPeer.setSelectedIcon(m_aiImages[SELECTED_IMAGE]);
722                            // add DisabledIcon, if any
723                        }
724                        if (m_aiImages[DISABLED_IMAGE] != null) {
725                            m_jmPeer.setDisabledIcon(m_aiImages[DISABLED_IMAGE]);
726                            // add DisabledSelectedIcon, if any
727                        }
728                        if (m_aiImages[DISABLED_SELECTED_IMAGE] != null) {
729                            m_jmPeer.setDisabledSelectedIcon(m_aiImages[DISABLED_SELECTED_IMAGE]);
730                        }
731                    }
732    
733                    for (Iterator<MenuSheetObject> i = iterator(); i.hasNext(); ) {
734                        MenuSheetObject mso = i.next();
735    
736                        if (mso.isSeparator()) {
737                            m_jmPeer.addSeparator();
738                        } else {
739                            m_jmPeer.add(mso.getPeer());
740                        }
741                    }
742                }
743            }
744    
745            return m_jmPeer;
746        }
747    
748        /**
749         * For MenuSheets there is no difference between JMenuItem and JMenu peer, they are
750         * both JMenus.
751         *
752         * @override Never
753         */
754        public JMenu getMenuPeer() {
755            return (JMenu)getPeer();
756        }
757    
758        /**
759         * Return the JMenuBar peer.
760         *
761         * <p>For a MenuSheet there is a special peer: the JMenuBar peer. All items of this
762         * MenuSheet will present their JMenu peer in the JMenuBar. Only MenuSheetSeparators
763         * are not displayed in a JMenuBar representation. Merged peers are only displayed in
764         * the JMenuBar representation.</p>
765         *
766         * @override Never
767         */
768        public JMenuBar getMenuBar() {
769            synchronized (getPeerLock()) {
770                if (m_jmbBarPeer == null) {
771                    boolean fResolvedMerge = false;
772    
773                    m_jmbBarPeer = new JMenuBar();
774    
775                    for (Iterator<MenuSheetObject> i = iterator(); i.hasNext(); ) {
776                        MenuSheetObject mso = i.next();
777    
778                        if ((!fResolvedMerge) && (m_msMerged != null)) {
779                            if (mso.getTag().equals(m_sMergedBefore)) {
780    
781                                m_nMergedAt = m_jmbBarPeer.getMenuCount();
782                                synchronized (m_msMerged) {
783                                    MenuElement[] ajmMerged = m_msMerged.getMenuBar().getSubElements();
784                                    m_msMerged.getMenuBar().removeAll();
785    
786                                    for (int n = 0; n < ajmMerged.length; n++) {
787                                        m_jmbBarPeer.add((JMenu)ajmMerged[n]);
788                                    }
789                                }
790    
791                                fResolvedMerge = true;
792                            }
793                        }
794    
795                        if (!mso.isSeparator()) {
796                            m_jmbBarPeer.add(mso.getMenuPeer());
797                            if (HELP_MENU_TAG.equals(mso.getTag())) {
798                                m_jmbBarPeer.setHelpMenu(mso.getMenuPeer());
799                            }
800                        }
801                    }
802    
803                    if ((!fResolvedMerge) && (m_msMerged != null)) {
804                        // mark merge at end !
805                        m_sMergedBefore = null;
806                        m_nMergedAt = m_jmbBarPeer.getMenuCount();
807    
808                        synchronized (m_msMerged) {
809                            MenuElement[] ajmMerged = m_msMerged.getMenuBar().getSubElements();
810                            m_msMerged.getMenuBar().removeAll();
811    
812                            for (int n = 0; n < ajmMerged.length; n++) {
813                                m_jmbBarPeer.add((JMenu)ajmMerged[n]);
814                            }
815                        }
816                    }
817                }
818            }
819    
820            return m_jmbBarPeer;
821        }
822    
823        /**
824         * Get the Mnemonic of this MenuSheet.
825         *
826         * @override Never
827         *
828         * @return the mnemonic of this MenuSheet.
829         */
830        public char getMnemonic() {
831            return m_cMnemonic;
832        }
833    
834        /**
835         * Get the ToolTip of this MenuSheet.
836         *
837         * @override Never
838         *
839         * @return the ToolTip-String of this MenuSheet.
840         */
841        public String getToolTipText() {
842            return m_sToolTip;
843        }
844    
845        /**
846         * Get the default icon of this MenuSheet.
847         *
848         * @override Never
849         *
850         * @return the default icon of this MenuSheet.
851         */
852        public ImageIcon getDefaultIcon() {
853            return (m_aiImages != null) ? (m_aiImages[DEFAULT_IMAGE]) : (null);
854        }
855    
856        /**
857         * Get the selected icon of this MenuSheet.
858         *
859         * @override Never
860         *
861         * @return the pressed icon of this MenuSheet.
862         */
863        public ImageIcon getSelectedIcon() {
864            return (m_aiImages != null) ? (m_aiImages[SELECTED_IMAGE]) : (null);
865        }
866    
867        /**
868         * Get the disabled item of this MenuSheet.
869         *
870         * @override Never
871         *
872         * @return the disabled icon of this MenuSheet.
873         */
874        public ImageIcon getDisabledIcon() {
875            return (m_aiImages != null) ? (m_aiImages[DISABLED_IMAGE]) : (null);
876        }
877    
878        /**
879         * Get the disabled selected item of this MenuSheet.
880         *
881         * @override Never
882         *
883         * @return the disabled selected icon of this MenuSheet.
884         */
885        public ImageIcon getDisabledSelectedIcon() {
886            return (m_aiImages != null) ? (m_aiImages[DISABLED_SELECTED_IMAGE]) : (null);
887        }
888    
889        /**
890         * A tag that will identify the help menu, should this MenuSheet be displayed as a
891         * JMenuBar.
892         */
893        public final static String HELP_MENU_TAG = "__TAG:_HELP_MENU";
894        // A Tag that will identify the Image for the DefaultIcon
895        private final static int DEFAULT_IMAGE = 0;
896        // A Tag that will identify the Image for the SelectedIcon
897        private final static int SELECTED_IMAGE = 1;
898        // A Tag that will identify the Image for the DisabledIcon
899        private final static int DISABLED_IMAGE = 2;
900        // A Tag that will identify the Image for the DisabledSelectedIcon
901        private final static int DISABLED_SELECTED_IMAGE = 3;
902    }