diff --git a/diylc/diylc-core/src/org/diylc/plugins/cloud/model/IServiceAPI.java b/diylc/diylc-core/src/org/diylc/plugins/cloud/model/IServiceAPI.java index 05813231..9b2f86ae 100644 --- a/diylc/diylc-core/src/org/diylc/plugins/cloud/model/IServiceAPI.java +++ b/diylc/diylc-core/src/org/diylc/plugins/cloud/model/IServiceAPI.java @@ -97,11 +97,13 @@ public interface IServiceAPI { * @param page * @param itemsPerPage * @param sort + * @param username * @return string with error message if the error occurred or a list of {@link ProjectEntity} * objects. */ Object search(@ParamName("criteria") String criteria, @ParamName("category") String category, - @ParamName("page") Integer page, @ParamName("itemsPerPage") Integer itemsPerPage, @ParamName("sort") String sort); + @ParamName("page") Integer page, @ParamName("itemsPerPage") Integer itemsPerPage, @ParamName("sort") String sort, + @ParamName("username") String username); /** * Uploads a project using token to authenticate. When projectI is specified, it updates the @@ -126,9 +128,9 @@ public interface IServiceAPI { @ParamName("diylcVersion") String diylcVersion, @ParamName("keywords") String keywords, @ParamName("thumbnail") File thumbnail, @ParamName("project") File project, @ParamName("projectId") Integer projectId); - + /** - *Deletes an existing project. The project must belong to the user + * Deletes an existing project. The project must belong to the user * * @param username * @param token diff --git a/diylc/diylc-core/src/org/diylc/plugins/cloud/presenter/CloudPresenter.java b/diylc/diylc-core/src/org/diylc/plugins/cloud/presenter/CloudPresenter.java index 0cc5608a..b87c3515 100644 --- a/diylc/diylc-core/src/org/diylc/plugins/cloud/presenter/CloudPresenter.java +++ b/diylc/diylc-core/src/org/diylc/plugins/cloud/presenter/CloudPresenter.java @@ -134,8 +134,8 @@ public class CloudPresenter { return categories; } - public void uploadProject(String projectName, String category, String description, String keywords, String diylcVersion, - File thumbnail, File project) throws IOException, CloudException { + public void uploadProject(String projectName, String category, String description, String keywords, + String diylcVersion, File thumbnail, File project) throws IOException, CloudException { String username = ConfigurationManager.getInstance().readString(USERNAME_KEY, null); String token = ConfigurationManager.getInstance().readString(TOKEN_KEY, null); @@ -234,37 +234,54 @@ public class CloudPresenter { throws CloudException { LOG.info(String.format("search(%1$s,%2$s,%3$s,%4$d,%5$d)", criteria, category, sortOrder, pageNumber, itemsPerPage)); try { - Object res = getService().search(criteria, category, pageNumber, itemsPerPage, sortOrder); - // Thread.sleep(2000); - if (res == null) - throw new CloudException("Failed to retreive search results."); - if (res instanceof String) - throw new CloudException(res.toString()); - if (res instanceof List) { - @SuppressWarnings("unchecked") - List projects = (List) res; - LOG.info("Received " + projects.size() + " results. Downloading thumbnails..."); - // 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); - ReadableByteChannel rbc = Channels.newChannel(website.openStream()); - 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()); - fos.close(); - } - LOG.info("Finished downloading thumbnails."); - return projects; - } - throw new CloudException("Unexpected server response received for search results: " + res.getClass().getName()); + Object res = getService().search(criteria, category, pageNumber, itemsPerPage, sortOrder, null); + return processResults(res); + } catch (CloudException ce) { + throw ce; } catch (Exception e) { throw new CloudException(e); } } + public List fetchUserUploads() throws CloudException { + UserEntity user = getUserDetails(); + try { + Object res = getService().search("", "", 1, Integer.MAX_VALUE, getSortings()[0], user.getUsername()); + return processResults(res); + } catch (CloudException ce) { + throw ce; + } catch (Exception e) { + throw new CloudException(e); + } + } + + private List processResults(Object res) throws CloudException, IOException { + if (res == null) + throw new CloudException("Failed to retreive search results."); + if (res instanceof String) + throw new CloudException(res.toString()); + if (res instanceof List) { + @SuppressWarnings("unchecked") + List projects = (List) res; + LOG.info("Received " + projects.size() + " results. Downloading thumbnails..."); + // 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); + ReadableByteChannel rbc = Channels.newChannel(website.openStream()); + 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()); + fos.close(); + } + LOG.info("Finished downloading thumbnails."); + return projects; + } + throw new CloudException("Unexpected server response received for search results: " + res.getClass().getName()); + } + public String[] getSortings() throws CloudException { try { return getService().getSortings().toArray(new String[0]); diff --git a/diylc/diylc-core/src/org/diylc/plugins/cloud/presenter/PagingProvider.java b/diylc/diylc-core/src/org/diylc/plugins/cloud/presenter/PagingProvider.java index 770b1f78..a243f58d 100644 --- a/diylc/diylc-core/src/org/diylc/plugins/cloud/presenter/PagingProvider.java +++ b/diylc/diylc-core/src/org/diylc/plugins/cloud/presenter/PagingProvider.java @@ -17,7 +17,12 @@ public class PagingProvider { private List currentResults; public PagingProvider(CloudPresenter cloudPresenter) { + this(cloudPresenter, 10); + } + + public PagingProvider(CloudPresenter cloudPresenter, int itemsPerPage) { this.cloudPresenter = cloudPresenter; + this.itemsPerPage = itemsPerPage; } public List startSession(String searchFor, String category, String sort) throws CloudException { diff --git a/diylc/diylc-swing/src/org/diylc/images/IconLoader.java b/diylc/diylc-swing/src/org/diylc/images/IconLoader.java index 00417107..c48e2ccf 100644 --- a/diylc/diylc-swing/src/org/diylc/images/IconLoader.java +++ b/diylc/diylc-swing/src/org/diylc/images/IconLoader.java @@ -32,10 +32,10 @@ public enum IconLoader { "briefcase_into.png"), RotateCW("rotate_cw.png"), RotateCCW("rotate_ccw.png"), ElementInto("element_into.png"), Arrow( "arrow.png"), Cloud("cloud.png"), CloudUp("cloud_up.png"), CloudGear("cloud_gear.png"), IdCardEdit( "id_card_edit.png"), KeyEdit("key_edit.png"), Find("find.png"), Dashboard("dashboard.png"), DataFind( - "data_find.png"), CloudDownload("cloud-download.png"), NavLeftBlue("nav_left_blue.png"), NavRightBlue( - "nav_right_blue.png"), MissingImage("missing_image.png"), CloudBg("cloud_bg.png"), CloudBig("cloud_big.png"), CloudWait( - "cloud_wait.png"), Spinning("spinning.gif"), Megaphone("megaphone.png"), Download("download.png"), Eye("eye.png"), Messages( - "messages.png"); + "data_find.png"), CloudDownload("cloud_download.png"), CloudUpload("cloud_upload.png"), NavLeftBlue( + "nav_left_blue.png"), NavRightBlue("nav_right_blue.png"), MissingImage("missing_image.png"), CloudBg( + "cloud_bg.png"), CloudBig("cloud_big.png"), CloudWait("cloud_wait.png"), Spinning("spinning.gif"), Megaphone( + "megaphone.png"), Download("download.png"), Eye("eye.png"), Messages("messages.png"); protected String name; diff --git a/diylc/diylc-swing/src/org/diylc/images/cloud-download.png b/diylc/diylc-swing/src/org/diylc/images/cloud_download.png similarity index 100% rename from diylc/diylc-swing/src/org/diylc/images/cloud-download.png rename to diylc/diylc-swing/src/org/diylc/images/cloud_download.png diff --git a/diylc/diylc-swing/src/org/diylc/images/cloud_upload.png b/diylc/diylc-swing/src/org/diylc/images/cloud_upload.png new file mode 100644 index 00000000..8ed48120 Binary files /dev/null and b/diylc/diylc-swing/src/org/diylc/images/cloud_upload.png differ diff --git a/diylc/diylc-swing/src/org/diylc/swing/ISimpleView.java b/diylc/diylc-swing/src/org/diylc/swing/ISimpleView.java new file mode 100644 index 00000000..1428945c --- /dev/null +++ b/diylc/diylc-swing/src/org/diylc/swing/ISimpleView.java @@ -0,0 +1,29 @@ +package org.diylc.swing; + +import javax.swing.JFrame; + +import org.diylc.common.ITask; + +/** + * Interface for secondary windows that support basic functionalities. + * + * @author Branislav Stojkovic + */ +public interface ISimpleView { + + /** + * Runs a task in background while showing busy cursor and a glass pane. + * + * @param task + */ + void executeBackgroundTask(ITask task); + + void showMessage(String message, String title, int messageType); + + int showConfirmDialog(String message, String title, int optionType, int messageType); + + /** + * @return {@link JFrame} that can be used to reference secondary dialogs and frames + */ + JFrame getOwnerFrame(); +} diff --git a/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/CloudPlugIn.java b/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/CloudPlugIn.java index c907b946..48b3a71a 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/CloudPlugIn.java +++ b/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/CloudPlugIn.java @@ -26,9 +26,9 @@ 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.cloud.view.browser.UploadManagerFrame; import org.diylc.swing.plugins.file.FileFilterEnum; import org.diylc.swingframework.ButtonDialog; -import org.diylc.swingframework.ProgressDialog; public class CloudPlugIn implements IPlugIn, CloudListener { @@ -118,6 +118,10 @@ public class CloudPlugIn implements IPlugIn, CloudListener { return cloudBrowser; } + public UploadManagerFrame createUploadManagerFrame() { + return new UploadManagerFrame(swingUI, plugInPort, cloudPresenter); + } + public LibraryAction getLibraryAction() { if (libraryAction == null) { libraryAction = new LibraryAction(); @@ -455,15 +459,14 @@ public class CloudPlugIn implements IPlugIn, CloudListener { public ManageProjectsAction() { super(); - putValue(AbstractAction.NAME, "Manage My Projects"); + putValue(AbstractAction.NAME, "Manage My Uploads"); putValue(AbstractAction.SMALL_ICON, IconLoader.CloudGear.getIcon()); } @Override public void actionPerformed(ActionEvent e) { - ProgressDialog dialog = - DialogFactory.getInstance().createProgressDialog("Test", new String[] {}, "Some text", false); - dialog.setVisible(true); + UploadManagerFrame frame = createUploadManagerFrame(); + frame.setVisible(true); } } diff --git a/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/CommentDialog.java b/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/CommentDialog.java index b4121f8b..e37c1e27 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/CommentDialog.java +++ b/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/CommentDialog.java @@ -23,7 +23,7 @@ import org.diylc.core.IView; import org.diylc.plugins.cloud.model.CommentEntity; import org.diylc.plugins.cloud.model.ProjectEntity; import org.diylc.plugins.cloud.presenter.CloudPresenter; -import org.diylc.swing.plugins.cloud.view.browser.CloudBrowserFrame; +import org.diylc.swing.ISimpleView; public class CommentDialog extends JDialog { @@ -44,19 +44,18 @@ public class CommentDialog extends JDialog { private int lastPosition = 0; - private CloudBrowserFrame owner; + private ISimpleView owner; - public CommentDialog(CloudBrowserFrame owner, ProjectEntity project, List comments, + public CommentDialog(ISimpleView cloudUI, ProjectEntity project, List comments, CloudPresenter presenter) { - super(owner, "Comments on " + project.getName()); - this.owner = owner; + super(cloudUI.getOwnerFrame(), "Comments on " + project.getName()); this.project = project; this.comments = comments; this.presenter = presenter; setMinimumSize(new Dimension(400, 600)); setContentPane(getMainPanel()); pack(); - setLocationRelativeTo(owner); + setLocationRelativeTo(cloudUI.getOwnerFrame()); setModal(true); if (!presenter.isLoggedIn()) { getReplyArea().setEnabled(false); diff --git a/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/browser/CloudBrowserFrame.java b/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/browser/CloudBrowserFrame.java index 17cba956..4e6c07a9 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/browser/CloudBrowserFrame.java +++ b/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/browser/CloudBrowserFrame.java @@ -28,10 +28,13 @@ import org.diylc.images.IconLoader; import org.diylc.plugins.cloud.model.ProjectEntity; import org.diylc.plugins.cloud.presenter.CloudPresenter; import org.diylc.plugins.cloud.presenter.PagingProvider; +import org.diylc.swing.ISimpleView; import org.diylc.swing.ISwingUI; import org.diylc.utils.Pair; -public class CloudBrowserFrame extends JFrame { +public class CloudBrowserFrame extends JFrame implements ISimpleView { + + private static final String TITLE = "Search The Cloud"; private static final long serialVersionUID = 1L; @@ -52,7 +55,7 @@ public class CloudBrowserFrame extends JFrame { private ISwingUI swingUI; public CloudBrowserFrame(ISwingUI swingUI, IPlugInPort plugInPort, CloudPresenter cloudPresenter) { - super("Search The Cloud"); + super(TITLE); this.swingUI = swingUI; this.setIconImage(IconLoader.Cloud.getImage()); this.setPreferredSize(new Dimension(700, 640)); @@ -195,12 +198,13 @@ public class CloudBrowserFrame extends JFrame { } @Override - public void complete(List result) { + public void complete(List result) { getResultsScrollPane().startSearch(result); } }); } + @Override public void executeBackgroundTask(final ITask task) { getGlassPane().setVisible(true); SwingWorker worker = new SwingWorker() { @@ -228,11 +232,18 @@ public class CloudBrowserFrame extends JFrame { worker.execute(); } + @Override public void showMessage(String message, String title, int messageType) { JOptionPane.showMessageDialog(this, message, title, messageType); } + @Override public int showConfirmDialog(String message, String title, int optionType, int messageType) { return JOptionPane.showConfirmDialog(this, message, title, optionType, messageType); } + + @Override + public JFrame getOwnerFrame() { + return this; + } } diff --git a/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/browser/ResultsScrollPanel.java b/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/browser/ResultsScrollPanel.java index 4989a81f..2ad758cd 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/browser/ResultsScrollPanel.java +++ b/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/browser/ResultsScrollPanel.java @@ -44,6 +44,7 @@ import org.diylc.plugins.cloud.model.CommentEntity; import org.diylc.plugins.cloud.model.ProjectEntity; import org.diylc.plugins.cloud.presenter.CloudPresenter; import org.diylc.plugins.cloud.presenter.PagingProvider; +import org.diylc.swing.ISimpleView; import org.diylc.swing.ISwingUI; import org.diylc.swing.gui.DialogFactory; import org.diylc.swing.plugins.cloud.view.CommentDialog; @@ -65,7 +66,7 @@ public class ResultsScrollPanel extends JScrollPane { private JLabel topLabel; private ISwingUI mainUI; - private CloudBrowserFrame cloudUI; + private ISimpleView cloudUI; private IPlugInPort plugInPort; @@ -80,7 +81,7 @@ public class ResultsScrollPanel extends JScrollPane { private Icon spinnerIcon = IconLoader.Spinning.getIcon(); - public ResultsScrollPanel(ISwingUI mainUI, CloudBrowserFrame cloudUI, IPlugInPort plugInPort, + public ResultsScrollPanel(ISwingUI mainUI, ISimpleView cloudUI, IPlugInPort plugInPort, PagingProvider provider, CloudPresenter cloudPresenter) { super(); this.mainUI = mainUI; @@ -157,7 +158,7 @@ public class ResultsScrollPanel extends JScrollPane { getViewport().setViewPosition(old); } }); - if (provider.hasMoreData()) { + if (provider != null && provider.hasMoreData()) { getLoadMoreLabel().setText("Querying the cloud for more results..."); getLoadMoreLabel().setIcon(spinnerIcon); } else { @@ -387,7 +388,7 @@ public class ResultsScrollPanel extends JScrollPane { @Override public void paint(Graphics g) { super.paint(g); - if (armed && provider.hasMoreData()) { + if (armed && provider != null && provider.hasMoreData()) { // disarm immediately so we don't trigger successive requests to the provider armed = false; SwingWorker, Void> worker = new SwingWorker, Void>() { diff --git a/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/browser/UploadManagerFrame.java b/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/browser/UploadManagerFrame.java new file mode 100644 index 00000000..6568553e --- /dev/null +++ b/diylc/diylc-swing/src/org/diylc/swing/plugins/cloud/view/browser/UploadManagerFrame.java @@ -0,0 +1,124 @@ +package org.diylc.swing.plugins.cloud.view.browser; + +import java.awt.Dimension; +import java.util.List; +import java.util.concurrent.ExecutionException; + +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.SwingWorker; + +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.ISimpleView; +import org.diylc.swing.ISwingUI; + +public class UploadManagerFrame extends JFrame implements ISimpleView { + + private static final String TITLE = "Manage My Uploads"; + + private static final long serialVersionUID = 1L; + + private static final Logger LOG = Logger.getLogger(UploadManagerFrame.class); + + private ResultsScrollPanel resultsScrollPane; + + private IPlugInPort plugInPort; + private CloudPresenter cloudPresenter; + + private ISwingUI swingUI; + + public UploadManagerFrame(ISwingUI swingUI, IPlugInPort plugInPort, CloudPresenter cloudPresenter) { + super(TITLE); + this.swingUI = swingUI; + this.setIconImage(IconLoader.CloudGear.getImage()); + this.setPreferredSize(new Dimension(700, 640)); + this.plugInPort = plugInPort; + this.cloudPresenter = cloudPresenter; + + setContentPane(getResultsScrollPane()); + this.pack(); + this.setLocationRelativeTo(swingUI.getOwnerFrame()); + this.setGlassPane(SimpleCloudGlassPane.GLASS_PANE); + + search(); + } + + private ResultsScrollPanel getResultsScrollPane() { + if (resultsScrollPane == null) { + resultsScrollPane = new ResultsScrollPanel(swingUI, this, plugInPort, null, cloudPresenter); + } + return resultsScrollPane; + } + + private void search() { + getResultsScrollPane().clearPrevious(); + executeBackgroundTask(new ITask>() { + + @Override + public List doInBackground() throws Exception { + return cloudPresenter.fetchUserUploads(); + } + + @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 result) { + setTitle(TITLE + " - " + result.size() + " Uploads Found"); + getResultsScrollPane().startSearch(result); + } + }); + } + + @Override + public void executeBackgroundTask(final ITask task) { + getGlassPane().setVisible(true); + SwingWorker worker = new SwingWorker() { + + @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(); + } + + @Override + public void showMessage(String message, String title, int messageType) { + JOptionPane.showMessageDialog(this, message, title, messageType); + } + + @Override + public int showConfirmDialog(String message, String title, int optionType, int messageType) { + return JOptionPane.showConfirmDialog(this, message, title, optionType, messageType); + } + + @Override + public JFrame getOwnerFrame() { + return this; + } +}