com.google.appinventor.client.explorer.youngandroid.ProjectList.java Source code

Java tutorial

Introduction

Here is the source code for com.google.appinventor.client.explorer.youngandroid.ProjectList.java

Source

// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

package com.google.appinventor.client.explorer.youngandroid;

import com.google.appinventor.client.GalleryClient;
import com.google.appinventor.client.Ode;
import com.google.appinventor.client.OdeAsyncCallback;
import static com.google.appinventor.client.Ode.MESSAGES;
import com.google.appinventor.client.explorer.project.Project;
import com.google.appinventor.client.explorer.project.ProjectComparators;
import com.google.appinventor.client.explorer.project.ProjectManagerEventListener;
import com.google.appinventor.shared.rpc.project.GalleryApp;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * The project list shows all projects in a table.
 *
 * <p> The project name, date created, and date modified will be shown in the table.
 *
 * @author lizlooney@google.com (Liz Looney)
 */
public class ProjectList extends Composite implements ProjectManagerEventListener {
    private enum SortField {
        NAME, DATE_CREATED, DATE_MODIFIED, PUBLISHED,
    }

    private enum SortOrder {
        ASCENDING, DESCENDING,
    }

    // TODO: add these to OdeMessages.java
    private static final String NOT_PUBLISHED = "No";
    private static final String PUBLISHED = "Yes";
    private static final String PUBLISHBUTTONTITLE = "Open a dialog to publish your app to the Gallery";
    private static final String UPDATEBUTTONTITLE = "Open a dialog to publish your newest version in the Gallery";

    private final List<Project> projects;
    private final List<Project> selectedProjects;
    private final Map<Project, ProjectWidgets> projectWidgets;
    private SortField sortField;
    private SortOrder sortOrder;

    // UI elements
    private final Grid table;
    private final Label nameSortIndicator;
    private final Label dateCreatedSortIndicator;
    private final Label dateModifiedSortIndicator;
    private final Label publishedSortIndicator;

    GalleryClient gallery = null;

    /**
     * Creates a new ProjectList
     */
    public ProjectList() {
        projects = new ArrayList<Project>();
        selectedProjects = new ArrayList<Project>();
        projectWidgets = new HashMap<Project, ProjectWidgets>();

        sortField = SortField.DATE_MODIFIED;
        sortOrder = SortOrder.DESCENDING;

        // Initialize UI
        table = new Grid(1, 5); // The table initially contains just the header row.
        table.addStyleName("ode-ProjectTable");
        table.setWidth("100%");
        table.setCellSpacing(0);
        nameSortIndicator = new Label("");
        dateCreatedSortIndicator = new Label("");
        dateModifiedSortIndicator = new Label("");
        publishedSortIndicator = new Label("");
        refreshSortIndicators();
        setHeaderRow();

        VerticalPanel panel = new VerticalPanel();
        panel.setWidth("100%");

        panel.add(table);
        initWidget(panel);

        // It is important to listen to project manager events as soon as possible.
        Ode.getInstance().getProjectManager().addProjectManagerEventListener(this);

        gallery = GalleryClient.getInstance();
    }

    /**
     * Adds the header row to the table.
     *
     */
    private void setHeaderRow() {
        table.getRowFormatter().setStyleName(0, "ode-ProjectHeaderRow");

        HorizontalPanel nameHeader = new HorizontalPanel();
        final Label nameHeaderLabel = new Label(MESSAGES.projectNameHeader());
        nameHeaderLabel.addStyleName("ode-ProjectHeaderLabel");
        nameHeader.add(nameHeaderLabel);
        nameSortIndicator.addStyleName("ode-ProjectHeaderLabel");
        nameHeader.add(nameSortIndicator);
        table.setWidget(0, 1, nameHeader);

        HorizontalPanel dateCreatedHeader = new HorizontalPanel();
        final Label dateCreatedHeaderLabel = new Label(MESSAGES.projectDateCreatedHeader());
        dateCreatedHeaderLabel.addStyleName("ode-ProjectHeaderLabel");
        dateCreatedHeader.add(dateCreatedHeaderLabel);
        dateCreatedSortIndicator.addStyleName("ode-ProjectHeaderLabel");
        dateCreatedHeader.add(dateCreatedSortIndicator);
        table.setWidget(0, 2, dateCreatedHeader);

        HorizontalPanel dateModifiedHeader = new HorizontalPanel();
        final Label dateModifiedHeaderLabel = new Label(MESSAGES.projectDateModifiedHeader());
        dateModifiedHeaderLabel.addStyleName("ode-ProjectHeaderLabel");
        dateModifiedHeader.add(dateModifiedHeaderLabel);
        dateModifiedSortIndicator.addStyleName("ode-ProjectHeaderLabel");
        dateModifiedHeader.add(dateModifiedSortIndicator);
        table.setWidget(0, 3, dateModifiedHeader);

        HorizontalPanel publishedHeader = new HorizontalPanel();
        final Label publishedHeaderLabel = new Label(MESSAGES.projectPublishedHeader());
        publishedHeaderLabel.addStyleName("ode-ProjectHeaderLabel");
        publishedHeader.add(publishedHeaderLabel);
        publishedSortIndicator.addStyleName("ode-ProjectHeaderLabel");
        publishedHeader.add(publishedSortIndicator);
        table.setWidget(0, 4, publishedHeader);

        MouseDownHandler mouseDownHandler = new MouseDownHandler() {
            @Override
            public void onMouseDown(MouseDownEvent e) {
                SortField clickedSortField;
                if (e.getSource() == nameHeaderLabel || e.getSource() == nameSortIndicator) {
                    clickedSortField = SortField.NAME;
                } else if (e.getSource() == dateCreatedHeaderLabel || e.getSource() == dateCreatedSortIndicator) {
                    clickedSortField = SortField.DATE_CREATED;
                } else if (e.getSource() == dateModifiedHeaderLabel || e.getSource() == dateModifiedSortIndicator) {
                    clickedSortField = SortField.DATE_MODIFIED;
                } else {
                    clickedSortField = SortField.PUBLISHED;
                }
                changeSortOrder(clickedSortField);
            }
        };
        nameHeaderLabel.addMouseDownHandler(mouseDownHandler);
        nameSortIndicator.addMouseDownHandler(mouseDownHandler);
        dateCreatedHeaderLabel.addMouseDownHandler(mouseDownHandler);
        dateCreatedSortIndicator.addMouseDownHandler(mouseDownHandler);
        dateModifiedHeaderLabel.addMouseDownHandler(mouseDownHandler);
        dateModifiedSortIndicator.addMouseDownHandler(mouseDownHandler);
        publishedHeaderLabel.addMouseDownHandler(mouseDownHandler);
        publishedSortIndicator.addMouseDownHandler(mouseDownHandler);
    }

    private void changeSortOrder(SortField clickedSortField) {
        if (sortField != clickedSortField) {
            sortField = clickedSortField;
            sortOrder = SortOrder.ASCENDING;
        } else {
            if (sortOrder == SortOrder.ASCENDING) {
                sortOrder = SortOrder.DESCENDING;
            } else {
                sortOrder = SortOrder.ASCENDING;
            }
        }
        refreshTable(true);
    }

    private void refreshSortIndicators() {
        String text = (sortOrder == SortOrder.ASCENDING) ? "\u25B2" // up-pointing triangle
                : "\u25BC"; // down-pointing triangle
        switch (sortField) {
        case NAME:
            nameSortIndicator.setText(text);
            dateCreatedSortIndicator.setText("");
            dateModifiedSortIndicator.setText("");
            break;
        case DATE_CREATED:
            dateCreatedSortIndicator.setText(text);
            dateModifiedSortIndicator.setText("");
            nameSortIndicator.setText("");
            break;
        case DATE_MODIFIED:
            dateModifiedSortIndicator.setText(text);
            dateCreatedSortIndicator.setText("");
            nameSortIndicator.setText("");
            break;
        case PUBLISHED:
            publishedSortIndicator.setText(text);
            nameSortIndicator.setText("");
            dateCreatedSortIndicator.setText("");
            dateModifiedSortIndicator.setText("");
        }
    }

    private class ProjectWidgets {
        final CheckBox checkBox;
        final Label nameLabel;
        final Label dateCreatedLabel;
        final Label dateModifiedLabel;
        final Label publishedLabel;

        private ProjectWidgets(final Project project) {
            checkBox = new CheckBox();
            checkBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
                @Override
                public void onValueChange(ValueChangeEvent<Boolean> event) {
                    boolean isChecked = event.getValue(); // auto-unbox from Boolean to boolean
                    int row = 1 + projects.indexOf(project);
                    if (isChecked) {
                        table.getRowFormatter().setStyleName(row, "ode-ProjectRowHighlighted");
                        selectedProjects.add(project);
                    } else {
                        table.getRowFormatter().setStyleName(row, "ode-ProjectRowUnHighlighted");
                        selectedProjects.remove(project);
                    }
                    Ode.getInstance().getProjectToolbar().updateButtons();
                }
            });

            nameLabel = new Label(project.getProjectName());
            nameLabel.addClickHandler(new ClickHandler() {
                @Override
                public void onClick(ClickEvent event) {
                    Ode ode = Ode.getInstance();
                    if (ode.screensLocked()) {
                        return; // i/o in progress, ignore request
                    }
                    ode.openYoungAndroidProjectInDesigner(project);
                }
            });
            nameLabel.addStyleName("ode-ProjectNameLabel");

            DateTimeFormat dateTimeFormat = DateTimeFormat.getMediumDateTimeFormat();

            Date dateCreated = new Date(project.getDateCreated());
            dateCreatedLabel = new Label(dateTimeFormat.format(dateCreated));

            Date dateModified = new Date(project.getDateModified());
            dateModifiedLabel = new Label(dateTimeFormat.format(dateModified));

            publishedLabel = new Label();
        }
    }

    // TODO(user): This method was made public so it can be called
    // directly from from Ode when the Project List View is selected
    // from another view.  Ode now clears any selected projects and
    // calls this to refresh the table as a result. Not sure this is
    // correct thing do to. The alternative is to add a call to the
    // ProjectManagerEventListener interface that this is the
    // implementation of.
    public void refreshTable(boolean needToSort) {
        if (needToSort) {
            // Sort the projects.
            Comparator<Project> comparator;
            switch (sortField) {
            default:
            case NAME:
                comparator = (sortOrder == SortOrder.ASCENDING) ? ProjectComparators.COMPARE_BY_NAME_ASCENDING
                        : ProjectComparators.COMPARE_BY_NAME_DESCENDING;
                break;
            case DATE_CREATED:
                comparator = (sortOrder == SortOrder.ASCENDING)
                        ? ProjectComparators.COMPARE_BY_DATE_CREATED_ASCENDING
                        : ProjectComparators.COMPARE_BY_DATE_CREATED_DESCENDING;
                break;
            case DATE_MODIFIED:
                comparator = (sortOrder == SortOrder.ASCENDING)
                        ? ProjectComparators.COMPARE_BY_DATE_MODIFIED_ASCENDING
                        : ProjectComparators.COMPARE_BY_DATE_MODIFIED_DESCENDING;
                break;
            case PUBLISHED:
                comparator = (sortOrder == SortOrder.ASCENDING) ? ProjectComparators.COMPARE_BY_PUBLISHED_ASCENDING
                        : ProjectComparators.COMPARE_BY_PUBLISHED_DESCENDING;
                break;
            }
            Collections.sort(projects, comparator);
        }

        refreshSortIndicators();

        // Refill the table.
        table.resize(1 + projects.size(), 5);
        int row = 1;
        for (Project project : projects) {
            ProjectWidgets pw = projectWidgets.get(project);
            if (selectedProjects.contains(project)) {
                table.getRowFormatter().setStyleName(row, "ode-ProjectRowHighlighted");
                pw.checkBox.setValue(true);
            } else {
                table.getRowFormatter().setStyleName(row, "ode-ProjectRowUnHighlighted");
                pw.checkBox.setValue(false);
            }
            table.setWidget(row, 0, pw.checkBox);
            table.setWidget(row, 1, pw.nameLabel);
            table.setWidget(row, 2, pw.dateCreatedLabel);
            table.setWidget(row, 3, pw.dateModifiedLabel);
            table.setWidget(row, 4, pw.publishedLabel);
            if (Ode.getGallerySettings().galleryEnabled()) {
                if (project.isPublished()) {
                    pw.publishedLabel.setText(PUBLISHED);
                } else {
                    pw.publishedLabel.setText(NOT_PUBLISHED);
                }
            }

            row++;
        }

        Ode.getInstance().getProjectToolbar().updateButtons();
    }

    /**
     * Gets the number of projects
     *
     * @return the number of projects
     */
    public int getNumProjects() {
        return projects.size();
    }

    /**
     * Gets the number of selected projects
     *
     * @return the number of selected projects
     */
    public int getNumSelectedProjects() {
        return selectedProjects.size();
    }

    /**
     * Returns the list of selected projects
     *
     * @return the selected projects
     */
    public List<Project> getSelectedProjects() {
        return selectedProjects;
    }

    // ProjectManagerEventListener implementation

    @Override
    public void onProjectAdded(Project project) {
        projects.add(project);
        projectWidgets.put(project, new ProjectWidgets(project));
        refreshTable(true);
    }

    @Override
    public void onProjectRemoved(Project project) {
        projects.remove(project);
        projectWidgets.remove(project);

        refreshTable(false);

        selectedProjects.remove(project);
        Ode.getInstance().getProjectToolbar().updateButtons();
    }

    @Override
    public void onProjectsLoaded() {
        // This can be empty
    }

    public void onProjectPublishedOrUnpublished() {
        refreshTable(false);
    }

    public void setPublishedHeaderVisible(boolean visible) {
        table.getWidget(0, 4).setVisible(visible);
    }
}