package org.docear.plugin.services.features.documentretrieval.view; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.NoSuchElementException; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JTabbedPane; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; import org.docear.plugin.core.DocearController; import org.docear.plugin.core.event.DocearEvent; import org.docear.plugin.core.event.DocearEventType; import org.docear.plugin.core.io.IOTools; import org.docear.plugin.services.ServiceController; import org.docear.plugin.services.features.documentretrieval.DocumentRetrievalController; import org.docear.plugin.services.features.documentretrieval.model.DocumentEntry; import org.docear.plugin.services.features.documentretrieval.model.DocumentModelNode; import org.docear.plugin.services.features.documentretrieval.model.DocumentsModel; import org.docear.plugin.services.features.documentretrieval.recommendations.RecommendationsController; import org.docear.plugin.services.features.user.action.DocearUserServicesAction; import org.freeplane.core.ui.components.UITools; import org.freeplane.core.util.LogUtils; import org.freeplane.core.util.TextUtils; import org.freeplane.features.mode.Controller; import org.freeplane.plugin.workspace.WorkspaceController; import com.jgoodies.forms.factories.FormFactory; import com.jgoodies.forms.layout.ColumnSpec; import com.jgoodies.forms.layout.FormLayout; import com.jgoodies.forms.layout.RowSpec; public abstract class DocumentView extends JPanel { private static final long serialVersionUID = 1L; protected static JTabbedPane tabPane; private String evaluationLabel = ""; private int recSetId = 0; public DocumentView(final DocumentsModel model) { this(); setModel(model); } protected DocumentView() { Container cont = Controller.getCurrentController().getViewController().getContentPane(); this.setLayout(new BorderLayout()); updateTitle(); this.setBackground(Color.WHITE); this.setBorder(new LineBorder(Color.LIGHT_GRAY, 1)); if(tabPane == null) { tabPane = findTabbedPane(cont); } cont.remove(tabPane); cont.add(this, BorderLayout.CENTER, 0); } protected abstract Container getNewRecommandationContainerComponent(String title); protected abstract Container getNewEmptyContainerComponent(); protected abstract void addComponendAfterDocumentList(Container documentList); public void close() throws NoSuchElementException { Container cont = Controller.getCurrentController().getViewController().getContentPane(); if (DocumentRetrievalController.getView() == null) { return; } cont.remove(DocumentRetrievalController.getView()); cont.add(tabPane, BorderLayout.CENTER, 0); DocumentRetrievalController.destroyView(); ((JComponent) cont).revalidate(); UITools.getFrame().repaint(); } // public abstract void close(); protected static JTabbedPane findTabbedPane(Container cont) throws NoSuchElementException { JTabbedPane tabPane = null; for(Component comp : cont.getComponents()) { if(comp instanceof JTabbedPane) { tabPane = (JTabbedPane) comp; break; } } if(tabPane == null) { LogUtils.warn("Exception in "+RecommendationsController.class+".getOrCreateRecommendationView(): could not find tabbed pane"); throw new NoSuchElementException("could not find tabbed pane"); } return tabPane; } public void setModel(DocumentsModel model) { removeAll(); layoutModel(model); updateTitle(); fireModelChanged(null, model); SwingUtilities.invokeLater(new Runnable() { public void run() { revalidate(); } }); } public void updateTitle() { String label = ServiceController.getCurrentUser().getName(); if(label != null && label.trim().length() > 0) { setName(TextUtils.format("recommendations.map.label.forUser", label)); } else { setName(TextUtils.getText("recommendations.map.label.anonymous")); } } private void layoutModel(DocumentsModel model) { evaluationLabel = model.getEvaluationLabel(); recSetId = model.getSetId(); DocumentModelNode node = model.getRootNode(); layoutModel(node, null); } private void layoutModel(DocumentModelNode node, Container parent) { if (node != null) { Object obj = node.getUserObject(); Container container = parent; if(node instanceof DocumentModelNode.RecommendationContainerNode) { container = getNewRecommandationContainerComponent(obj.toString()); if(parent == null) { //this.add(container); } else { parent.add(container); } } else if(node instanceof DocumentModelNode.UntitledRecommendationContainerNode) { container = getNewEmptyContainerComponent(); if(parent == null) { this.add(container); } else { parent.add(container); } } else { if(container == null) { container = getNewEmptyContainerComponent(); //this.add(container); } if (node instanceof DocumentModelNode.RecommendationEntryNode) { JComponent comp = getRecommendationComponent((DocumentEntry) obj); container.add(comp); } else if(node instanceof DocumentModelNode.NoRecommendationsNode) { container.add(getNoRecommendationsComponent((String) obj)); } else if(node instanceof DocumentModelNode.NoServiceNode) { container.add(getNoServiceComponent()); } else { container.add(new JLabel(obj.toString())); } } if (node.getChildCount() > 0) { for (DocumentModelNode child : node.getChildren()) { layoutModel(child, container); } addComponendAfterDocumentList(container); } } } private JComponent getRecommendationComponent(final DocumentEntry recommendation) { DocumentEntryComponent comp = new DocumentEntryComponent(recommendation); comp.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { URL page = recommendation.getClickUrl(); try { page = redirectRecommendationLink(recommendation, page); } catch (Exception ex) { //click didn't work LogUtils.info(ex.getMessage()); } if(e.getID() == DocumentEntryComponent.OPEN_RECOMMENDATION) { try { Controller.getCurrentController().getViewController().openDocument(page); } catch (Exception ex) { LogUtils.warn("could not open link to (" + recommendation.getLink() + ")", ex); } } else if(e.getID() == DocumentEntryComponent.IMPORT_RECOMMENDATION) { //WORKSPACE - DOCEAR todo: change EventType -> recommendations are project independent, so there is no specific library DocearController.getController().getEventQueue().dispatchEvent(new DocearEvent(page, null, DocearEventType.IMPORT_TO_LIBRARY, recommendation.getTitle())); } } private URL redirectRecommendationLink(final DocumentEntry recommendation, URL page) throws IOException, MalformedURLException { URLConnection connection; connection = recommendation.getClickUrl().openConnection(); if(connection instanceof HttpURLConnection) { HttpURLConnection hconn = (HttpURLConnection) connection; hconn.setInstanceFollowRedirects(false); String accessToken = ServiceController.getCurrentUser().getAccessToken(); hconn.addRequestProperty("accessToken", accessToken); int response = hconn.getResponseCode(); boolean redirect = (response >= 300 && response <= 399); /* * In the case of a redirect, we want to actually change the URL * that was input to the new, redirected URL */ if (redirect) { String loc = connection.getHeaderField("Location"); if (loc.startsWith("http", 0)) { page = new URL(loc); } else { page = new URL(page, loc); } } else { if(response == 200) { String content = IOTools.getStringFromStream(connection.getInputStream(), "UTF-8"); String searchPattern = "<meta http-equiv=\"REFRESH\" content=\"0;url="; int pos = content.indexOf(searchPattern); if(pos >= 0) { String loc = content.substring(pos+searchPattern.length()); loc = loc.substring(0,loc.indexOf("\"")); if (loc.startsWith("http", 0)) { page = new URL(loc); } else { page = new URL(page, loc); } } } } } return page; } }); return comp; } protected Component getStarBar() { return new StarPanel(evaluationLabel, recSetId); } protected Component getNewButtonBar(boolean showRefreshButton) { JPanel panel = new JPanel(new LayoutManager() { public void removeLayoutComponent(Component comp) { } public Dimension preferredLayoutSize(Container parent) { int count = parent.getComponentCount(); for(Component comp : parent.getComponents()) { Dimension comDim = comp.getPreferredSize(); if(comDim != null) { return new Dimension((parent.getInsets().left+parent.getInsets().right+comDim.width)*count, parent.getInsets().top+parent.getInsets().bottom+comDim.height); } } return null; } public Dimension minimumLayoutSize(Container parent) { for(Component comp : parent.getComponents()) { int count = parent.getComponentCount(); Dimension comDim = comp.getMinimumSize(); if(comDim != null) { return new Dimension((parent.getInsets().left+parent.getInsets().right+comDim.width)*count, parent.getInsets().top+parent.getInsets().bottom+comDim.height); } } return null; } public void layoutContainer(Container parent) { int right = parent.getWidth()-parent.getInsets().right; int top = parent.getInsets().top; int count = parent.getComponentCount(); for(Component comp : parent.getComponents()) { comp.setSize(comp.getPreferredSize()); int x = right-comp.getWidth()*count; comp.setLocation(x,top); count--; } } public void addLayoutComponent(String name, Component comp) { } }); panel.setBackground(Color.white); panel.setBorder(new EmptyBorder(5, 5, 0, 5)); if (showRefreshButton) { JButton refreshButton = new JButton(new ImageIcon(DocumentEntryComponent.class.getResource("/icons/view-refresh-7_32x32.png"))); refreshButton.setMinimumSize(new Dimension(50, 50)); refreshButton.setPreferredSize(new Dimension(50, 50)); refreshButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { DocumentRetrievalController.getController().refreshDocuments(); } }); refreshButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); refreshButton.setToolTipText(TextUtils.getText("recommendations.refresh.title")); panel.add(refreshButton); } JButton closeButton = new JButton(new ImageIcon(DocumentEntryComponent.class.getResource("/icons/window-close-2_32x32.png"))); closeButton.setMinimumSize(new Dimension(50, 50)); closeButton.setPreferredSize(new Dimension(50, 50)); closeButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { SwingUtilities.invokeLater(new Runnable() { public void run() { DocumentRetrievalController.getController().closeDocumentView(); } }); } }); closeButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); closeButton.setToolTipText(TextUtils.getText("recommendations.close.title")); panel.add(closeButton); return panel; } private Component getNoRecommendationsComponent(String message) { return new NoRecommendations(message); } private Component getNoServiceComponent() { return new NoService(); } // private Component getProgressBarNode(int min, int max) { // return new ProgressBarComponent(min, max); // } protected class NoRecommendations extends JLabel implements NodeModelItem { private static final long serialVersionUID = 1L; private final String text; public NoRecommendations(String message) { this.text = message; this.setText(this.getText()); this.setHorizontalAlignment(CENTER); this.setVerticalAlignment(CENTER); this.setBorder(new EmptyBorder(30, 10, 30, 10)); } public String getText() { return this.text; } public String toString() { return getText(); } } protected class ProgressBarComponent extends JPanel implements NodeModelItem { private static final long serialVersionUID = 1L; public ProgressBarComponent(int min, int max) { this.setLayout(new BorderLayout()); JProgressBar bar = new JProgressBar(); if(max < min) { bar.setIndeterminate(true); } else { bar.setMinimum(min); bar.setMaximum(max); } this.add(bar, BorderLayout.CENTER); } public String getText() { return "waiting ..."; } } protected class NoService extends JPanel implements NodeModelItem { private static final long serialVersionUID = 1L; private final String text; public NoService() { this.text = TextUtils.getText("recommendations.error.no_service"); setLayout(new FormLayout(new ColumnSpec[] { FormFactory.RELATED_GAP_COLSPEC, FormFactory.DEFAULT_COLSPEC, FormFactory.RELATED_GAP_COLSPEC, ColumnSpec.decode("default:grow"),}, new RowSpec[] { FormFactory.RELATED_GAP_ROWSPEC, RowSpec.decode("fill:default"), FormFactory.RELATED_GAP_ROWSPEC, FormFactory.DEFAULT_ROWSPEC, FormFactory.RELATED_GAP_ROWSPEC, RowSpec.decode("default:grow"),})); JLabel lblText = new JLabel(text); add(lblText, "2, 2, 3, 1"); JButton btnNewButton = new JButton(TextUtils.getText("recommendations.error.no_service.button")); add(btnNewButton, "2, 4"); btnNewButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { WorkspaceController.getAction(DocearUserServicesAction.KEY).actionPerformed(null); } }); } public String getText() { return this.text; } public String toString() { return getText(); } } interface NodeModelItem { public String getText(); } protected final class ListLayoutManager implements LayoutManager { public ListLayoutManager() { } public void removeLayoutComponent(Component comp) { } public Dimension preferredLayoutSize(Container parent) { if(parent.getComponentCount() > 0) { Dimension compPref = parent.getComponent(0).getPreferredSize(); // for(Component comp : parent.getComponents()) { // // } Insets insets = new Insets(0, 0, 0, 0); if(parent instanceof JComponent) { insets = ((JComponent) parent).getInsets(); } return new Dimension(compPref.width+insets.left+insets.right, compPref.height*parent.getComponentCount()+insets.top+insets.bottom); } return new Dimension(); } public Dimension minimumLayoutSize(Container parent) { return parent.getMinimumSize(); } public void layoutContainer(Container parent) { int i = parent.getComponentCount()-1; if(i < 0) { return; } Insets insets = new Insets(0, 0, parent.getHeight(), parent.getWidth()); if(parent instanceof JComponent) { insets = ((JComponent) parent).getInsets(); } int width = parent.getWidth()-insets.left-insets.right; int height = parent.getComponent(0).getPreferredSize().height; int x = insets.left; if(parent.getHeight() < ((height*(i+1)) + insets.top)) { height = (parent.getHeight()-insets.top-insets.bottom)/(i+1); } if(height < 20) { height = 20; } for(; i >= 0; i-- ) { Component comp = parent.getComponent(i); int y = i*height + insets.top; setPreferredSize(new Dimension(width, height)); comp.setBounds(x, y, width, height); } } public void addLayoutComponent(String name, Component comp) { } } private void fireModelChanged(DocumentsModel oldModel, DocumentsModel newModel) { DocumentViewChangedEvent event = new DocumentViewChangedEvent(this, DocumentViewChangedEvent.MODEL_CHANGED_TYPE, oldModel, newModel); synchronized (listenerList) { DocumentViewListener[] listeners = listenerList.getListeners(DocumentViewListener.class); for (DocumentViewListener listener : listeners) { listener.viewChanged(event); } } } public void addViewChangeListener(DocumentViewListener listener) { synchronized (listenerList) { listenerList.add(DocumentViewListener.class, listener); } } }