/**
* NanoDoA - File based document archive
*
* Copyright (C) 2011-2012 Christian Packenius, christian.packenius@googlemail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.chris_soft.nanodoa.gui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Image;
import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
import org.jdesktop.swingx.JXMultiSplitPane;
import org.jdesktop.swingx.MultiSplitLayout;
import de.chris_soft.nanodoa.God;
import de.chris_soft.nanodoa.gui.tree.ArchiveTree;
import de.chris_soft.nanodoa.gui.tree.DocumentTree;
import de.chris_soft.nanodoa.gui.tree.LabelTree;
import de.chris_soft.nanodoa.gui.tree.SpecialTree;
import de.chris_soft.nanodoa.gui.tree.path.DocumentPath;
import de.chris_soft.nanodoa.gui.tree.path.LabelPath;
import de.chris_soft.nanodoa.gui.tree.path.SearchPath;
import de.chris_soft.utilities.LogUtils;
import de.chris_soft.utilities.pdf.PdfPageRenderUtility;
import de.chris_soft.utilities.swing.SwingUtils;
import de.chris_soft.utilities.swing.labellist.LabelList;
import de.chris_soft.utilities.swing.labellist.LabelListListener;
import de.chris_soft.utilities.swing.labellist.LabelStore;
import de.chris_soft.utilities.swing.labellist.LabeledContainer;
import de.chris_soft.utilities.swing.pdf.PdfThumbnailZapper;
/**
* Window with application GUI.
* @author Christian Packenius.
*/
public class AppWindow implements LabelListListener, LabeledContainer {
/**
* Swing window.
*/
public final JFrame frame;
PdfThumbnailZapper pdfThumbnailZapper;
LabelList labelList;
private volatile long currentDocumentID = 0;
private volatile AppStatusBar statusbar = null;
/**
* Constructor.
*/
public AppWindow() {
frame = createFrame();
buildContentPanel(frame.getContentPane());
fillLabelTree();
fillSpecialTree();
}
private JFrame createFrame() {
JFrame frame = new JFrame("NanoDoA - (w) by Christian Packenius, 2011-2012");
frame.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
frame.setSize(800, 400);
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
frame.setJMenuBar(new AppMenuBar());
ArrayList<Image> icons = getFrameIcons();
frame.setIconImages(icons);
return frame;
}
private ArrayList<Image> getFrameIcons() {
ArrayList<Image> icons = new ArrayList<Image>();
icons.add(new ImageIcon("icons/icon48.png").getImage());
icons.add(new ImageIcon("icons/icon64.png").getImage());
return icons;
}
private void fillLabelTree() {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
List<Long> labels = God.archive.getAllLabels();
for (long labelID : labels) {
LabelPath labelPath = new LabelPath(labelID);
God.labelTree.addNode(null, labelPath);
List<Long> docs = God.archive.db.getDocumentsFromLabel(labelID);
for (long docID : docs) {
DocumentPath docPath = new DocumentPath(docID);
God.labelTree.addNode(labelPath, docPath);
}
}
} catch (SQLException exception) {
// Ignore?
}
}
};
Thread thread = new Thread(runnable, "Label tree filling thread");
thread.start();
}
private void fillSpecialTree() {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
List<Long> docs = God.archive.db.getDocumentsWithoutLabel();
for (long documentID : docs) {
God.specialsTree.addToUnlabeledDocuments(documentID);
}
} catch (SQLException exception) {
// Ignore?
}
}
};
Thread thread = new Thread(runnable, "Special tree filling thread");
thread.start();
}
private void buildContentPanel(Container cp) {
JXMultiSplitPane msp = new JXMultiSplitPane();
String layoutDef =
"(ROW (COLUMN (LEAF name=tree1 weight=0.34) (LEAF name=tree2 weight=0.33) (LEAF name=tree3 weight=0.33) weight=0.1 ) (LEAF name=view weight=0.8) (LEAF name=labels weight=0.1) )";
MultiSplitLayout.Node modelRoot = MultiSplitLayout.parseModel(layoutDef);
msp.getMultiSplitLayout().setModel(modelRoot);
msp.add(createTreePanel(God.archiveTree = new ArchiveTree()), "tree1");
msp.add(createTreePanel(God.labelTree = new LabelTree()), "tree2");
msp.add(createTreePanel(God.specialsTree = new SpecialTree()), "tree3");
pdfThumbnailZapper = new PdfThumbnailZapper();
msp.add(pdfThumbnailZapper.getComponent(), "view");
JComponent labelComponent = null;
try {
LabelStore labelStore = God.archive;
labelList = new LabelList(God.centralLabelLister, labelStore, this);
labelComponent = labelList.getComponent();
} catch (Exception exception) {
LogUtils.log(exception);
labelComponent = new JLabel("Exception in label reading!");
}
msp.add(labelComponent, "labels");
msp.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
cp.add(msp, BorderLayout.CENTER);
cp.add(statusbar = new AppStatusBar(), BorderLayout.SOUTH);
}
private Component createTreePanel(DocumentTree tree) {
JPanel panel = new JPanel(new GridLayout(1, 0));
panel.add(tree);
return panel;
}
/**
* Show a document from a search result list.
* @param searchTerm Search items.
* @param documentID Document to show.
*/
public void showSearchedDocument(String searchTerm, long documentID) {
God.specialsTree.setCurrentNode(new SearchPath(searchTerm));
God.specialsTree.setCurrentChild(new DocumentPath(documentID));
}
/**
* @see de.chris_soft.utilities.swing.labellist.LabelListListener#labelSet(long, java.lang.Object)
*/
@Override
public void labelSet(long labelID, Object docID) {
try {
God.archive.db.addLabelToDocument((Long) docID, labelID);
setDocumentLabel((Long) docID, labelID);
} catch (SQLException exception) {
// Ignore.
}
labelList.refresh();
}
private void setDocumentLabel(long documentID, long labelID) {
LabelPath labelPath = new LabelPath(labelID);
List<Object> children = God.labelTree.getChildUserObjects(labelPath);
DocumentPath docPath = new DocumentPath(documentID);
if (!children.contains(docPath)) {
God.labelTree.addNode(labelPath, docPath);
}
}
/**
* @see de.chris_soft.utilities.swing.labellist.LabelListListener#labelUnset(long, java.lang.Object)
*/
@Override
public void labelUnset(long labelID, Object docID) {
try {
God.archive.db.removeLabelFromDocument((Long) docID, labelID);
unsetDocumentLabel((Long) docID, labelID);
} catch (SQLException exception) {
LogUtils.log(exception);
}
labelList.refresh();
}
private void unsetDocumentLabel(long documentID, long labelID) {
LabelPath labelPath = new LabelPath(labelID);
if (God.labelTree.hasNode(labelPath)) {
List<Object> children = God.labelTree.getChildUserObjects(labelPath);
for (Object oChild : children) {
DocumentPath child = (DocumentPath) oChild;
if (child.docID == documentID) {
God.labelTree.removeUserObjectPath(new Object[] {God.labelTree.rootObject, labelPath, child});
break;
}
}
}
}
/**
* @see de.chris_soft.utilities.swing.labellist.LabelListListener#labelDeleted(long)
*/
@Override
public void labelDeleted(long labelID) {
LabelPath labelPath = new LabelPath(labelID);
God.labelTree.removeNode(labelPath);
labelList.refresh();
}
/**
* @see de.chris_soft.utilities.swing.labellist.LabelListListener#labelAdded(long)
*/
@Override
public void labelAdded(long labelID) {
LabelPath labelPath = new LabelPath(labelID);
if (!God.labelTree.hasNode(labelPath)) {
God.labelTree.addNode(null, labelPath);
}
labelList.refresh();
}
/**
* @see de.chris_soft.utilities.swing.labellist.LabeledContainer#getObjectToBeLabeled()
*/
@Override
public Long getObjectToBeLabeled() {
return currentDocumentID == 0 ? null : currentDocumentID;
}
/**
* Show another document.
* @param docID ID of the document to show.
*/
public void setCurrentDocument(long docID) {
try {
if (currentDocumentID != docID) {
currentDocumentID = docID;
File pdfFile = God.archive.getDocumentFileFromDocID(docID);
pdfThumbnailZapper.set(new PdfPageRenderUtility(pdfFile));
refreshLabelList();
God.archiveTree.selectDocumentInArchiveTree(docID);
}
} catch (Exception exception) {
LogUtils.log(exception);
SwingUtils.showError(frame, "Couldn't load document!");
}
}
/**
* Returns the status bar of this window.
* @return Status bar.
*/
public AppStatusBar getStatusBar() {
return statusbar;
}
/**
* Refresh content of the label list.
*/
public void refreshLabelList() {
labelList.refresh();
}
/**
* @see de.chris_soft.utilities.swing.labellist.LabelListListener#labelRenamed(long, java.lang.String)
*/
@Override
public void labelRenamed(long labelID, String newLabelName) {
labelList.refresh();
}
}