search rework

This commit is contained in:
bancika
2016-10-24 17:56:13 +02:00
parent b529adefcb
commit be334165ba
11 changed files with 731 additions and 621 deletions
@@ -6,12 +6,12 @@ import java.util.List;
import com.diyfever.httpproxy.ParamName;
/***
* Interface of DIYLC PHP server located at www.diy-fever.com/diylc/api
* Interface of DIYLC PHP server located at www.diy-fever.com/diylc/api/v1
*
* @author bancika
*
*/
public interface ServiceAPI {
public interface IServiceAPI {
public static final String URL_KEY = "serviceUrl";
@@ -14,7 +14,7 @@ import java.util.List;
import org.apache.log4j.Logger;
import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.plugins.cloud.model.ProjectEntity;
import org.diylc.plugins.cloud.model.ServiceAPI;
import org.diylc.plugins.cloud.model.IServiceAPI;
import org.diylc.plugins.cloud.model.UserEntity;
import com.diyfever.httpproxy.PhpFlatProxy;
@@ -30,7 +30,7 @@ public class CloudPresenter {
private final static Logger LOG = Logger.getLogger(CloudPresenter.class);
private static final Object SUCCESS = "Success";
private ServiceAPI service;
private IServiceAPI service;
private String serviceUrl;
private String machineId;
private String[] categories;
@@ -41,9 +41,9 @@ public class CloudPresenter {
public CloudPresenter(CloudListener listener) {
serviceUrl =
ConfigurationManager.getInstance().readString(ServiceAPI.URL_KEY, "http://www.diy-fever.com/diylc/api/v1");
ConfigurationManager.getInstance().readString(IServiceAPI.URL_KEY, "http://www.diy-fever.com/diylc/api/v1");
ProxyFactory factory = new ProxyFactory(new PhpFlatProxy());
service = factory.createProxy(ServiceAPI.class, serviceUrl);
service = factory.createProxy(IServiceAPI.class, serviceUrl);
if (service == null)
LOG.warn("Service proxy not created!");
this.listener = listener;
@@ -223,7 +223,8 @@ public class CloudPresenter {
throw new CloudException(res.toString());
if (res instanceof List<?>) {
List<ProjectEntity> projects = (List<ProjectEntity>) res;
// Download thumbnails and replace urls with local paths
LOG.info("Received " + projects.size() + " results");
// Download thumbnails and replace urls with local paths to speed up loading in the main thread
for (int i = 0; i < projects.size(); i++) {
String url = projects.get(i).getThumbnailUrl();
URL website = new URL(url);
@@ -231,7 +232,8 @@ public class CloudPresenter {
File temp = File.createTempFile("thumbnail", ".png");
FileOutputStream fos = new FileOutputStream(temp);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
projects.get(i).setThumbnailUrl(temp.getAbsolutePath());
projects.get(i).setThumbnailUrl(temp.getAbsolutePath());
fos.close();
}
return projects;
}
@@ -69,4 +69,9 @@ public interface ISwingUI extends IView {
* @return {@link JFrame} that can be used to reference secondary dialogs and frames
*/
JFrame getOwnerFrame();
/**
*
*/
void bringToFocus();
}
@@ -376,4 +376,9 @@ public class MainFrame extends JFrame implements ISwingUI {
}
}
@Override
public void bringToFocus() {
this.requestFocus();
}
}
@@ -22,10 +22,10 @@ import org.diylc.swing.ISwingUI;
import org.diylc.swing.gui.DialogFactory;
import org.diylc.swing.gui.DummyView;
import org.diylc.swing.plugins.cloud.view.ChangePasswordDialog;
import org.diylc.swing.plugins.cloud.view.CloudBrowserFrame;
import org.diylc.swing.plugins.cloud.view.LoginDialog;
import org.diylc.swing.plugins.cloud.view.UploadDialog;
import org.diylc.swing.plugins.cloud.view.UserEditDialog;
import org.diylc.swing.plugins.cloud.view.browser.CloudBrowserFrame;
import org.diylc.swing.plugins.file.FileFilterEnum;
import org.diylc.swingframework.ButtonDialog;
import org.diylc.swingframework.ProgressDialog;
@@ -113,7 +113,7 @@ public class CloudPlugIn implements IPlugIn, CloudListener {
public CloudBrowserFrame getCloudBrowser() {
if (cloudBrowser == null) {
cloudBrowser = new CloudBrowserFrame(swingUI.getOwnerFrame(), plugInPort, cloudPresenter);
cloudBrowser = new CloudBrowserFrame(swingUI, plugInPort, cloudPresenter);
}
return cloudBrowser;
}
@@ -1,609 +0,0 @@
package org.diylc.swing.plugins.cloud.view;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.apache.log4j.Logger;
import org.diylc.common.IPlugInPort;
import org.diylc.common.ITask;
import org.diylc.core.IView;
import org.diylc.images.IconLoader;
import org.diylc.plugins.cloud.model.ProjectEntity;
import org.diylc.plugins.cloud.presenter.CloudException;
import org.diylc.plugins.cloud.presenter.CloudPresenter;
import org.diylc.swing.ISwingUI;
import org.diylc.swing.gui.DialogFactory;
import org.diylc.swing.plugins.file.FileFilterEnum;
public class CloudBrowserFrame extends JFrame {
private static final long serialVersionUID = 1L;
private static final Logger LOG = Logger.getLogger(CloudBrowserFrame.class);
private JPanel mainPanel;
private JTabbedPane tabbedPane;
private JPanel dashboardPanel;
private JPanel browsePanel;
private JPanel searchPanel;
private JTextField searchField;
private JComboBox categoryBox;
private JComboBox sortBox;
private JButton goButton;
private JScrollPane resultsScrollPane;
private JPanel resultsPanel;
private IPlugInPort plugInPort;
private CloudPresenter cloudPresenter;
private JPanel navigationPanel;
private JButton prevPageButton;
private JButton nextPageButton;
private JLabel pageLabel;
private List<ProjectEntity> currentResults;
// search criteria
private String searchFor;
private String category;
private String sort;
private int pageNumber;
private int itemsPerPage = 10;
public CloudBrowserFrame(JFrame owner, IPlugInPort plugInPort, CloudPresenter cloudPresenter) {
super("DIY Cloud Browser");
this.setIconImage(IconLoader.Cloud.getImage());
this.setPreferredSize(new Dimension(800, 600));
this.plugInPort = plugInPort;
this.cloudPresenter = cloudPresenter;
setContentPane(getMainPanel());
this.pack();
this.setLocationRelativeTo(owner);
this.setGlassPane(new CloudGlassPane());
JRootPane rootPane = SwingUtilities.getRootPane(getGoButton());
rootPane.setDefaultButton(getGoButton());
}
public JPanel getMainPanel() {
if (mainPanel == null) {
mainPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1;
gbc.weighty = 1;
mainPanel.add(getTabbedPane(), gbc);
}
return mainPanel;
}
private JTabbedPane getTabbedPane() {
if (tabbedPane == null) {
tabbedPane = new JTabbedPane();
tabbedPane.addTab("Dashboard", IconLoader.Dashboard.getIcon(), getDashboardPanel());
tabbedPane.addTab("Search For Projects", IconLoader.Find.getIcon(), getBrowsePanel());
tabbedPane.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
if (getTabbedPane().getSelectedIndex() == 1)
getSearchField().requestFocus();
}
});
}
return tabbedPane;
}
private JPanel getDashboardPanel() {
if (dashboardPanel == null) {
dashboardPanel = new JPanel();
}
return dashboardPanel;
}
private JPanel getBrowsePanel() {
if (browsePanel == null) {
browsePanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
browsePanel.setBackground(Color.white);
gbc.anchor = GridBagConstraints.NORTH;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
browsePanel.add(getSearchPanel(), gbc);
// gbc.gridy = 1;
// gbc.fill = GridBagConstraints.HORIZONTAL;
// browsePanel.add(new JSeparator(), gbc);
gbc.gridy = 1;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
browsePanel.add(getResultsScrollPane(), gbc);
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridx = 0;
gbc.gridy++;
gbc.fill = GridBagConstraints.BOTH;
gbc.weighty = 0;
gbc.gridwidth = 3;
browsePanel.add(getNavigationPanel(), gbc);
}
return browsePanel;
}
private JPanel getSearchPanel() {
if (searchPanel == null) {
searchPanel = new JPanel(new GridBagLayout());
searchPanel.setBackground(Color.white);
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.LINE_START;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 0;
searchPanel.add(new JLabel("Search For:"), gbc);
gbc.gridx = 1;
gbc.weightx = 1;
searchPanel.add(getSearchField(), gbc);
gbc.gridx = 2;
gbc.weightx = 0;
searchPanel.add(new JLabel("Filter By Category:"), gbc);
gbc.gridx = 3;
gbc.weightx = 0.3;
searchPanel.add(getCategoryBox(), gbc);
gbc.gridx = 4;
gbc.weightx = 0;
searchPanel.add(new JLabel("Sort By:"), gbc);
gbc.gridx = 5;
searchPanel.add(getSortBox(), gbc);
gbc.gridx = 6;
searchPanel.add(getGoButton(), gbc);
}
return searchPanel;
}
private JTextField getSearchField() {
if (searchField == null) {
searchField = new JTextField(60);
}
return searchField;
}
private JComboBox getCategoryBox() {
if (categoryBox == null) {
try {
categoryBox = new JComboBox(cloudPresenter.getCategories());
} catch (CloudException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return categoryBox;
}
private JComboBox getSortBox() {
if (sortBox == null) {
try {
sortBox = new JComboBox(cloudPresenter.getSortings());
} catch (CloudException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return sortBox;
}
private JScrollPane getResultsScrollPane() {
if (resultsScrollPane == null) {
resultsScrollPane = new JScrollPane(getResultsPanel());
resultsScrollPane.getVerticalScrollBar().setUnitIncrement(16);
resultsScrollPane.setBorder(null);
}
return resultsScrollPane;
}
private JPanel getResultsPanel() {
if (resultsPanel == null) {
resultsPanel = new JPanel(new GridBagLayout());
resultsPanel.setBackground(Color.white);
}
return resultsPanel;
}
public JButton getGoButton() {
if (goButton == null) {
goButton = new JButton("Go", IconLoader.DataFind.getIcon());
goButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
setPageNumber(1);
CloudBrowserFrame.this.searchFor = getSearchField().getText();
CloudBrowserFrame.this.category =
getCategoryBox().getSelectedItem() == null ? "" : getCategoryBox().getSelectedItem().toString();
CloudBrowserFrame.this.sort =
getSortBox().getSelectedItem() == null ? "" : getSortBox().getSelectedItem().toString();
search();
}
});
}
return goButton;
}
private void search() {
executeBackgroundTask(new ITask<List<ProjectEntity>>() {
@Override
public List<ProjectEntity> doInBackground() throws Exception {
return cloudPresenter.search(searchFor, category, sort, pageNumber, itemsPerPage);
}
@Override
public void failed(Exception e) {
showMessage("Search failed! Detailed message is in the logs. Please report to the author.", "Search Failed",
IView.ERROR_MESSAGE);
}
@Override
public void complete(List<ProjectEntity> result) {
CloudBrowserFrame.this.currentResults = result;
getResultsPanel().removeAll();
int count = 0;
for (Iterator<ProjectEntity> i = result.iterator(); i.hasNext();) {
ProjectEntity project = i.next();
addProjectToDisplay(project, count++);
}
if (count == 0) {
showNoMatches();
count++;
}
// addNavigationPanel(count);
}
});
}
private void showNoMatches() {
JLabel label = new JLabel("<html><font size='5' color='red'>No projects match the search criteria.</font></html>");
label.setHorizontalAlignment(SwingConstants.CENTER);
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1;
gbc.weighty = Integer.MAX_VALUE;
getResultsPanel().add(label, gbc);
}
private void addProjectToDisplay(final ProjectEntity project, int location) {
JLabel thumbnailLabel = new JLabel(downloadImage(project.getThumbnailUrl()));
JLabel nameLabel = new JLabel("<html><b>" + project.getName() + "</b></html>");
nameLabel.setFont(nameLabel.getFont().deriveFont(12f));
JLabel descriptionLabel = new JLabel("<html>" + project.getDescription() + "</html>");
JLabel categoryLabel = new JLabel("<html>Category: <b>" + project.getCategory() + "</b></html>");
JLabel authorLabel = new JLabel("<html>Author: <b>" + project.getOwner() + "</b></html>");
JLabel updatedLabel = new JLabel("<html>Last updated: <b>" + project.getUpdated() + "</b></html>");
JButton downloadButton = new JButton(IconLoader.CloudDownload.getIcon());
downloadButton.setBorderPainted(false);
// downloadButton.setFocusPainted(false);
downloadButton.setContentAreaFilled(false);
downloadButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
downloadButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
final File file =
DialogFactory.getInstance().showSaveDialog(CloudBrowserFrame.this, FileFilterEnum.DIY.getFilter(),
new File(project.getName() + ".diy"), FileFilterEnum.DIY.getExtensions()[0], null);
if (file != null) {
CloudBrowserFrame.this.executeBackgroundTask(new ITask<Void>() {
@Override
public Void doInBackground() throws Exception {
LOG.debug("Downloading project to to " + file.getAbsolutePath());
URL website = new URL(project.getDownloadUrl());
ReadableByteChannel rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(file.getAbsolutePath());
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
return null;
}
@Override
public void complete(Void result) {
if (CloudBrowserFrame.this.showConfirmDialog("Project downloaded to " + file.getAbsolutePath()
+ ".\nDo you want to open it?", "Cloud", ISwingUI.YES_NO_OPTION, ISwingUI.INFORMATION_MESSAGE) == IView.YES_OPTION) {
if (!plugInPort.allowFileAction()) {
return;
}
CloudBrowserFrame.this.executeBackgroundTask(new ITask<Void>() {
@Override
public Void doInBackground() throws Exception {
LOG.debug("Opening from " + file.getAbsolutePath());
plugInPort.loadProjectFromFile(file.getAbsolutePath());
return null;
}
@Override
public void complete(Void result) {}
@Override
public void failed(Exception e) {
CloudBrowserFrame.this.showMessage("Could not open file. Detailed message is in the logs", "Error",
ISwingUI.ERROR_MESSAGE);
}
});
}
}
@Override
public void failed(Exception e) {
CloudBrowserFrame.this.showMessage("Could not save to file. Detailed message is in the logs", "Error",
ISwingUI.ERROR_MESSAGE);
}
});
}
}
});
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridx = 0;
gbc.gridy = location * 6;
gbc.fill = GridBagConstraints.NONE;
gbc.gridheight = 5;
gbc.weightx = 0;
getResultsPanel().add(thumbnailLabel, gbc);
gbc.gridheight = 1;
gbc.gridx = 1;
gbc.weightx = 1;
gbc.insets = new Insets(2, 6, 2, 2);
getResultsPanel().add(nameLabel, gbc);
//
// gbc.gridx = 2;
// gbc.anchor = GridBagConstraints.NORTHEAST;
// gbc.insets = new Insets(2, 2, 2, 8);
// getResultsPanel().add(authorLabel, gbc);
gbc.gridy++;
gbc.gridx = 1;
gbc.weighty = 1;
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.insets = new Insets(2, 6, 2, 2);
getResultsPanel().add(descriptionLabel, gbc);
gbc.gridy++;
gbc.gridx = 1;
gbc.weighty = 0;
getResultsPanel().add(categoryLabel, gbc);
gbc.gridx = 2;
gbc.gridheight = 3;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.anchor = GridBagConstraints.SOUTHEAST;
getResultsPanel().add(downloadButton, gbc);
gbc.gridy++;
gbc.gridx = 1;
gbc.gridheight = 1;
gbc.insets = new Insets(2, 6, 2, 2);
gbc.anchor = GridBagConstraints.NORTHWEST;
getResultsPanel().add(authorLabel, gbc);
gbc.gridy++;
getResultsPanel().add(updatedLabel, gbc);
gbc.gridx = 0;
gbc.gridy++;
gbc.gridwidth = 3;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
gbc.insets = new Insets(2, 2, 2, 2);
getResultsPanel().add(new JSeparator(), gbc);
}
private JPanel getNavigationPanel() {
if (navigationPanel == null) {
navigationPanel = new JPanel(new GridBagLayout());
navigationPanel.setBackground(Color.white);
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.SOUTHWEST;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridx = 0;
gbc.weightx = 0;
gbc.fill = GridBagConstraints.NONE;
navigationPanel.add(getPrevPageButton(), gbc);
gbc.gridx++;
gbc.weightx = 1;
gbc.anchor = GridBagConstraints.LINE_START;
gbc.fill = GridBagConstraints.HORIZONTAL;
navigationPanel.add(getPageLabel(), gbc);
gbc.gridx++;
gbc.weightx = 0;
gbc.anchor = GridBagConstraints.SOUTHWEST;
gbc.fill = GridBagConstraints.NONE;
navigationPanel.add(getNextPageButton(), gbc);
}
return navigationPanel;
}
private JButton getPrevPageButton() {
if (prevPageButton == null) {
prevPageButton = new JButton(IconLoader.NavLeftBlue.getIcon());
prevPageButton.setBorderPainted(false);
prevPageButton.setContentAreaFilled(false);
prevPageButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
prevPageButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (CloudBrowserFrame.this.pageNumber > 1) {
setPageNumber(CloudBrowserFrame.this.pageNumber - 1);
CloudBrowserFrame.this.search();
}
}
});
}
return prevPageButton;
}
private JButton getNextPageButton() {
if (nextPageButton == null) {
nextPageButton = new JButton(IconLoader.NavRightBlue.getIcon());
nextPageButton.setBorderPainted(false);
nextPageButton.setContentAreaFilled(false);
nextPageButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
nextPageButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (CloudBrowserFrame.this.currentResults != null && !CloudBrowserFrame.this.currentResults.isEmpty()) {
setPageNumber(CloudBrowserFrame.this.pageNumber + 1);
CloudBrowserFrame.this.search();
}
}
});
}
return nextPageButton;
}
private void setPageNumber(int pageNumber) {
this.pageNumber = pageNumber;
getPageLabel().setText("Page " + pageNumber);
}
private JLabel getPageLabel() {
if (pageLabel == null) {
pageLabel = new JLabel();
pageLabel.setFont(pageLabel.getFont().deriveFont(12f));
pageLabel.setHorizontalAlignment(SwingConstants.CENTER);
}
return pageLabel;
}
// private void addNavigationPanel(int location) {
// GridBagConstraints gbc = new GridBagConstraints();
// gbc.anchor = GridBagConstraints.NORTHWEST;
// gbc.insets = new Insets(2, 2, 2, 2);
// gbc.gridx = 0;
// gbc.gridy = location * 6;
// gbc.fill = GridBagConstraints.BOTH;
// gbc.weighty = 100;
// gbc.gridwidth = 3;
// getResultsPanel().add(getNavigationPanel(), gbc);
// }
public <T extends Object> void executeBackgroundTask(final ITask<T> task) {
getGlassPane().setVisible(true);
SwingWorker<T, Void> worker = new SwingWorker<T, Void>() {
@Override
protected T doInBackground() throws Exception {
return task.doInBackground();
}
@Override
protected void done() {
getGlassPane().setVisible(false);
try {
T result = get();
task.complete(result);
} catch (ExecutionException e) {
LOG.error("Background task execution failed", e);
task.failed(e);
} catch (InterruptedException e) {
LOG.error("Background task execution interrupted", e);
task.failed(e);
}
}
};
worker.execute();
}
public void showMessage(String message, String title, int messageType) {
JOptionPane.showMessageDialog(this, message, title, messageType);
}
public int showConfirmDialog(String message, String title, int optionType, int messageType) {
return JOptionPane.showConfirmDialog(this, message, title, optionType, messageType);
}
private Icon downloadImage(String imageFile) {
// Image image = null;
// try {
// URL url = new URL(imageUrl);
// image = ImageIO.read(url);
// } catch (IOException e) {
// }
// return image == null ? IconLoader.MissingImage.getIcon() : new ImageIcon(image);
try {
BufferedImage img = ImageIO.read(new File(imageFile));
return new ImageIcon(img);
} catch (Exception e) {
return IconLoader.MissingImage.getIcon();
}
}
}
@@ -0,0 +1,274 @@
package org.diylc.swing.plugins.cloud.view.browser;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.apache.log4j.Logger;
import org.diylc.common.IPlugInPort;
import org.diylc.common.ITask;
import org.diylc.core.IView;
import org.diylc.images.IconLoader;
import org.diylc.plugins.cloud.model.ProjectEntity;
import org.diylc.plugins.cloud.presenter.CloudPresenter;
import org.diylc.swing.ISwingUI;
public class CloudBrowserFrame extends JFrame {
private static final long serialVersionUID = 1L;
private static final Logger LOG = Logger.getLogger(CloudBrowserFrame.class);
private JPanel mainPanel;
private JTabbedPane tabbedPane;
private JPanel dashboardPanel;
private JPanel searchPanel;
private SearchHeaderPanel searchHeaderPanel;
private ResultsScrollPanel resultsScrollPane;
private NavigationPanel navigationPanel;
private IPlugInPort plugInPort;
private CloudPresenter cloudPresenter;
private List<ProjectEntity> currentResults;
// search criteria
private String searchFor;
private String category;
private String sort;
private int pageNumber;
private int itemsPerPage = 10;
private ISwingUI swingUI;
public CloudBrowserFrame(ISwingUI swingUI, IPlugInPort plugInPort, CloudPresenter cloudPresenter) {
super("DIY Cloud Browser");
this.swingUI = swingUI;
this.setIconImage(IconLoader.Cloud.getImage());
this.setPreferredSize(new Dimension(800, 600));
this.plugInPort = plugInPort;
this.cloudPresenter = cloudPresenter;
setContentPane(getMainPanel());
this.pack();
this.setLocationRelativeTo(swingUI.getOwnerFrame());
this.setGlassPane(new CloudGlassPane());
JRootPane rootPane = SwingUtilities.getRootPane(getSearchHeaderPanel().getGoButton());
rootPane.setDefaultButton(getSearchHeaderPanel().getGoButton());
}
public JPanel getMainPanel() {
if (mainPanel == null) {
mainPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1;
gbc.weighty = 1;
mainPanel.add(getTabbedPane(), gbc);
}
return mainPanel;
}
private JTabbedPane getTabbedPane() {
if (tabbedPane == null) {
tabbedPane = new JTabbedPane();
tabbedPane.addTab("Dashboard", IconLoader.Dashboard.getIcon(), getDashboardPanel());
tabbedPane.addTab("Search For Projects", IconLoader.Find.getIcon(), getSearchPanel());
tabbedPane.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
if (getTabbedPane().getSelectedIndex() == 1)
getSearchHeaderPanel().setFocus();
}
});
}
return tabbedPane;
}
private JPanel getDashboardPanel() {
if (dashboardPanel == null) {
dashboardPanel = new JPanel();
}
return dashboardPanel;
}
private JPanel getSearchPanel() {
if (searchPanel == null) {
searchPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
searchPanel.setBackground(Color.white);
gbc.anchor = GridBagConstraints.NORTH;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
searchPanel.add(getSearchHeaderPanel(), gbc);
gbc.gridy = 1;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
searchPanel.add(getResultsScrollPane(), gbc);
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridx = 0;
gbc.gridy++;
gbc.fill = GridBagConstraints.BOTH;
gbc.weighty = 0;
gbc.gridwidth = 3;
searchPanel.add(getNavigationPanel(), gbc);
}
return searchPanel;
}
private SearchHeaderPanel getSearchHeaderPanel() {
if (searchHeaderPanel == null) {
searchHeaderPanel = new SearchHeaderPanel(cloudPresenter);
searchHeaderPanel.getGoButton().addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
setPageNumber(1);
CloudBrowserFrame.this.searchFor = getSearchHeaderPanel().getSearchText();
CloudBrowserFrame.this.category = getSearchHeaderPanel().getCategory();
CloudBrowserFrame.this.sort = getSearchHeaderPanel().getSorting();
search();
}
});
}
return searchHeaderPanel;
}
private ResultsScrollPanel getResultsScrollPane() {
if (resultsScrollPane == null) {
resultsScrollPane = new ResultsScrollPanel(swingUI, this, plugInPort);
}
return resultsScrollPane;
}
private void search() {
executeBackgroundTask(new ITask<List<ProjectEntity>>() {
@Override
public List<ProjectEntity> doInBackground() throws Exception {
return cloudPresenter.search(searchFor, category, sort, pageNumber, itemsPerPage);
}
@Override
public void failed(Exception e) {
showMessage("Search failed! Detailed message is in the logs. Please report to the author.", "Search Failed",
IView.ERROR_MESSAGE);
}
@Override
public void complete(List<ProjectEntity> result) {
CloudBrowserFrame.this.currentResults = result;
getResultsScrollPane().clear();
int count = 0;
for (Iterator<ProjectEntity> i = result.iterator(); i.hasNext();) {
ProjectEntity project = i.next();
getResultsScrollPane().addProjectToDisplay(project, count++);
}
if (count == 0) {
getResultsScrollPane().showNoMatches();
count++;
}
}
});
}
private NavigationPanel getNavigationPanel() {
if (navigationPanel == null) {
navigationPanel = new NavigationPanel();
navigationPanel.getPrevPageButton().addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (CloudBrowserFrame.this.pageNumber > 1) {
setPageNumber(CloudBrowserFrame.this.pageNumber - 1);
CloudBrowserFrame.this.search();
}
}
});
navigationPanel.getNextPageButton().addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (CloudBrowserFrame.this.currentResults != null && !CloudBrowserFrame.this.currentResults.isEmpty()) {
setPageNumber(CloudBrowserFrame.this.pageNumber + 1);
CloudBrowserFrame.this.search();
}
}
});
}
return navigationPanel;
}
private void setPageNumber(int pageNumber) {
this.pageNumber = pageNumber;
getNavigationPanel().getPageLabel().setText("Page " + pageNumber);
}
public <T extends Object> void executeBackgroundTask(final ITask<T> task) {
getGlassPane().setVisible(true);
SwingWorker<T, Void> worker = new SwingWorker<T, Void>() {
@Override
protected T doInBackground() throws Exception {
return task.doInBackground();
}
@Override
protected void done() {
getGlassPane().setVisible(false);
try {
T result = get();
task.complete(result);
} catch (ExecutionException e) {
LOG.error("Background task execution failed", e);
task.failed(e);
} catch (InterruptedException e) {
LOG.error("Background task execution interrupted", e);
task.failed(e);
}
}
};
worker.execute();
}
public void showMessage(String message, String title, int messageType) {
JOptionPane.showMessageDialog(this, message, title, messageType);
}
public int showConfirmDialog(String message, String title, int optionType, int messageType) {
return JOptionPane.showConfirmDialog(this, message, title, optionType, messageType);
}
}
@@ -1,4 +1,4 @@
package org.diylc.swing.plugins.cloud.view;
package org.diylc.swing.plugins.cloud.view.browser;
import java.awt.Color;
import java.awt.Cursor;
@@ -19,6 +19,11 @@ import javax.swing.Timer;
import org.diylc.images.IconLoader;
/**
* JPanel that shows cloud animation while visible.
*
* @author bancika
*/
public class CloudGlassPane extends JPanel implements MouseListener, KeyListener {
public static final CloudGlassPane GLASS_PANE = new CloudGlassPane();
@@ -26,7 +31,7 @@ public class CloudGlassPane extends JPanel implements MouseListener, KeyListener
private static final long serialVersionUID = -5344758920442881290L;
private long startTime;
private final int msPerPx = 5;
private final int msPerPx = 6;
private Timer animationTimer;
@@ -0,0 +1,77 @@
package org.diylc.swing.plugins.cloud.view.browser;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import org.diylc.images.IconLoader;
public class NavigationPanel extends JPanel {
private static final long serialVersionUID = 1L;
private JButton prevPageButton;
private JButton nextPageButton;
private JLabel pageLabel;
public NavigationPanel() {
super(new GridBagLayout());
this.setBackground(Color.white);
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.SOUTHWEST;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridx = 0;
gbc.weightx = 0;
gbc.fill = GridBagConstraints.NONE;
this.add(getPrevPageButton(), gbc);
gbc.gridx++;
gbc.weightx = 1;
gbc.anchor = GridBagConstraints.LINE_START;
gbc.fill = GridBagConstraints.HORIZONTAL;
this.add(getPageLabel(), gbc);
gbc.gridx++;
gbc.weightx = 0;
gbc.anchor = GridBagConstraints.SOUTHWEST;
gbc.fill = GridBagConstraints.NONE;
this.add(getNextPageButton(), gbc);
}
public JButton getPrevPageButton() {
if (prevPageButton == null) {
prevPageButton = new JButton(IconLoader.NavLeftBlue.getIcon());
prevPageButton.setBorderPainted(false);
prevPageButton.setContentAreaFilled(false);
prevPageButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
return prevPageButton;
}
public JButton getNextPageButton() {
if (nextPageButton == null) {
nextPageButton = new JButton(IconLoader.NavRightBlue.getIcon());
nextPageButton.setBorderPainted(false);
nextPageButton.setContentAreaFilled(false);
nextPageButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
return nextPageButton;
}
public JLabel getPageLabel() {
if (pageLabel == null) {
pageLabel = new JLabel();
pageLabel.setFont(pageLabel.getFont().deriveFont(12f));
pageLabel.setHorizontalAlignment(SwingConstants.CENTER);
}
return pageLabel;
}
}
@@ -0,0 +1,230 @@
package org.diylc.swing.plugins.cloud.view.browser;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.SwingConstants;
import org.apache.log4j.Logger;
import org.diylc.common.IPlugInPort;
import org.diylc.common.ITask;
import org.diylc.core.IView;
import org.diylc.images.IconLoader;
import org.diylc.plugins.cloud.model.ProjectEntity;
import org.diylc.swing.ISwingUI;
import org.diylc.swing.gui.DialogFactory;
import org.diylc.swing.plugins.file.FileFilterEnum;
public class ResultsScrollPanel extends JScrollPane {
private static final long serialVersionUID = 1L;
private static final Logger LOG = Logger.getLogger(ResultsScrollPanel.class);
private JPanel resultsPanel;
private ISwingUI mainUI;
private CloudBrowserFrame cloudUI;
private IPlugInPort plugInPort;
public ResultsScrollPanel(ISwingUI mainUI, CloudBrowserFrame cloudUI, IPlugInPort plugInPort) {
super();
this.mainUI = mainUI;
this.cloudUI = cloudUI;
this.plugInPort = plugInPort;
this.getVerticalScrollBar().setUnitIncrement(16);
this.setBorder(null);
setViewportView(getResultsPanel());
}
public void clear() {
getResultsPanel().removeAll();
}
public void showNoMatches() {
JLabel label = new JLabel("<html><font size='5'>No projects match the search criteria.</font></html>");
label.setHorizontalAlignment(SwingConstants.CENTER);
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1;
gbc.weighty = Integer.MAX_VALUE;
getResultsPanel().add(label, gbc);
}
public void addProjectToDisplay(final ProjectEntity project, int location) {
JLabel thumbnailLabel = new JLabel(loadImage(project.getThumbnailUrl()));
JLabel nameLabel = new JLabel("<html><b>" + project.getName() + "</b></html>");
nameLabel.setFont(nameLabel.getFont().deriveFont(12f));
JLabel descriptionLabel = new JLabel("<html>" + project.getDescription() + "</html>");
JLabel categoryLabel = new JLabel("<html>Category: <b>" + project.getCategory() + "</b></html>");
JLabel authorLabel = new JLabel("<html>Author: <b>" + project.getOwner() + "</b></html>");
JLabel updatedLabel = new JLabel("<html>Last updated: <b>" + project.getUpdated() + "</b></html>");
JButton downloadButton = new JButton(IconLoader.CloudDownload.getIcon());
downloadButton.setBorderPainted(false);
// downloadButton.setFocusPainted(false);
downloadButton.setContentAreaFilled(false);
downloadButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
downloadButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
final File file =
DialogFactory.getInstance().showSaveDialog((JFrame)cloudUI, FileFilterEnum.DIY.getFilter(),
new File(project.getName() + ".diy"), FileFilterEnum.DIY.getExtensions()[0], null);
if (file != null) {
cloudUI.executeBackgroundTask(new ITask<Void>() {
@Override
public Void doInBackground() throws Exception {
LOG.debug("Downloading project to to " + file.getAbsolutePath());
URL website = new URL(project.getDownloadUrl());
ReadableByteChannel rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(file.getAbsolutePath());
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
return null;
}
@Override
public void complete(Void result) {
if (cloudUI.showConfirmDialog("Project downloaded to " + file.getAbsolutePath()
+ ".\nDo you want to open it?", "Cloud", ISwingUI.YES_NO_OPTION, ISwingUI.INFORMATION_MESSAGE) == IView.YES_OPTION) {
if (!plugInPort.allowFileAction()) {
return;
}
mainUI.executeBackgroundTask(new ITask<Void>() {
@Override
public Void doInBackground() throws Exception {
LOG.debug("Opening from " + file.getAbsolutePath());
plugInPort.loadProjectFromFile(file.getAbsolutePath());
return null;
}
@Override
public void complete(Void result) {
mainUI.bringToFocus();
}
@Override
public void failed(Exception e) {
mainUI.showMessage("Could not open file. Detailed message is in the logs", "Error",
ISwingUI.ERROR_MESSAGE);
}
});
}
}
@Override
public void failed(Exception e) {
cloudUI.showMessage("Could not save to file. Detailed message is in the logs", "Error",
ISwingUI.ERROR_MESSAGE);
}
});
}
}
});
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridx = 0;
gbc.gridy = location * 6;
gbc.fill = GridBagConstraints.NONE;
gbc.gridheight = 5;
gbc.weightx = 0;
getResultsPanel().add(thumbnailLabel, gbc);
gbc.gridheight = 1;
gbc.gridx = 1;
gbc.weightx = 1;
gbc.insets = new Insets(2, 6, 2, 2);
getResultsPanel().add(nameLabel, gbc);
//
// gbc.gridx = 2;
// gbc.anchor = GridBagConstraints.NORTHEAST;
// gbc.insets = new Insets(2, 2, 2, 8);
// getResultsPanel().add(authorLabel, gbc);
gbc.gridy++;
gbc.gridx = 1;
gbc.weighty = 1;
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.insets = new Insets(2, 6, 2, 2);
getResultsPanel().add(descriptionLabel, gbc);
gbc.gridy++;
gbc.gridx = 1;
gbc.weighty = 0;
getResultsPanel().add(categoryLabel, gbc);
gbc.gridx = 2;
gbc.gridheight = 3;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.anchor = GridBagConstraints.SOUTHEAST;
getResultsPanel().add(downloadButton, gbc);
gbc.gridy++;
gbc.gridx = 1;
gbc.gridheight = 1;
gbc.insets = new Insets(2, 6, 2, 2);
gbc.anchor = GridBagConstraints.NORTHWEST;
getResultsPanel().add(authorLabel, gbc);
gbc.gridy++;
getResultsPanel().add(updatedLabel, gbc);
gbc.gridx = 0;
gbc.gridy++;
gbc.gridwidth = 3;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
gbc.insets = new Insets(2, 2, 2, 2);
getResultsPanel().add(new JSeparator(), gbc);
}
private JPanel getResultsPanel() {
if (resultsPanel == null) {
resultsPanel = new JPanel(new GridBagLayout());
resultsPanel.setBackground(Color.white);
}
return resultsPanel;
}
private Icon loadImage(String imageFile) {
try {
BufferedImage img = ImageIO.read(new File(imageFile));
return new ImageIcon(img);
} catch (Exception e) {
return IconLoader.MissingImage.getIcon();
}
}
}
@@ -0,0 +1,121 @@
package org.diylc.swing.plugins.cloud.view.browser;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import org.diylc.images.IconLoader;
import org.diylc.plugins.cloud.presenter.CloudException;
import org.diylc.plugins.cloud.presenter.CloudPresenter;
public class SearchHeaderPanel extends JPanel {
private static final long serialVersionUID = 1L;
private JTextField searchField;
private JComboBox categoryBox;
private JComboBox sortBox;
private JButton goButton;
private CloudPresenter cloudPresenter;
public SearchHeaderPanel(CloudPresenter cloudPresenter) {
this.cloudPresenter = cloudPresenter;
setLayout(new GridBagLayout());
this.setBackground(Color.white);
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.LINE_START;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 0;
this.add(new JLabel("Search For:"), gbc);
gbc.gridx = 1;
gbc.weightx = 1;
this.add(getSearchField(), gbc);
gbc.gridx = 2;
gbc.weightx = 0;
this.add(new JLabel("Filter By Category:"), gbc);
gbc.gridx = 3;
gbc.weightx = 0.3;
this.add(getCategoryBox(), gbc);
gbc.gridx = 4;
gbc.weightx = 0;
this.add(new JLabel("Sort By:"), gbc);
gbc.gridx = 5;
this.add(getSortBox(), gbc);
gbc.gridx = 6;
gbc.weighty = 1;
this.add(getGoButton(), gbc);
}
public void setFocus() {
getSearchField().requestFocusInWindow();
}
private JTextField getSearchField() {
if (searchField == null) {
searchField = new JTextField(60);
}
return searchField;
}
private JComboBox getCategoryBox() {
if (categoryBox == null) {
try {
categoryBox = new JComboBox(cloudPresenter.getCategories());
} catch (CloudException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return categoryBox;
}
private JComboBox getSortBox() {
if (sortBox == null) {
try {
sortBox = new JComboBox(cloudPresenter.getSortings());
} catch (CloudException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return sortBox;
}
public JButton getGoButton() {
if (goButton == null) {
goButton = new JButton("Go", IconLoader.DataFind.getIcon());
}
return goButton;
}
public String getSearchText() {
return getSearchField().getText();
}
public String getCategory() {
return getCategoryBox().getSelectedItem() == null ? "" : getCategoryBox().getSelectedItem().toString();
}
public String getSorting() {
return getSortBox().getSelectedItem() == null ? "" : getSortBox().getSelectedItem().toString();
}
}