BugDialog.java
001 /*
002  * This class is part of DocWhatsUp, a bug profiling and -reporting lib.
003  
004  * Copyright (C)
005  
006  * This library is free software; you can redistribute it and/or modify it
007  * under the terms of the GNU General Public License as published by the
008  * Free Software Foundation; either version 2 of the License, or (at your
009  * option) any later version.
010  
011  * This program is distributed in the hope that it will be useful, but
012  * WITHOUT ANY WARRANTY; without even the implied warranty of
013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
014  * Public License for more details.
015  *  
016  * You should have received a copy of the GNU General Public License along
017  * with this program; if not, write to the Free Software Foundation, Inc.,
018  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019  
020  * EXTENSION:
021  * Linking DocWhatsUp statically or dynamically with other modules is making a
022  * combined work based on DocWhatsUp.  Thus, the terms and conditions of the 
023  * GNU General Public License cover the whole combination.
024  *
025  * As a special exception, the copyright holder of DocWhatsUp give you
026  * permission to link DocWhatsUp with independent modules that communicate with
027  * DocWhatsUp solely through the DocWhatsUp.java interface, regardless of the 
028  * license terms of these independent modules, and to copy and distribute the
029  * resulting combined work under terms of your choice, provided that
030  * every copy of the combined work is accompanied by a complete copy of
031  * the source code of DocWhatsUp (the version of DocWhatsUp used to produce the
032  * combined work), being distributed under the terms of the GNU General
033  * Public License plus this exception.  An independent module is a module
034  * which is not derived from or based on DocWhatsUp.
035 
036  * Note that people who make modified versions of DocWhatsUp are not obligated
037  * to grant this special exception for their modified versions; it is
038  * their choice whether to do so.  The GNU General Public License gives
039  * permission to release a modified version without this exception; this
040  * exception also makes it possible to release a modified version which
041  * carries forward this exception.
042  
043  * Author: Philipp Bartsch; codeshaker@gmx.net
044  */
045 
046 package org.shaker.dwu;
047 
048 import java.awt.BorderLayout;
049 import java.awt.Frame;
050 import java.awt.GridLayout;
051 import java.awt.event.ActionEvent;
052 import java.awt.event.ActionListener;
053 
054 import javax.swing.BorderFactory;
055 import javax.swing.JButton;
056 import javax.swing.JDialog;
057 import javax.swing.JEditorPane;
058 import javax.swing.JLabel;
059 import javax.swing.JPanel;
060 import javax.swing.JScrollPane;
061 import javax.swing.JTabbedPane;
062 import javax.swing.JTextArea;
063 
064 /**
065  * This class provides a message dialog, that informs the user about the occured
066  * error. 
067  * The BugProfile can be submitted and previewed via a seperate tab.
068  
069  @author <A HREF="mailto:codeshaker@gmx.net">
070  *            Philipp Bartsch (codeshaker@gmx.net)</A>
071  *            <A HREF="../../../../gpl.txt">GPL License</A>
072  */
073 final class         BugDialog     
074       extends         JDialog 
075       implements     ActionListener {
076 
077 
078     /**ActionCommand: Dispose this dialog*/
079     private   static  final String      DISPOSE        = "CMD_DISPOSE";
080     /**ActionCommand: Start the configuration wizard*/
081     private   static  final String      SHOW_WIZARD    = "SHOW_WIZARD";
082     /**ActionCommand: Send reports*/
083     private   static  final String      SEND_NOW      = "SEND_NOW";
084     /**ActionCommand: Send later (just dispose)*/
085     private   static  final String      SEND_LATER  = "SEND_LATER";        
086     /**ActionCommand: show message preview*/
087     private   static  final String      PREVIEW        = "PREVIEW";        
088     /**A reference to the settings*/
089     private   static  final Settings     SETTINGS    = DocWhatsUp.SETTINGS;
090     
091     /**The statusbar*/
092     private final JLabel       statusLabel  = new JLabel(" ");
093     /**Dialog`s tabbedpane. Holds the message, stacktrace and reportpanel*/
094     private final JTabbedPane tabPane        = new JTabbedPane();
095     /**Send button*/
096     private final JButton       sendBtn        = GUIFactory.button("send_btn"
097                                                                this, 
098                                                                SEND_NOW, 
099                                                                "send.png");
100     /**Send later button*/                                                               
101     private final JButton       sendLaterBtn = GUIFactory.button("sendlater_btn"
102                                                                this, 
103                                                                SEND_LATER, 
104                                                                "cancel.png");
105     /**Send later button*/                                                               
106     private final JButton       previewBtn   = GUIFactory.button("preview_btn"
107                                                                this, 
108                                                                PREVIEW, 
109                                                                "preview.png");
110     /**Configuration wizard starter*/                                                           
111     private final JButton       wizardBtn    = GUIFactory.button("startwiz_btn"
112                                                                this, 
113                                                                SHOW_WIZARD, 
114                                                                "wizard.png");
115     /**The user comment TextArea*/                                                               
116     private final JTextArea   commentsArea = GUIFactory.textArea(""
117                                                                  true,
118                                                                  false);
119     /**The mail preview TextArea*/                                                               
120     private final JEditorPane previewPane  = GUIFactory.editorPane();
121     
122     /**The Profile of the occured bug*/    
123     private final BugProfile  bugProfile;
124 
125     /**
126      * Constructor for a BugProfile driven dialog.
127      *
128      @param profile    a bugprofile that has never been submitted
129      @param parent    the parental frame
130      @param error     error description.
131      @param solution    an optional solution/hint regarding this error
132      @see #BugDialog(Frame,String,String) for a simple, BugProfile-less
133      *                                         messagedialog.
134      */
135     BugDialog (final BugProfile profile,
136                final Frame      parent,                
137                final String     error,
138                final String     hint) {
139     
140         super(parent, 
141               ToolBox.localize("dwu_error_title"));
142         bugProfile = profile;        
143         tabPane.setFont(GUIFactory.ARIAL_10P);
144         initUserInfoPanel(error,
145                           hint);        
146         //
147         initPreviewPane();
148                 
149         final JPanel contentPane = new JPanel (new BorderLayout(0,0));
150         // if there are no available configurations (custom or default), don`t
151         // show a report tab but a small configure me button on the bottom left
152         if (Settings.isConfigurated()) {
153             if (SETTINGS.isMailingEnabled())
154                 initReportPane(false);
155             contentPane.add(tabPane, 
156                             BorderLayout.CENTER);
157             contentPane.add(initControlPane(false)
158                             BorderLayout.SOUTH);            
159         else {
160             contentPane.add(tabPane, 
161                             BorderLayout.CENTER);
162             contentPane.add(initControlPane(true)
163                             BorderLayout.SOUTH);
164         }
165         
166         //        
167         setContentPane(contentPane);
168         setModal(true);
169         setResizable(true);
170         ToolBox.setSmartSize(this,
171                              400,
172                              410);
173         show();        
174     }
175     
176     /**
177      * Constructor for a simple info dialog. It contains a problem description
178      * and a optional solution.
179      @see #BugDialog(BugProfile,Frame,String,String) for a BugProfile driven
180      * dialog
181      
182      @param parent        parental frame
183      @param error         the error description
184      @param solution        a optional solution
185      */
186     BugDialog (final Frame   parent,
187                 final String  error,
188                 final String  solution) {
189         
190         super(parent, 
191               ToolBox.localize("dwu_msg_title"));
192         bugProfile = null;
193         tabPane.setFont(GUIFactory.ARIAL_9B);
194         initUserInfoPanel(error,
195                          solution);                    
196         final JPanel contentPane = new JPanel (new BorderLayout(0,0));   
197         contentPane.add(tabPane, 
198                         BorderLayout.CENTER);
199         contentPane.add(initControlPane(false)
200                         BorderLayout.SOUTH);
201         setContentPane(contentPane);
202         setModal(true);
203         setSize(300380);
204         setResizable(true);
205         ToolBox.setSmartSize(this,
206                              400,
207                              410);
208         show();
209     }
210     
211     /**
212      * Inits the general description pane (what happened, what can be done..).
213      *     
214      @param  error            a string representation of the error
215      @param  solution            a optional hint
216      */
217     private void initUserInfoPanel (final String error,
218                                     final String solution) {
219         final JPanel master = new JPanel (new BorderLayout(0,0));
220         final JPanel panel1 = new JPanel (new GridLayout((solution.length() == 0
221                                                           1
222                                                           2),0,3,3));
223         final JPanel panel2 = new JPanel (new GridLayout((solution.length() == 0
224                                                           1
225                                                           2),0,3,3));        
226 
227         panel1.add(GUIFactory.label("error",
228                                     false,
229                                     true));        
230         panel2.add(GUIFactory.scrollWrap(GUIFactory.textArea(error,
231                                                              false,
232                                                              true),
233                                          GUIFactory.EMPTY2))
234         if (solution != null && solution.length() 0) {
235             panel1.add(GUIFactory.label("tip",
236                                         false,
237                                         true));        
238             panel2.add(GUIFactory.scrollWrap(GUIFactory.textArea(solution,
239                                                                  false,
240                                                                  true),
241                                              GUIFactory.EMPTY2));             
242         }
243         
244         
245         master.add(panel1, BorderLayout.WEST);
246         master.add(panel2, BorderLayout.CENTER);                                          
247         master.setBorder(BorderFactory.createEmptyBorder(10,5,10,5));
248         
249         //    
250         tabPane.addTab(ToolBox.localize("message_tab"),
251                        GUIFactory.getIcon("message.png"),
252                        master,
253                        ToolBox.localize("message_tt"));        
254     }
255        
256     /**
257      * Inits the shortened report panel. It contains a restart-wizard button, a
258      * comment textarea and sendbuttons. This pane gets created, when the wizard
259      * has created a properly working dwu setting. 
260      
261      @param setShown    preselect the bugreport pane 
262      */
263      private void initReportPane (final boolean setShown) {
264          final JPanel masterPanel     = new JPanel (new BorderLayout(11));    
265         final JPanel reconfigPanel    = new JPanel (new BorderLayout(00));
266          final JPanel commentsPanel    = new JPanel (new BorderLayout(00));
267         final JPanel sendPanel      = new JPanel (new BorderLayout(00));
268         
269         wizardBtn.setForeground(GUIFactory.BLACK);
270         reconfigPanel.setBorder(GUIFactory.titledEBorder("brd_reconfig"));
271         reconfigPanel.add(wizardBtn, 
272                           BorderLayout.CENTER);
273         masterPanel.add(reconfigPanel, 
274                         BorderLayout.NORTH);
275         
276         commentsPanel.setBorder(GUIFactory.titledEBorder("brd_comment"));
277         commentsPanel.add(GUIFactory.textArea("cmnt_help"
278                                               false,
279                                               true),
280                           BorderLayout.NORTH);
281         commentsPanel.add(new JScrollPane(commentsArea)
282                           BorderLayout.CENTER);
283         masterPanel.add(commentsPanel, 
284                         BorderLayout.CENTER);
285 
286         //send panel
287         sendPanel.setBorder(GUIFactory.titledEBorder("brd_send"));
288 
289         sendPanel.add(GUIFactory.textArea("send_help"
290                                           false,
291                                           true),
292                       BorderLayout.NORTH);
293         sendPanel.add(sendBtn, 
294                       BorderLayout.CENTER);
295         //
296         final JPanel subPanel = new JPanel (new GridLayout(0,2));
297         subPanel.add(sendLaterBtn);
298         subPanel.add(previewBtn);
299         sendPanel.add(subPanel, 
300                       BorderLayout.SOUTH);
301         //
302         masterPanel.add(sendPanel,
303                         BorderLayout.SOUTH);
304         // make it visible yet        
305         statusLabel.setBorder(GUIFactory.LOW);
306         wizardBtn.setText(ToolBox.localize("startwiz_btn"));
307         
308         tabPane.addTab(ToolBox.localize("reporterror_tab"),
309                        GUIFactory.getIcon("send.png"),
310                        masterPanel,
311                        ToolBox.localize("reporterror_tt"));
312         tabPane.setForegroundAt(tabPane.getTabCount() 1,
313                                 GUIFactory.RED);
314         if (setShown)
315             tabPane.setSelectedIndex(tabPane.getTabCount()-1);
316      }
317      
318     /**
319      * Inits the report previewer pane by including the mailbody.
320      */    
321     private void initPreviewPane () {
322         previewPane.setBackground(GUIFactory.WHITE);
323         previewPane.setEditable(false);
324         previewPane.setContentType(bugProfile.getMimeType());
325         previewPane.setText(bugProfile.getMailBody());
326         previewPane.setCaretPosition(0);            
327     }
328     
329     /**
330      * Inits the controlpane. The controlpane delivers a close button and, 
331      * if the wizard has never been started, a wizardstarter.
332      
333      @param showErrorButton    indicates wheter to show the wizardstarter
334      *                             button
335      @return JPanel            the control container panel
336      */    
337     private JPanel initControlPane (final boolean showErrorButton) {
338         final JPanel controlPanel = new JPanel (new BorderLayout(1,1));
339 
340         statusLabel.setFont(GUIFactory.ARIAL_10P);
341         statusLabel.setIconTextGap(5);        
342         controlPanel.add(statusLabel, 
343                          BorderLayout.CENTER);
344         
345         final JButton closeButton = GUIFactory.button("close_btn",
346                                                          this,
347                                                       DISPOSE,
348                                                       "close.png");
349         controlPanel.add(closeButton, 
350                          BorderLayout.WEST);
351         
352         if (showErrorButton) {
353             wizardBtn.setForeground(GUIFactory.RED);
354             wizardBtn.setText(ToolBox.localize("reporterror_tab"));
355             controlPanel.add(wizardBtn, 
356                                BorderLayout.EAST);
357         }
358         
359         return controlPanel;
360     }
361 
362     /**
363      * Resets the embedded status panel.
364      
365      @param dictKey     the message dictionary key
366      @param isError   is true, the label has a red foreground
367      */
368     private void resetStatus (final String   dictKey,
369                               final boolean  isError) {
370         // set failure message text
371         if (dictKey.length() 0) {
372             statusLabel.setForeground((isError
373                                        ? GUIFactory.RED
374                                        : GUIFactory.BLUE));
375             statusLabel.setText(ToolBox.localize(dictKey));
376             statusLabel.setIcon(GUIFactory.getIcon("message.png"));
377         // no message, reset label
378         else {    
379             statusLabel.setText (" ");
380             statusLabel.setIcon(null);
381         }        
382     }    
383 
384     /**
385      * Creates and shows the configuration wizard.
386      
387      @see org.shaker.dwu.SetupDialog for a description of the wizard
388      */
389     private void showWizard () {
390         final SetupDialog wizard = new SetupDialog (this);
391         wizard.show();
392         // make sure that the wizard has been successfully executed 
393         if (Settings.isConfigurated() && tabPane.getTabCount() == 1)
394             initReportPane(true);               
395             
396     }
397     
398     /**
399      * This method toggles the visibility of the ReportMail preview tab.
400      */
401     private void togglePreview () {
402         // there`s already a preview tab, so remove it
403         if (tabPane.getTabCount() == 3) {
404             tabPane.removeTabAt(2);        
405             previewBtn.setBorder(GUIFactory.ETCHED);
406         // no preview yet, add it
407         else {
408             tabPane.addTab(ToolBox.localize("preview_tab")
409                            GUIFactory.getIcon("preview.png"),
410                            GUIFactory.scrollWrap(previewPane,
411                                                  GUIFactory.LOW),                           
412                            ToolBox.localize("preview_tt"));    
413             previewBtn.setBorder(GUIFactory.LOW);
414             tabPane.setSelectedIndex(2);                                               
415         }        
416     }
417         
418     /**
419      * This method handles occuring events, like button usage etc.
420      *
421      @param ae    an ActionEvent
422      */
423     public void actionPerformed (final ActionEvent ae) {
424         final String command = ae.getActionCommand();
425         if (command.equals(DISPOSE)) {
426             dispose();
427         else if (command.equals(SHOW_WIZARD)) {
428             showWizard();
429         else if (command.equals(PREVIEW)) {
430             togglePreview();
431         else if (command.equals(SEND_LATER)) {            
432             if (tabPane.getTabCount() == 3)        
433                 tabPane.removeTabAt(2);        
434             tabPane.removeTabAt(1);
435             
436             bugProfile.setProperty(BugProfile.USER_COMMENT,
437                                    commentsArea.getText());    
438             tabPane.setSelectedIndex(0);                                                           
439         else if (command.equals(SEND_NOW)) {
440             try {
441                 if (commentsArea.getText().length() 0)
442                     bugProfile.setProperty(BugProfile.USER_COMMENT,
443                                            commentsArea.getText());
444                 if (!SETTINGS.hasPassword()
445                     && SETTINGS.containsKey("mail.pop")
446                     && SETTINGS.getProperty("mail.pop").length() 0) {
447                     //ask for password
448                     AuthDialog dialog = new AuthDialog(this);
449                     String pass;
450                     if ((pass = dialog.getPassword()) == null)
451                         return;
452                     else
453                         SETTINGS.setProperty("mail.pass"
454                                              pass);
455                 }
456                 final String state = MailEngine.submit(this,
457                                                        DocWhatsUp.getQueuedBugs());
458                 // submit successful
459                 if (state.length() == 0) {
460                     resetStatus(state,
461                                 false);
462                     tabPane.removeTabAt(1);
463                     if (tabPane.getTabCount() == 2)
464                         tabPane.removeTabAt(1);
465                     tabPane.setSelectedIndex(0);
466                 //submit failed
467                 else {                
468                     resetStatus(state,
469                                 true);
470                     //forget given password
471                     SETTINGS.removePassword();
472                 }                        
473             catch (Exception e) {
474                 ToolBox.logException(e);
475                 Settings.killPhysically();
476             }
477         }
478     }    
479 }