001    /*
002     * This program is free software; you can redistribute it and/or modify
003     * it under the terms of the GNU General Public License as published by
004     * the Free Software Foundation; version 2 of the License.
005     *
006     * This program is distributed in the hope that it will be useful,
007     * but WITHOUT ANY WARRANTY; without even the implied warranty of
008     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
009     * GNU General Public License for more details.
010     *
011     * You should have received a copy of the GNU General Public License along
012     * with this program; if not, write to the Free Software Foundation, Inc.,
013     * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
014     */
015    package org.tastybug.bugwerk.bugtrail.widget.ticket;
016    
017    import java.awt.Dimension;
018    import java.util.Arrays;
019    import java.util.Date;
020    import java.util.Iterator;
021    
022    import javax.swing.JScrollPane;
023    import javax.swing.JTabbedPane;
024    import javax.swing.SwingConstants;
025    import javax.swing.ToolTipManager;
026    
027    import org.apache.commons.logging.Log;
028    import org.apache.commons.logging.LogFactory;
029    import org.tastybug.bugwerk.blueprint.event.IncidentChangeListener;
030    import org.tastybug.bugwerk.blueprint.event.TicketChangeListener;
031    import org.tastybug.bugwerk.blueprint.model.Incident;
032    import org.tastybug.bugwerk.blueprint.model.Ticket;
033    import org.tastybug.bugwerk.bugtrail.widget.incident.IncidentTable;
034    
035    
036    /**
037     * This <code>JTabbedPane</code> displays a ticket.
038     * <br>
039     * One tab is created for the base data of the Ticket, one tab for each contained <code>Incident</code>,
040     * containing an <code>IncidentTable</code>.
041     * <br><br>
042     * 
043     * <hr>
044     * Copyright 2006 Philipp Bartsch.<br>
045     * <a href="http://www.tastybug.com">www.tastybug.com</a><br>
046     * <hr>
047     * Created on Feb 8, 2006<br>
048     * @author Philipp Bartsch, philipp.bartsch{at}tastybug{dot}com</a>
049     */
050    public class TicketDisplayTabPane extends JTabbedPane implements TicketChangeListener, IncidentChangeListener {
051    
052        /**Comment for <code>serialVersionUID</code>*/
053        private static final long serialVersionUID = -6451931754422314904L;
054    
055        /**The commons logger.*/
056        private static final Log logger = LogFactory.getLog(TicketDisplayTabPane.class);  
057        
058    
059        private Ticket      ticket;
060        private Incident[]  incidents;
061        private final Dimension scrollerDimension;
062        
063        /**
064         * Creates the tab pane with TOP tab layout.
065         *
066         * @param _scrollerDimension the dimension of the scroller that holds the tabs content
067         */
068        public TicketDisplayTabPane (Dimension _scrollerDimension) {
069            super(SwingConstants.TOP, JTabbedPane.SCROLL_TAB_LAYOUT);
070            scrollerDimension = _scrollerDimension;
071            ToolTipManager.sharedInstance().registerComponent(this);
072            // erstmal eine null-Sicht
073            setTicket(null);
074        }
075        
076        /**
077         * Sets a new <code>Ticket</code> that is to be displayed. The display unregisters
078         * from the old ticket.
079         * 
080         * @param _ticket the new ticket - can be <code>null</code> to empty the display
081         */
082        public void setTicket (Ticket _ticket) {
083            
084            // beim alten ticket und seinen incidents abmelden
085            if (ticket != null) {
086                ticket.removeTicketChangeListener(this);
087                for (Iterator incidentsIt = Arrays.asList(incidents).iterator(); incidentsIt.hasNext();)
088                    ((Incident)incidentsIt.next()).removeIncidentChangeListener(this);
089            }
090            
091            // neues ticket merken
092            ticket = _ticket;
093            
094            // alle alten tabs entfernen
095            removeAll();
096            
097            // common-tab bauen
098            JScrollPane scroller = new JScrollPane(new TicketTable(ticket));
099            scroller.setPreferredSize(scrollerDimension);        
100            addTab("Common", null, scroller, "bla");
101            
102            // gibts ein neues ticket oder wird die komponente "zurueckgesetzt"?
103            if (ticket == null) {
104                incidents = null;
105            } else {
106                incidents = ticket.getIncidents();
107                ticket.addTicketChangeListener(this);
108                
109                // incident-tabs bauen
110                Incident incident;
111                for (Iterator incidentsIt = Arrays.asList(incidents).iterator(); incidentsIt.hasNext();) {
112                    incident = (Incident)incidentsIt.next();
113                    // gleich mal beim incident als listener anemelden
114                    incident.addIncidentChangeListener(this);
115                    addIncidentTab(incident);
116                }
117            }        
118        }
119        
120        /**
121         * Adds a tab for <code>incident</code>.
122         * 
123         * @param incident the incident
124         */
125        private void addIncidentTab (Incident incident) {
126            
127            IncidentTable incidentTable = new IncidentTable(incident);
128            incidentTable.setName(incident.getOccurrenceDate() + ""); // noch markieren, damit wirs wieder finden
129            JScrollPane scroller = new JScrollPane(incidentTable);
130            scroller.setPreferredSize(scrollerDimension);        
131            
132            addTab(new Date(incident.getOccurrenceDate().longValue()).toString(), null, scroller, "Lists the incident from " + new Date(incident.getOccurrenceDate().longValue()).toString() + ".");
133        }
134        
135        /**
136         * Removes the tab of <code>incident</code>
137         * 
138         * @param incident the incident
139         */
140        private void removeIncidentTab (Incident incident) {
141            // durch alle tabs iterieren und dasjenige loeschen, hinter dem sich der incident verbirgt
142            int incidentIndex = getIndexOfIncident(incident);
143            if (incidentIndex != -1)
144                removeTabAt(incidentIndex);
145            else
146                logger.error("Incident '" + incident.getIncidentSignature() + "' has been removed, but i couldn`t find its tab within me!");
147        }
148        
149        /**
150         * Returns the tab index at which <code>incident</code> is displayed. 
151         * 
152         * @param incident  the incident
153         * @return          the index or -1, if <code>incident</code> was not found
154         */
155        private int getIndexOfIncident (Incident incident) {
156            if (getTabCount() <= 1)
157                return -1;
158            
159            for (int i = 1; i < getTabCount(); i++) {
160                // hier gucken, ob der name der komponente mit dem incident-datum uebereinstimmt
161                if (getComponentAt(i).getName().equals(incident.getOccurrenceDate() + "")) {
162                    return i;
163                }
164            }
165            return -1;
166        }
167    
168        /**
169         * Results in the removal of the corresponding incident tab.
170         *
171         * @see org.tastybug.bugwerk.blueprint.event.TicketChangeListener#performIncidentRemovedEvent(org.tastybug.bugwerk.blueprint.event.TicketChangeListener.IncidentEvent)
172         */ 
173        public void performIncidentRemovedEvent(IncidentEvent event) {
174            // keine ueberpruefung, obs ueberhaupt incidents gibt (incidents.length > 0), da es 
175            // keinen event gibt, wenns keine incidents gibt
176            removeIncidentTab(event.getIncident());
177        }
178    
179        /**
180         * Results in the appendage of a display tab for the new incident 
181         *
182         * @see org.tastybug.bugwerk.blueprint.event.TicketChangeListener#performIncidentAddedEvent(org.tastybug.bugwerk.blueprint.event.TicketChangeListener.IncidentEvent)
183         */
184        public void performIncidentAddedEvent(IncidentEvent event) {
185            addIncidentTab(event.getIncident());
186        }
187    
188        /**
189         * Results in an update of the base data tab.
190         *
191         * @see org.tastybug.bugwerk.blueprint.event.TicketChangeListener#performTicketChangedEvent(org.tastybug.bugwerk.blueprint.event.TicketChangeListener.TicketChangeEvent)
192         */
193        public void performTicketChangedEvent(TicketChangeEvent event) {
194            setTicket(event.getTicket());
195        }
196    
197        /**
198         * Results in an update of the corresponding incident tab.
199         *
200         * @see org.tastybug.bugwerk.blueprint.event.IncidentChangeListener#performIncidentChangedEvent(org.tastybug.bugwerk.blueprint.event.IncidentChangeListener.IncidentChangeEvent)
201         */
202        public void performIncidentChangedEvent(IncidentChangeEvent event) {
203            // alten display loeschen
204            removeIncidentTab(event.getIncident());
205            // neuen display hinzufuegen
206            addIncidentTab(event.getIncident());
207        }
208    
209        /**
210         * Results in an update of the corresponding incident tab.
211         *
212         * @see org.tastybug.bugwerk.blueprint.event.IncidentChangeListener#performAttachementAddedEvent(org.tastybug.bugwerk.blueprint.event.IncidentChangeListener.AttachmentEvent)
213         */
214        public void performAttachementAddedEvent(AttachmentEvent event) {
215            // alten display loeschen
216            removeIncidentTab(event.getIncident());
217            // neuen display hinzufuegen
218            addIncidentTab(event.getIncident());
219        }
220    
221        /**
222         * Results in an update of the corresponding incident tab.
223         *
224         * @see org.tastybug.bugwerk.blueprint.event.IncidentChangeListener#performAttachmentRemovedEvent(org.tastybug.bugwerk.blueprint.event.IncidentChangeListener.AttachmentEvent)
225         */
226        public void performAttachmentRemovedEvent(AttachmentEvent event) {
227            // alten display loeschen
228            removeIncidentTab(event.getIncident());
229            // neuen display hinzufuegen
230            addIncidentTab(event.getIncident());
231        }
232        
233    }