search paging improvement

This commit is contained in:
bancika
2016-10-26 12:04:04 +02:00
parent 5ffb223a0d
commit 54e9797566
8 changed files with 176 additions and 65 deletions
@@ -0,0 +1,40 @@
package org.diylc.plugins.cloud.presenter;
import java.util.List;
import org.diylc.plugins.cloud.model.ProjectEntity;
public class PagingProvider {
private CloudPresenter cloudPresenter;
private String searchFor;
private String category;
private String sort;
private int itemsPerPage = 10;
private int currentPage;
private List<ProjectEntity> currentResults;
public PagingProvider(CloudPresenter cloudPresenter) {
this.cloudPresenter = cloudPresenter;
}
public List<ProjectEntity> startSession(String searchFor, String category, String sort) throws CloudException {
this.searchFor = searchFor;
this.category = category;
this.sort = sort;
this.currentPage = 1;
return currentResults = cloudPresenter.search(searchFor, category, sort, currentPage, itemsPerPage);
}
public boolean hasMoreData() {
return this.currentResults != null && this.currentResults.size() == itemsPerPage;
}
public List<ProjectEntity> requestMoreData() throws CloudException {
currentPage++;
return currentResults = cloudPresenter.search(searchFor, category, sort, currentPage, itemsPerPage);
}
}
@@ -33,7 +33,7 @@ public enum IconLoader {
"arrow.png"), Cloud("cloud.png"), CloudUp("cloud_up.png"), CloudGear("cloud_gear.png"), IdCardEdit( "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( "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( "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"); "nav_right_blue.png"), MissingImage("missing_image.png"), CloudBg("cloud_bg.png"), CloudBig("cloud_big.png");
protected String name; protected String name;
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

@@ -28,9 +28,9 @@ import org.diylc.images.IconLoader;
* *
* @author bancika * @author bancika
*/ */
public class CloudGlassPane extends JPanel implements MouseListener, KeyListener { public class AnimatedCloudGlassPane extends JPanel implements MouseListener, KeyListener {
public static final CloudGlassPane GLASS_PANE = new CloudGlassPane(); public static final AnimatedCloudGlassPane GLASS_PANE = new AnimatedCloudGlassPane();
private static final long serialVersionUID = -5344758920442881290L; private static final long serialVersionUID = -5344758920442881290L;
@@ -42,7 +42,7 @@ public class CloudGlassPane extends JPanel implements MouseListener, KeyListener
private VolatileImage volatileImg; private VolatileImage volatileImg;
public CloudGlassPane() { public AnimatedCloudGlassPane() {
addKeyListener(this); addKeyListener(this);
addMouseListener(this); addMouseListener(this);
setCursor(new Cursor(Cursor.WAIT_CURSOR)); setCursor(new Cursor(Cursor.WAIT_CURSOR));
@@ -27,6 +27,7 @@ import org.diylc.core.IView;
import org.diylc.images.IconLoader; import org.diylc.images.IconLoader;
import org.diylc.plugins.cloud.model.ProjectEntity; import org.diylc.plugins.cloud.model.ProjectEntity;
import org.diylc.plugins.cloud.presenter.CloudPresenter; import org.diylc.plugins.cloud.presenter.CloudPresenter;
import org.diylc.plugins.cloud.presenter.PagingProvider;
import org.diylc.swing.ISwingUI; import org.diylc.swing.ISwingUI;
public class CloudBrowserFrame extends JFrame { public class CloudBrowserFrame extends JFrame {
@@ -45,15 +46,7 @@ public class CloudBrowserFrame extends JFrame {
private IPlugInPort plugInPort; private IPlugInPort plugInPort;
private CloudPresenter cloudPresenter; private CloudPresenter cloudPresenter;
private PagingProvider pagingProvider;
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; private ISwingUI swingUI;
@@ -64,11 +57,12 @@ public class CloudBrowserFrame extends JFrame {
this.setPreferredSize(new Dimension(700, 640)); this.setPreferredSize(new Dimension(700, 640));
this.plugInPort = plugInPort; this.plugInPort = plugInPort;
this.cloudPresenter = cloudPresenter; this.cloudPresenter = cloudPresenter;
this.pagingProvider = new PagingProvider(cloudPresenter);
setContentPane(getSearchPanel()); setContentPane(getSearchPanel());
this.pack(); this.pack();
this.setLocationRelativeTo(swingUI.getOwnerFrame()); this.setLocationRelativeTo(swingUI.getOwnerFrame());
this.setGlassPane(new CloudGlassPane()); this.setGlassPane(SimpleCloudGlassPane.GLASS_PANE);
JRootPane rootPane = SwingUtilities.getRootPane(getSearchHeaderPanel().getGoButton()); JRootPane rootPane = SwingUtilities.getRootPane(getSearchHeaderPanel().getGoButton());
rootPane.setDefaultButton(getSearchHeaderPanel().getGoButton()); rootPane.setDefaultButton(getSearchHeaderPanel().getGoButton());
@@ -144,11 +138,6 @@ public class CloudBrowserFrame extends JFrame {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
CloudBrowserFrame.this.pageNumber = 1;
CloudBrowserFrame.this.searchFor = getSearchHeaderPanel().getSearchText();
CloudBrowserFrame.this.category = getSearchHeaderPanel().getCategory();
CloudBrowserFrame.this.sort = getSearchHeaderPanel().getSorting();
getResultsScrollPane().startOver();
search(); search();
} }
}); });
@@ -158,29 +147,19 @@ public class CloudBrowserFrame extends JFrame {
private ResultsScrollPanel getResultsScrollPane() { private ResultsScrollPanel getResultsScrollPane() {
if (resultsScrollPane == null) { if (resultsScrollPane == null) {
resultsScrollPane = new ResultsScrollPanel(swingUI, this, plugInPort, new ILazyProvider<ProjectEntity>() { resultsScrollPane = new ResultsScrollPanel(swingUI, this, plugInPort, pagingProvider);
@Override
public void requestMoreData() {
CloudBrowserFrame.this.pageNumber++;
CloudBrowserFrame.this.search();
}
@Override
public boolean hasMoreData() {
return currentResults.size() == itemsPerPage;
}
});
} }
return resultsScrollPane; return resultsScrollPane;
} }
private void search() { private void search() {
getResultsScrollPane().clearPrevious();
executeBackgroundTask(new ITask<List<ProjectEntity>>() { executeBackgroundTask(new ITask<List<ProjectEntity>>() {
@Override @Override
public List<ProjectEntity> doInBackground() throws Exception { public List<ProjectEntity> doInBackground() throws Exception {
return cloudPresenter.search(searchFor, category, sort, pageNumber, itemsPerPage); return pagingProvider.startSession(getSearchHeaderPanel().getSearchText(),
getSearchHeaderPanel().getCategory(), getSearchHeaderPanel().getSorting());
} }
@Override @Override
@@ -191,8 +170,7 @@ public class CloudBrowserFrame extends JFrame {
@Override @Override
public void complete(List<ProjectEntity> result) { public void complete(List<ProjectEntity> result) {
CloudBrowserFrame.this.currentResults = result; getResultsScrollPane().startSearch(result);
getResultsScrollPane().addData(result);
} }
}); });
} }
@@ -1,21 +0,0 @@
package org.diylc.swing.plugins.cloud.view.browser;
/***
* Generic interface for dynamic data provider.
*
* @author Branislav Stojkovic
*
* @param <T>
*/
public interface ILazyProvider<T> {
/**
* @return true if there's potentially more data at the source
*/
boolean hasMoreData();
/**
* call to request more data. New data batch should be sent asynchronously to this function call.
*/
void requestMoreData();
}
@@ -6,7 +6,6 @@ import java.awt.Graphics;
import java.awt.GridBagConstraints; import java.awt.GridBagConstraints;
import java.awt.GridBagLayout; import java.awt.GridBagLayout;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
@@ -29,6 +28,7 @@ import javax.swing.JScrollPane;
import javax.swing.JSeparator; import javax.swing.JSeparator;
import javax.swing.JTextArea; import javax.swing.JTextArea;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
import javax.swing.SwingWorker;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
@@ -36,6 +36,7 @@ import org.diylc.common.ITask;
import org.diylc.core.IView; import org.diylc.core.IView;
import org.diylc.images.IconLoader; import org.diylc.images.IconLoader;
import org.diylc.plugins.cloud.model.ProjectEntity; import org.diylc.plugins.cloud.model.ProjectEntity;
import org.diylc.plugins.cloud.presenter.PagingProvider;
import org.diylc.swing.ISwingUI; import org.diylc.swing.ISwingUI;
import org.diylc.swing.gui.DialogFactory; import org.diylc.swing.gui.DialogFactory;
import org.diylc.swing.plugins.file.FileFilterEnum; import org.diylc.swing.plugins.file.FileFilterEnum;
@@ -63,10 +64,9 @@ public class ResultsScrollPanel extends JScrollPane {
* This flag tells us whether the loadMoreLabel should invoke a new data pull or not. * This flag tells us whether the loadMoreLabel should invoke a new data pull or not.
*/ */
private boolean armed; private boolean armed;
private ILazyProvider<ProjectEntity> provider; private PagingProvider provider;
public ResultsScrollPanel(ISwingUI mainUI, CloudBrowserFrame cloudUI, IPlugInPort plugInPort, public ResultsScrollPanel(ISwingUI mainUI, CloudBrowserFrame cloudUI, IPlugInPort plugInPort, PagingProvider provider) {
ILazyProvider<ProjectEntity> provider) {
super(); super();
this.mainUI = mainUI; this.mainUI = mainUI;
this.cloudUI = cloudUI; this.cloudUI = cloudUI;
@@ -78,18 +78,24 @@ public class ResultsScrollPanel extends JScrollPane {
setViewportView(getResultsPanel()); setViewportView(getResultsPanel());
} }
public void startOver() { public void clearPrevious() {
currentLocation = 0; currentLocation = 0;
getResultsPanel().removeAll(); getResultsPanel().removeAll();
armed = false; armed = false;
}
public void startSearch(List<ProjectEntity> projects) {
GridBagConstraints gbc = new GridBagConstraints(); GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.NORTHWEST; gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.gridx = 0; gbc.gridx = 0;
gbc.gridy = 10000; gbc.gridy = 10000;
gbc.fill = GridBagConstraints.BOTH; gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 0; gbc.weightx = 1;
gbc.weighty = 100; gbc.weighty = 100;
gbc.gridwidth = 3;
resultsPanel.add(getLoadMoreLabel(), gbc); resultsPanel.add(getLoadMoreLabel(), gbc);
addData(projects);
} }
public void showNoMatches() { public void showNoMatches() {
@@ -109,12 +115,15 @@ public class ResultsScrollPanel extends JScrollPane {
if (projects == null || projects.isEmpty() && currentLocation == 0) { if (projects == null || projects.isEmpty() && currentLocation == 0) {
showNoMatches(); showNoMatches();
} else { } else {
LOG.info("Adding " + projects.size() + " projects to display.");
for (int i = 0; i < projects.size(); i++) { for (int i = 0; i < projects.size(); i++) {
addProjectToDisplay(projects.get(i)); addProjectToDisplay(projects.get(i));
this.currentLocation++; this.currentLocation++;
} }
armed = true; armed = true;
} }
getLoadMoreLabel().setText(provider.hasMoreData() ? "Loading more data..." : "");
} }
private JComponent addProjectToDisplay(final ProjectEntity project) { private JComponent addProjectToDisplay(final ProjectEntity project) {
@@ -253,24 +262,50 @@ public class ResultsScrollPanel extends JScrollPane {
gbc.insets = new Insets(2, 2, 2, 2); gbc.insets = new Insets(2, 2, 2, 2);
getResultsPanel().add(new JSeparator(), gbc); getResultsPanel().add(new JSeparator(), gbc);
getResultsPanel().invalidate();
return thumbnailLabel; return thumbnailLabel;
} }
private JLabel getLoadMoreLabel() { private JLabel getLoadMoreLabel() {
if (loadMoreLabel == null) { if (loadMoreLabel == null) {
loadMoreLabel = new JLabel("Load more...") { loadMoreLabel = new JLabel("Loading more data...") {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Override @Override
public void paint(Graphics g) { public void paint(Graphics g) {
super.paint(g);
if (armed && provider.hasMoreData()) { if (armed && provider.hasMoreData()) {
// disarm immediately so we don't trigger successive requests to the provider // disarm immediately so we don't trigger successive requests to the provider
armed = false; armed = false;
provider.requestMoreData(); SwingWorker<List<ProjectEntity>, Void> worker = new SwingWorker<List<ProjectEntity>, Void>() {
@Override
protected List<ProjectEntity> doInBackground() throws Exception {
return provider.requestMoreData();
}
@Override
protected void done() {
try {
List<ProjectEntity> newResults = get();
if (newResults != null && !newResults.isEmpty())
addData(newResults);
else
getLoadMoreLabel().setText("");
} catch (Exception e) {
cloudUI.showMessage("Search failed! Detailed message is in the logs. Please report to the author.",
"Search Failed", IView.ERROR_MESSAGE);
}
}
};
worker.execute();
} }
} }
}; };
loadMoreLabel.setHorizontalAlignment(SwingConstants.CENTER);
loadMoreLabel.setFont(loadMoreLabel.getFont().deriveFont(10f));
} }
return loadMoreLabel; return loadMoreLabel;
} }
@@ -0,0 +1,79 @@
package org.diylc.swing.plugins.cloud.view.browser;
import java.awt.Cursor;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import org.diylc.images.IconLoader;
/**
* JPanel that shows cloud animation while visible.
*
* @author bancika
*/
public class SimpleCloudGlassPane extends JPanel implements MouseListener, KeyListener {
public static final SimpleCloudGlassPane GLASS_PANE = new SimpleCloudGlassPane();
private static final long serialVersionUID = -5344758920442881290L;
public SimpleCloudGlassPane() {
addKeyListener(this);
addMouseListener(this);
setCursor(new Cursor(Cursor.WAIT_CURSOR));
setOpaque(false);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.LAST_LINE_START;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
gbc.weighty = 1;
JLabel cloudLabel = new JLabel(IconLoader.CloudBig.getIcon());
cloudLabel.setHorizontalAlignment(SwingConstants.CENTER);
add(cloudLabel, gbc);
gbc.gridy = 1;
gbc.weighty = 1.5;
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
JLabel label = new JLabel("<html><font size='5' color='#999999'>Querying the cloud...</font></html>");
label.setHorizontalAlignment(SwingConstants.CENTER);
add(label, gbc);
}
@Override
public void mouseClicked(final MouseEvent pArg0) {}
@Override
public void mouseEntered(final MouseEvent pArg0) {}
@Override
public void mouseExited(final MouseEvent pArg0) {}
@Override
public void mousePressed(final MouseEvent pArg0) {}
@Override
public void mouseReleased(final MouseEvent pArg0) {}
@Override
public void keyPressed(KeyEvent e) {}
@Override
public void keyReleased(KeyEvent e) {}
@Override
public void keyTyped(KeyEvent e) {}
}