cl.uai.client.marks.Mark.java Source code

Java tutorial

Introduction

Here is the source code for cl.uai.client.marks.Mark.java

Source

// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * @package   eMarking
 * @copyright 2013 Jorge Villaln <villalon@gmail.com>
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
package cl.uai.client.marks;

import java.util.ArrayList;
import java.util.Map;
import java.util.logging.Logger;

import cl.uai.client.EMarkingConfiguration;
import cl.uai.client.EMarkingWeb;
import cl.uai.client.MarkingInterface;
import cl.uai.client.data.AjaxData;
import cl.uai.client.data.AjaxRequest;
import cl.uai.client.feedback.FeedbackObject;
import cl.uai.client.page.EditIcon;
import cl.uai.client.page.EditMarkDialog;
import cl.uai.client.page.EditMarkMenu;
import cl.uai.client.page.LoadingIcon;
import cl.uai.client.page.MarkPopup;
import cl.uai.client.page.MarkingPage;
import cl.uai.client.page.MinimizeIcon;
import cl.uai.client.page.RegradeIcon;
import cl.uai.client.page.TrashIcon;
import cl.uai.client.resources.Resources;
import cl.uai.client.utils.Color;

import com.github.gwtbootstrap.client.ui.Icon;
import com.github.gwtbootstrap.client.ui.constants.IconType;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.ContextMenuEvent;
import com.google.gwt.event.dom.client.ContextMenuHandler;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.http.client.URL;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.PopupPanel;

/**
 * The most basic mark a page can include
 * 
 * @author Jorge Villaln <villalon@gmail.com>
 *
 */
public abstract class Mark extends HTML implements ContextMenuHandler, ClickHandler {

    /** For logging purposes **/
    protected static Logger logger = Logger.getLogger(Mark.class.getName());

    /** The delete icon **/
    protected static TrashIcon deleteIcon = null;

    /** Criterion to which this mark is associated (if any) **/
    protected int criterionid = 0;

    protected ArrayList<FeedbackObject> feedback;

    static {
        deleteIcon = new TrashIcon();
    }

    public int getCriterionId() {
        return criterionid;
    }

    /** The regrade icon **/
    protected static RegradeIcon regradeIcon = null;

    protected boolean iconOnly = false;

    protected IconType iconType = null;

    static {
        regradeIcon = new RegradeIcon();
    }

    /** The edit icon **/
    protected static EditIcon editIcon = null;

    static {
        editIcon = new EditIcon();
    }

    /** The minimize icon **/
    protected static MinimizeIcon minimizeIcon = null;

    static {
        minimizeIcon = new MinimizeIcon();
    }

    public static LoadingIcon loadingIcon = null;
    static {
        loadingIcon = new LoadingIcon();
    }

    public static MarkPopup markPopup = null;
    static {
        markPopup = new MarkPopup();
    }

    /**
     * Hides all icons
     */
    public static void hideIcons() {
        deleteIcon.setVisible(false);
        editIcon.setVisible(false);
        regradeIcon.setVisible(false);
        minimizeIcon.setVisible(false);
        markPopup.setVisible(false);
    }

    public static void showIcons(Mark mark, int mouseLeft) {
        // Gets the absolute panel which contains the mark to calculate its coordinates
        AbsolutePanel abspanel = (AbsolutePanel) mark.getParent();

        int topdiff = -Mark.editIcon.getOffsetHeight();

        // Calculates basic left, top position for icons
        int top = mark.getAbsoluteTop() - abspanel.getAbsoluteTop() + (topdiff);
        int left = mouseLeft > 0 && mark instanceof HighlightMark ? mouseLeft : mark.getAbsoluteLeft();

        if (top < 0) {
            top += mark.getOffsetHeight();
        }
        // Check if icons and popup are already added in the panel, if not adds them
        if (abspanel.getWidgetIndex(Mark.editIcon) < 0)
            abspanel.add(Mark.editIcon, left, top);

        if (abspanel.getWidgetIndex(Mark.deleteIcon) < 0)
            abspanel.add(Mark.deleteIcon, left, top);

        if (abspanel.getWidgetIndex(Mark.regradeIcon) < 0)
            abspanel.add(Mark.regradeIcon, left, top);

        if (abspanel.getWidgetIndex(Mark.minimizeIcon) < 0)
            abspanel.add(Mark.minimizeIcon, left, top);

        if (abspanel.getWidgetIndex(Mark.markPopup) < 0)
            abspanel.add(Mark.markPopup, left, top);

        // Make sure no other icons are left
        Mark.hideIcons();

        // If we are in grading mode, show delete and edit icons
        if (!EMarkingConfiguration.isReadonly()) {

            // Edit icon is only for comments and rubrics
            abspanel.setWidgetPosition(Mark.editIcon, left, top);
            Mark.editIcon.setVisible(true);
            Mark.editIcon.setMark(mark);
            left += Mark.editIcon.getOffsetWidth() + 5;
            top -= 1;

            // Delete icon
            abspanel.setWidgetPosition(Mark.deleteIcon, left, top);
            Mark.deleteIcon.setVisible(true);
            Mark.deleteIcon.setMark(mark);
        }

        // If the user owns the submission and the dates are ok we show the regrade icon
        if (EMarkingConfiguration.isOwnDraft() && MarkingInterface.submissionData.isRegradingAllowed()
                && !EMarkingConfiguration.isFormativeFeedbackOnly()) {
            // Edit icon is only for comments and rubrics
            if (mark instanceof RubricMark) {
                abspanel.setWidgetPosition(Mark.regradeIcon, left, top);
                Mark.regradeIcon.setVisible(true);
                Mark.regradeIcon.setMark(mark);
            }
        }

        // Highlight the rubric interface if the mark is a RubricMark
        if (EMarkingConfiguration.getRubricMarkType() != EMarkingConfiguration.EMARKING_RUBRICMARK_TEXTBOX) {
            Mark.markPopup.setHTML(mark.getMarkPopupHTML());
            Mark.markPopup.setVisible(true);
            top += 50;
            abspanel.setWidgetPosition(Mark.markPopup, left, top);
            EMarkingWeb.reloadMathJax();
        }
    }

    public void setPosx(int posx) {
        this.posx = posx;
    }

    public void setPosy(int posy) {
        this.posy = posy;
    }

    protected String getMarkPopupHTML() {
        String html = "";
        if (this.getRawtext() != null && this.getRawtext().length() > 0) {
            html += "<div class=\"" + Resources.INSTANCE.css().markrawtext() + "\">"
                    + SafeHtmlUtils.htmlEscape(this.getRawtext()) + "</div>";
        }
        // Show the marker's name if the marking process is not anonymous
        if (!EMarkingConfiguration.isMarkerAnonymous()) {
            html += "<div class=\"" + Resources.INSTANCE.css().markmarkername() + "\">" + markername + "</div>";
        }
        return html;
    }

    protected static EditMarkMenu editMenu = null;

    /** A mark id, corresponding to emarking_comment table in Moodle **/
    protected int id = -1;

    /** The mark position in the page **/
    protected int posx = -1;
    protected int posy = -1;

    protected int width = 140;
    protected int height = 100;
    /** The mark inner comment **/
    protected String rawtext = "";
    /** The mark page number **/
    protected int pageno = 0;
    /** The marker id and name **/
    protected int markerid = 0;
    protected String markername = "";
    /** The mark format, as there is no OO in the DB. 1 is Mark **/
    protected int format = 1;

    protected String previousText = "";

    private long timecreated;

    /**
     * @return the pageno
     */
    public int getPageno() {
        return pageno;
    }

    /**
     * Creates a Mark object at a specific position in a page
     * @param posx X coordinate in the page
     * @param posy Y coordinate in the page
     * @param pageno the page number (1 to N)
     */
    public Mark(int id, int posx, int posy, int pageno, int markerId, long timecreated, int criterionid,
            String markername, String rawtext) {
        this.markerid = markerId;
        this.posx = posx;
        this.posy = posy;
        this.pageno = pageno;
        this.timecreated = timecreated;
        this.criterionid = criterionid;
        this.markername = markername;
        this.rawtext = rawtext;
        this.id = id;

        this.addStyleName(Resources.INSTANCE.css().mark());

        this.addHandlers();
        feedback = new ArrayList<FeedbackObject>();
    }

    protected void addHandlers() {
        this.addMouseOverHandler(new MarkOnMouseOverHandler());
        this.addMouseOutHandler(new MarkOnMouseOutHandler());
        this.addDomHandler(this, ContextMenuEvent.getType());
        this.addDomHandler(this, ClickEvent.getType());
    }

    /**
     * @return the format
     */
    public int getFormat() {
        return format;
    }

    /**
     * @return the id
     */
    public int getId() {
        return id;
    }

    /**
     * @return the markername
     */
    public String getMarkername() {
        return markername;
    }

    /**
     * @return the posx
     */
    public int getPosx() {
        return posx;
    }

    /**
     * @return the posy
     */
    public int getPosy() {
        return posy;
    }

    /**
     * @return the rawtext of the mark
     */
    public String getRawtext() {
        return rawtext;
    }

    @Override
    protected void onLoad() {
        super.onLoad();
        this.setMarkHTML();
    }

    /**
     * Sets the inner HTML according to an icon
     */
    public void setMarkHTML() {

        // Starts with an empty HTML
        String html = "";
        String iconhtml = "";

        // Create the icon string if any
        if (this.iconType != null) {
            Icon icon = new Icon(this.iconType);
            iconhtml = icon.toString();
        } else if (this.iconOnly && this instanceof CustomMark) {
            CustomMark cmark = (CustomMark) this;
            iconhtml = cmark.getTitle();
        }

        String markername = EMarkingConfiguration.isMarkerAnonymous()
                ? MarkingInterface.messages.MarkerDetails(MarkingInterface.messages.Anonymous())
                : MarkingInterface.messages.MarkerDetails(this.getMarkername());
        String styleColor = "";

        // If the mark has a color, we use the background to color it
        if (this.criterionid > 0 && this.iconOnly) {
            styleColor = "style=\"color:" + Color.getCSSHueColor(criterionid) + "\"";
        }

        html += "<div class=\"" + Resources.INSTANCE.css().markicon() + "\" title=\"" + markername + "\" "
                + styleColor + ">" + iconhtml + "</div>";
        // If the mark is an icon
        if ((!this.iconOnly
                || EMarkingConfiguration.getRubricMarkType() == EMarkingConfiguration.EMARKING_RUBRICMARK_TEXTBOX)
                && this.getRawtext().trim().length() > 0) {
            html += "<div class=\"" + Resources.INSTANCE.css().markrawtext() + "\">"
                    + SafeHtmlUtils.htmlEscape(this.getRawtext()) + "</div>";
            // Show the marker's name if the marking process is not anonymous
            if (!EMarkingConfiguration.isMarkerAnonymous()) {
                html += "<div class=\"" + Resources.INSTANCE.css().markmarkername() + "\">" + markername + "</div>";
            }
        }

        this.removeStyleName(Resources.INSTANCE.css().rubricmarkpopup());
        if (EMarkingConfiguration.getRubricMarkType() == EMarkingConfiguration.EMARKING_RUBRICMARK_TEXTBOX) {
            this.addStyleName(Resources.INSTANCE.css().rubricmarkpopup());
        }
        this.setHTML(html);
    }

    /**
     * @param id the id to set
     */
    public void setId(int id) {
        this.id = id;
    }

    /**
     * Changes its inner HTML while it is loading
     */
    protected void setLoading() {
        Icon icon = new Icon(IconType.COG);
        icon.addStyleName("icon-spin");
        icon.addStyleName(Resources.INSTANCE.css().iconupdating());
        this.setHTML(
                "<div class=\"" + Resources.INSTANCE.css().innercomment() + "\">" + icon.toString() + "</div>");
        this.addStyleName(Resources.INSTANCE.css().updating());
    }

    /**
     * @param markerid the markerid to set
     */
    public void setMarkerid(int markerid) {
        this.markerid = markerid;
    }

    /**
     * @param markername the markername to set
     */
    public void setMarkername(String markername) {
        this.markername = markername;
    }

    /**
     * @param rawtext the rawtext to set
     */
    public void setRawtext(String rawtext) {
        this.rawtext = rawtext;
    }

    /**
     * Updates a mark's comment, position or bonus
     * 
     * @param newcomment the new comment
     * @param newposx the new X coordinate in the page
     * @param newposy the new Y coordinate in the page
     * @param newbonus the new bonus
     */
    public void update(final String newcomment, int newposx, int newposy, final int newlevel, final float newbonus,
            final String newregrademarkercomment, final int newregradeaccepted, int widthPage, int heightPage) {

        final Mark mark = this;

        int regradeid = 0;
        if (mark instanceof RubricMark)
            regradeid = ((RubricMark) mark).getRegradeid();

        // This shouldn't happen so log it for debugging
        if (this.id == 0) {
            logger.severe("Fatal error! A comment with id 0!");
            return;
        }

        EMarkingWeb.markingInterface.addLoading(true);

        this.setLoading();

        final String feedbackToAjax;
        if (feedback.size() > 0) {
            feedbackToAjax = getFeedbackToAjax();
        } else {
            feedbackToAjax = "";
        }
        logger.severe(feedbackToAjax);
        // Call the ajax request to update the data
        AjaxRequest.ajaxRequest("action=updcomment&cid=" + this.id + "&posx=" + newposx + "&posy=" + newposy
                + "&bonus=" + newbonus + "&format=" + this.format + "&levelid=" + newlevel + "&regradeid="
                + regradeid + "&regradeaccepted=" + newregradeaccepted + "&regrademarkercomment="
                + newregrademarkercomment + "&markerid=" + EMarkingConfiguration.getMarkerId() + "&width="
                + this.width + "&height=" + this.height + "&comment=" + URL.encode(newcomment) + "&windowswidth="
                + widthPage + "&windowsheight=" + heightPage + "&feedback=" + URL.encode(feedbackToAjax),
                new AsyncCallback<AjaxData>() {

                    @Override
                    public void onFailure(Throwable caught) {
                        logger.severe("Error updating mark to Moodle!");
                        logger.severe(caught.getMessage());
                        Window.alert(caught.getMessage());
                        EMarkingWeb.markingInterface.finishLoading();
                    }

                    @Override
                    public void onSuccess(AjaxData result) {
                        Map<String, String> value = AjaxRequest.getValueFromResult(result);

                        if (!result.getError().equals("")) {
                            Window.alert(result.getError());
                            setMarkHTML();
                            removeStyleName(Resources.INSTANCE.css().updating());
                            EMarkingWeb.markingInterface.finishLoading();
                            return;
                        }

                        // Parse json values from Moodle
                        long timemodified = Long.parseLong(value.get("timemodified"));
                        float newgrade = Float.parseFloat(value.get("newgrade"));
                        mark.setPreviousText(mark.getRawtext());
                        mark.setRawtext(newcomment);

                        if (mark instanceof RubricMark) {
                            RubricMark rmark = (RubricMark) mark;
                            // Update submission data
                            int previousLevelid = rmark.getLevelId();
                            float previousBonus = rmark.getBonus();
                            rmark.setLevelId(newlevel);
                            rmark.setBonus(newbonus);
                            rmark.setRegradeaccepted(newregradeaccepted);
                            rmark.setRegrademarkercomment(newregrademarkercomment);
                            if (rmark.getLevelId() != previousLevelid || rmark.getBonus() != previousBonus) {
                                rmark.setMarkername(MarkingInterface.submissionData.getMarkerfirstname() + " "
                                        + MarkingInterface.submissionData.getMarkerlastname());
                                rmark.setMarkerid(MarkingInterface.submissionData.getMarkerid());
                                Mark.showIcons(rmark, 0);
                            }
                            EMarkingWeb.markingInterface.getRubricInterface().getRubricPanel()
                                    .addMarkToRubric(rmark);
                            EMarkingWeb.markingInterface.getRubricInterface().getRubricPanel()
                                    .finishloadingRubricCriterion(newlevel);
                        }

                        // Update the marking interface with the final grade and time
                        EMarkingWeb.markingInterface.setFinalgrade(newgrade, timemodified);
                        setMarkHTML();

                        EMarkingWeb.markingInterface.getRubricInterface().getToolsPanel().getPreviousComments()
                                .addMarkAsCommentToInterface(mark, true);

                        removeStyleName(Resources.INSTANCE.css().updating());

                        EMarkingWeb.markingInterface.finishLoading();
                    }
                });
    }

    public void updateMark(int posx, int posy) {
        // Edit works for both comment and rubric marks only
        final Mark mark = (Mark) this;

        // If the mark is a rubric get its level
        int level = 0;
        int regradeid = 0;
        if (mark instanceof RubricMark) {
            regradeid = ((RubricMark) mark).getRegradeid();
            level = ((RubricMark) mark).getLevelId();
        }

        // Create the comment dialog with the corresponding rubric level
        EditMarkDialog dialog = new EditMarkDialog(posx, posy, level, regradeid);

        if (mark instanceof RubricMark && regradeid > 0) {
            dialog.getTxtRegradeComment().setText(((RubricMark) mark).getRegrademarkercomment());
        }

        if (feedback.size() > 0) {
            dialog.setFeedbackArray(feedback, id);
            dialog.loadFeedback();
        }

        // Set dialog's current values to the mark's
        dialog.setTxtComment(mark.getRawtext());

        // Update when closing
        dialog.addCloseHandler(new CloseHandler<PopupPanel>() {
            @Override
            public void onClose(CloseEvent<PopupPanel> event) {
                EditMarkDialog dialog = (EditMarkDialog) event.getSource();

                MarkingPage page = EMarkingWeb.markingInterface.getMarkingPagesInterface()
                        .getPageByIndex(pageno - 1);
                int widthPage = page.getWidth();
                int heightPage = page.getHeight();
                // If the dialog was not cancelled update the mark with the dialog values
                if (!dialog.isCancelled()) {
                    // mark.setFeedback(dialog.getFeedbackArray());
                    mark.update(dialog.getTxtComment(), mark.getPosx(), mark.getPosy(), dialog.getLevelId(),
                            dialog.getBonus(), dialog.getRegradeComment(), dialog.getRegradeAccepted(), widthPage,
                            heightPage);
                }
            }
        });

        // Show the dialog
        dialog.center();
    }

    protected void setPreviousText(String text) {
        this.previousText = text;

    }

    public int getWidth() {
        return this.width;
    }

    public int getHeight() {
        return this.height;
    }

    public String getPreviousText() {
        return this.previousText;
    }

    public int getMarkerId() {
        return markerid;
    }

    public long getTimeCreated() {
        return timecreated;
    }

    public void setTimeCreated(long timecreated) {
        this.timecreated = timecreated;
    }

    @Override
    public void onContextMenu(ContextMenuEvent event) {
        if (EMarkingConfiguration.isReadonly()) {
            return;
        }
        event.getNativeEvent().stopPropagation();
        event.getNativeEvent().preventDefault();

        editMenu = new EditMarkMenu(this, event.getNativeEvent().getClientX(), event.getNativeEvent().getClientY());
        editMenu.show();
    }

    @Override
    public void onClick(ClickEvent event) {
        event.stopPropagation();
    }

    public ArrayList<FeedbackObject> getFeedback() {
        return feedback;
    }

    public void setFeedback(ArrayList<FeedbackObject> newfeedback) {
        feedback = newfeedback;
    }

    protected String getFeedbackToAjax() {
        JSONObject outputFeedback = new JSONObject();
        for (int iterator = 0; iterator < feedback.size(); iterator++) {
            JSONArray array = new JSONArray();
            array.set(0, new JSONString(feedback.get(iterator).getNameOER().replaceAll("\\<.*?>", "")));
            array.set(1, new JSONString(feedback.get(iterator).getName().replaceAll("\\<.*?>", "")));
            array.set(2, new JSONString(feedback.get(iterator).getLink()));

            outputFeedback.put(Integer.toString(iterator), array);
        }
        return outputFeedback.toString();
    }
}