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 }