001    /*
002     *  Copyright (C) 2003 Adam Olsen
003     *  This program is free software; you can redistribute it and/or modify
004     *  it under the terms of the GNU General Public License as published by
005     *  the Free Software Foundation; either version 1, or (at your option)
006     *  any later version.
007     *  This program is distributed in the hope that it will be useful,
008     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
009     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
010     *  GNU General Public License for more details.
011     *  You should have received a copy of the GNU General Public License
012     *  along with this program; if not, write to the Free Software
013     *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
014     */
015    package com.valhalla.jbother;
016    
017    import java.awt.*;
018    import java.awt.event.*;
019    import java.io.*;
020    import java.text.*;
021    import java.util.*;
022    import javax.swing.text.*;
023    
024    import javax.swing.*;
025    
026    import com.valhalla.gui.CopyPasteContextMenu;
027    import com.valhalla.gui.DialogTracker;
028    import com.valhalla.gui.Standard;
029    import com.valhalla.settings.Settings;
030    
031    /**
032     *  Allows the user to view the log of any contact Displays a dialog that allows
033     *  you to view the log of any Jabber user you have contacted. You can view the
034     *  log by date and time
035     *
036     *@author     Adam Olsen
037     *@created    April 20, 2005
038     *@version    1.0
039     */
040    public class LogViewerDialog extends JFrame {
041        private ResourceBundle resources = ResourceBundle.getBundle(
042                "JBotherBundle", Locale.getDefault());
043    
044        private String logDirectory;
045    
046        private JList logList = new JList();
047    
048        private LogListModel model = new LogListModel();
049    
050        private JPanel container = new JPanel();
051    
052        private JPanel rightPanel = new JPanel();
053    
054        private ConversationArea logView;
055    
056        private File logDirectoryFile;
057    
058        private JButton closeButton = new JButton(resources.getString("closeButton")), clearButton = new JButton(resources.getString("clearButton"));
059    
060        private JSplitPane splitPane;
061    
062        private File fileList[];
063    
064        private LogViewerCaller caller;
065    
066        private JPopupMenu popMenu = new JPopupMenu();
067    
068        private JMenuItem delete = new JMenuItem(resources.getString("deleteButton"));
069    
070        private JScrollPane scrollPane;
071    
072        private JButton searchButton = new JButton(resources.getString("search"));
073    
074        private JTextField searchField = new JTextField();
075    
076    
077        /**
078         *  Default constructor Can be passed a ChatRoomPanel, HeadlineWindow, and a
079         *  ChatPanel as the caller
080         *
081         *@param  caller     the object that called this dialog
082         *@param  entryName  the user who's log is to be viewed
083         */
084        public LogViewerDialog(LogViewerCaller caller, String entryName) {
085            super("Log Viewer (" + entryName + ")");
086            setTitle(resources.getString("logViewer") + " (" + entryName + ")");
087    
088            setIconImage(Standard.getImage("frameicon.png"));
089            logList.setModel(model);
090    
091            if (caller != null) {
092                this.caller = caller;
093            }
094    
095            logDirectory = JBother.profileDir + File.separatorChar + "logs"
096                     + File.separatorChar
097                     + entryName.replaceAll("@", "_at_").replaceAll("\\/", "-");
098    
099            logDirectoryFile = new File(logDirectory);
100    
101            container.setLayout(new BoxLayout(container, BoxLayout.X_AXIS));
102            setContentPane(container);
103    
104            logView = new ConversationArea();
105            logView.setEmoticons(false);
106            popMenu.add(delete);
107    
108            logView.setPreferredSize(new Dimension(500, 350));
109            CopyPasteContextMenu.registerComponent(logView.getTextPane());
110    
111            rightPanel.setLayout(new BorderLayout());
112    
113            JPanel topPanel = new JPanel(new BorderLayout(2, 2));
114            topPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
115            topPanel.add(searchField, BorderLayout.CENTER);
116            topPanel.add(searchButton, BorderLayout.EAST);
117            rightPanel.add(topPanel, BorderLayout.NORTH);
118    
119    
120            rightPanel.add(logView, BorderLayout.CENTER);
121    
122            JPanel buttonPanel = new JPanel();
123            buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
124            buttonPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 0));
125            buttonPanel.add(Box.createHorizontalGlue());
126            buttonPanel.add(clearButton);
127            buttonPanel.add(closeButton);
128            rightPanel.add(buttonPanel, BorderLayout.SOUTH);
129    
130            SearchActionListener searchListener = new SearchActionListener();
131            searchField.addActionListener(searchListener);
132            searchButton.addActionListener(searchListener);
133    
134            loadLogFiles();
135            scrollPane = new JScrollPane(logList);
136            splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, scrollPane,
137                    rightPanel);
138            splitPane.setDividerLocation(150);
139            splitPane.setOneTouchExpandable(true);
140    
141            container.add(splitPane);
142            container.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
143    
144            setUpListeners();
145    
146            pack();
147            Standard.cascadePlacement(this);
148            DialogTracker.addDialog(this, false, true);
149    
150            if (logList.getModel().getSize() >= 1) {
151                setVisible(true);
152            } else {
153                Standard.warningMessage(null, resources.getString("logViewer"),
154                        resources.getString("noLogData"));
155                DialogTracker.removeDialog(this);
156            }
157        }
158    
159        /**
160         *  Returns a formatted date string that is used in many places in JBother
161         *
162         *@return    the formatted date and time
163         */
164        public static String getDateName() {
165            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
166            String date = formatter.format(new Date());
167            return date;
168        }
169    
170    
171        /**
172         *  Sets up the listeners for the various events
173         */
174        private void setUpListeners() {
175            setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
176    
177            closeButton.addActionListener(
178                new ActionListener() {
179                    public void actionPerformed(ActionEvent e) {
180                        DialogTracker.removeDialog(LogViewerDialog.this);
181                    }
182                });
183    
184            clearButton.addActionListener(
185                new ActionListener() {
186                    public void actionPerformed(ActionEvent e) {
187                        clearHandler();
188                    }
189                });
190    
191            delete.addActionListener(
192                new ActionListener() {
193                    public void actionPerformed(ActionEvent e) {
194                        int result = JOptionPane.showConfirmDialog(null, resources.getString("sureDeleteItem"), resources.getString("logViewer"), JOptionPane.YES_NO_OPTION);
195    
196                        if (result == JOptionPane.YES_OPTION) {
197                            File file = (File) logList.getSelectedValue();
198                            if (file != null) {
199                                com.valhalla.Logger.debug("deleting " + file.getPath());
200                                if (file.delete()) {
201                                    model.removeLog(file);
202                                }
203                            }
204                        }
205                    }
206                });
207    
208            logList.addMouseListener(new LogListMouseListener());
209    
210            logList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
211            logList.setCellRenderer(new LogListRenderer());
212        }
213    
214    
215        /**
216         *  Listens for someone to click on an entry date and populates the textArea
217         *  with the log data
218         *
219         *@author     Adam Olsen
220         *@created    April 20, 2005
221         *@version    1.0
222         */
223        private class LogListMouseListener extends MouseAdapter {
224            /**
225             *  Description of the Method
226             *
227             *@param  e  Description of the Parameter
228             */
229            public void mousePressed(MouseEvent e) {
230                checkPop(e);
231            }
232    
233    
234            /**
235             *  Description of the Method
236             *
237             *@param  e  Description of the Parameter
238             */
239            public void mouseReleased(MouseEvent e) {
240                checkPop(e);
241            }
242    
243    
244            /**
245             *  Description of the Method
246             *
247             *@param  e  Description of the Parameter
248             */
249            public void mouseClicked(MouseEvent e) {
250                File file = (File) logList.getSelectedValue();
251                logView.setText("");
252                logView.append(getFileContents(file));
253    
254                new java.util.Timer().schedule(new Scroller(logView.getTextPane()), 100);
255    
256                validate();
257                checkPop(e);
258    
259            }
260    
261            /**
262             *  Description of the Method
263             *
264             *@param  e  Description of the Parameter
265             */
266            private void checkPop(MouseEvent e) {
267                if (e.isPopupTrigger()) {
268                    int index = logList.locationToIndex(new Point(e.getX(), e.getY()));
269                    logList.setSelectedIndex(index);
270    
271                    if (logList.getSelectedValue() != null) {
272                        popMenu.show(logList, e.getX(), e.getY());
273                    }
274                }
275            }
276        }
277    
278        class Scroller extends TimerTask
279        {
280            JTextPane pane;
281            public Scroller(JTextPane pane) { this.pane = pane; }
282            public void run()
283            {
284                SwingUtilities.invokeLater(new Runnable()
285                {
286                    public void run()
287                    {
288                        pane.setCaretPosition(0);
289                    }
290                });
291    
292            }
293        }
294    
295    
296        /**
297         *  Clears all log data (deletes all log entries)
298         */
299        private void clearHandler() {
300            int result = JOptionPane.showConfirmDialog(null, resources.getString("sureClearLog"), resources.getString("clearLogs"),
301                    JOptionPane.YES_NO_OPTION);
302    
303            if (result == 0) {
304                if (caller != null) {
305                    caller.closeLog();
306                    caller.startLog();
307                }
308    
309                for (int i = 0; i < fileList.length; i++) {
310                    fileList[i].delete();
311                }
312                DialogTracker.removeDialog(this);
313            }
314        }
315    
316    
317        /**
318         *  Returns a list of all available log entries
319         *
320         */
321        private void loadLogFiles() {
322            if (!logDirectoryFile.isDirectory()) {
323                return;
324            }
325    
326            // opens the directory and lists the files
327            fileList = logDirectoryFile.listFiles(new LogFileFilter());
328    
329            logView.setText("");
330            Arrays.sort(fileList, Collections.reverseOrder());
331    
332            if (!searchField.getText().equals("")) {
333                ArrayList list = new ArrayList();
334                for (int i = 0; i < fileList.length; i++) {
335                    if (fileContainsText(fileList[i], searchField.getText())) {
336                        list.add(fileList[i]);
337                    }
338                }
339    
340                fileList = (File[]) list.toArray(new File[list.size()]);
341            }
342    
343            if (fileList.length == 0) {
344                logView.setText("No logs found");
345                model.setLogs(fileList);
346                validate();
347                return;
348            }
349    
350            logView.append(getFileContents(fileList[0]));
351    
352            new java.util.Timer().schedule(new Scroller(logView.getTextPane()), 100);
353    
354            logList.setSelectedIndex(0);
355            model.setLogs(fileList);
356            validate();
357        }
358    
359    
360        /**
361         *  Description of the Class
362         *
363         *@author     synic
364         *@created    April 20, 2005
365         */
366        class SearchActionListener implements ActionListener {
367            /**
368             *  Description of the Method
369             *
370             *@param  e  Description of the Parameter
371             */
372            public void actionPerformed(ActionEvent e) {
373                loadLogFiles();
374            }
375        }
376    
377        private String getFileContents(File file)
378        {
379            String html = "";
380            try {
381                FileInputStream in = new FileInputStream(file);
382                byte[] contents = new byte[in.available()];
383                in.read(contents);
384                in.close();
385                String logEnc =
386                        Settings.getInstance().getProperty("keepLogsEncoding");
387                try {
388                    if (logEnc != null) {
389                        html = new String(contents, logEnc);
390                    } else {
391                        html = new String(contents);
392                    }
393                } catch (UnsupportedEncodingException ex) {
394                } catch (NullPointerException ex) {
395                }
396    
397            } catch (FileNotFoundException fnfe) {
398            } catch (IOException ioe) {
399            }
400    
401            return html;
402        }
403    
404        /**
405         *  Description of the Method
406         *
407         *@param  file  Description of the Parameter
408         *@param  text  Description of the Parameter
409         *@return       Description of the Return Value
410         */
411        private boolean fileContainsText(File file, String text) {
412            text = text.toLowerCase();
413            String html = getFileContents(file);
414            html = html.toLowerCase();
415            if (html.indexOf(text) > -1) {
416                return true;
417            } else {
418                return false;
419            }
420        }
421    
422    
423        /**
424         *  The model that represents the list of buddies in the room
425         *
426         *@author     Adam Olsen
427         *@created    April 20, 2005
428         *@version    1.0
429         */
430        class LogListModel extends AbstractListModel {
431            private Vector logs = new Vector();
432    
433    
434            /**
435             *  Sets the logs attribute of the LogListModel object
436             *
437             *@param  list  The new logs value
438             */
439            public void setLogs(File[] list) {
440                logs.clear();
441                for (int i = 0; i < list.length; i++) {
442                    logs.add(list[i]);
443                }
444    
445                fireChanged();
446            }
447    
448    
449            /**
450             *@return    the number of elements in the list
451             */
452            public int getSize() {
453                return logs.size();
454            }
455    
456    
457            /**
458             *@param  row  the element you want to get
459             *@return      the Object at <tt>row</tt>
460             */
461            public Object getElementAt(int row) {
462                return logs.get(row);
463            }
464    
465    
466            /**
467             *@param  log    The feature to be added to the Log attribute
468             */
469            public void addLog(File log) {
470                logs.add(log);
471                fireChanged();
472            }
473    
474    
475            /**
476             *  Removes a buddy from the list
477             *
478             *@param  log  Description of the Parameter
479             */
480            public void removeLog(File log) {
481                logs.remove(log);
482                fireChanged();
483            }
484    
485    
486    
487            /**
488             *  Fires a change of the list
489             */
490            private synchronized void fireChanged() {
491                SwingUtilities.invokeLater(
492                    new Runnable() {
493                        public void run() {
494                            fireContentsChanged(LogListModel.this, 0, logs.size());
495                            logList.validate();
496                        }
497                    });
498            }
499        }
500    }
501    
502    /**
503     *  Displays each log entry as a date and time
504     *
505     *@author     Adam Olsen
506     *@created    April 20, 2005
507     *@version    1.0
508     */
509    
510    class LogListRenderer extends JLabel implements ListCellRenderer {
511    
512    
513        /**
514         *  Sets the background to opaque
515         */
516        public LogListRenderer() {
517            setOpaque(true);
518        }
519    
520    
521        /**
522         *  Renders each entry
523         *
524         *@param  list          Description of the Parameter
525         *@param  value         Description of the Parameter
526         *@param  index         Description of the Parameter
527         *@param  isSelected    Description of the Parameter
528         *@param  cellHasFocus  Description of the Parameter
529         *@return               The listCellRendererComponent value
530         */
531        public Component getListCellRendererComponent(JList list, Object value,
532                int index, boolean isSelected, boolean cellHasFocus) {
533            File file = (File) value;
534    
535            String dateString[] = file.toString().replaceAll(
536                    ".*\\" + File.separatorChar, "")
537                    .replaceAll("\\.log", "").split("\\-");
538    
539            try {
540                setText(dateString[1] + "-" + dateString[2] + "-" + dateString[0]
541                         + " " + dateString[3] + ":" + dateString[4] + ":"
542                         + dateString[5]);
543            } catch (Exception e) {
544                setText("Invalid Date");
545            }
546    
547            setBackground(isSelected ? list.getSelectionBackground() : list.getBackground());
548            setForeground(isSelected ? list.getSelectionForeground() : list.getForeground());
549            list.validate();
550    
551            return this;
552        }
553    }
554    
555    /**
556     *  A filter to only accept html files
557     *
558     *@author     Adam Olsen
559     *@created    April 20, 2005
560     *@version    1.0
561     */
562    
563    class LogFileFilter implements FileFilter {
564    
565        // accept html files
566    
567        /**
568         *  Description of the Method
569         *
570         *@param  f  Description of the Parameter
571         *@return    Description of the Return Value
572         */
573        public boolean accept(File f) {
574            if (f.isDirectory()) {
575                return false;
576            }
577    
578            if (f.length() <= 0.0) {
579                return false;
580            }
581    
582            String extension = Utils.getExtension(f);
583    
584            if (extension != null) {
585                if (extension.equals(Utils.log)) {
586                    return true;
587                } else {
588                    return false;
589                }
590            }
591    
592            return false;
593        }
594    }