com.googlesource.gerrit.plugins.xdocs.client.XDocDiffScreen.java Source code

Java tutorial

Introduction

Here is the source code for com.googlesource.gerrit.plugins.xdocs.client.XDocDiffScreen.java

Source

// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.googlesource.gerrit.plugins.xdocs.client;

import com.google.gerrit.client.rpc.NativeMap;
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.plugin.client.Plugin;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.InlineHTML;
import com.google.gwt.user.client.ui.InlineHyperlink;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;

import com.googlesource.gerrit.plugins.xdocs.client.ChangeInfo.EditInfo;
import com.googlesource.gerrit.plugins.xdocs.client.ChangeInfo.RevisionInfo;

import java.util.List;

public abstract class XDocDiffScreen extends VerticalPanel {
    protected final String changeId;
    protected final String path;
    protected String revisionA;
    protected String revisionB;
    protected int patchSet;
    protected Integer base;
    private FlowPanel iconPanel;
    private FlowPanel additionalIconPanel;

    XDocDiffScreen(String changeId, final String patchSet, String path) {
        setStyleName("xdocs-panel");

        this.changeId = changeId;
        this.path = path;

        ChangeApi.getChangeInfo(changeId, new AsyncCallback<ChangeInfo>() {

            @Override
            public void onSuccess(final ChangeInfo change) {
                change.revisions().copyKeysIntoChildren("name");
                if (Plugin.get().isSignedIn()) {
                    ChangeApi.edit(change._number(), new AsyncCallback<EditInfo>() {
                        @Override
                        public void onSuccess(EditInfo edit) {
                            if (edit != null) {
                                change.set_edit(edit);
                                change.revisions().put(edit.name(), RevisionInfo.fromEdit(edit));
                            }
                            initRevisionsAndShow(change);
                        }

                        @Override
                        public void onFailure(Throwable caught) {
                            // never invoked
                        }
                    });
                } else {
                    initRevisionsAndShow(change);
                }
            }

            private void initRevisionsAndShow(final ChangeInfo change) {
                parseRevisions(change, patchSet);
                if (revisionA == null) {
                    ProjectApi.getCommitInfo(change.project(), change.current_revision(),
                            new AsyncCallback<CommitInfo>() {
                                @Override
                                public void onSuccess(CommitInfo commit) {
                                    if (commit.parents() != null) {
                                        List<CommitInfo> parents = Natives.asList(commit.parents());
                                        if (!parents.isEmpty()) {
                                            revisionA = parents.get(0).commit();
                                        }
                                    }
                                    show(change);
                                }

                                @Override
                                public void onFailure(Throwable caught) {
                                    // never invoked
                                }
                            });
                } else {
                    show(change);
                }
            }

            private void show(ChangeInfo change) {
                addHeader(change);
                init();
                display(change);
            }

            @Override
            public void onFailure(Throwable caught) {
                showError("Unable to load change " + XDocDiffScreen.this.changeId + ": " + caught.getMessage());
            }
        });
    }

    protected abstract void display(ChangeInfo change);

    protected String getPath() {
        return path;
    }

    protected String getRevisionA() {
        return revisionA;
    }

    protected String getRevisionB() {
        return revisionB;
    }

    private void parseRevisions(ChangeInfo change, String patchSetString) {
        int i = patchSetString.indexOf("..");
        if (i > 0) {
            base = parsePatchSet(patchSetString.substring(0, i));
            revisionA = getRevision(change, base);
            if (patchSetString.length() > i + 2) {
                patchSet = parsePatchSet(patchSetString.substring(i + 2));
                revisionB = getRevision(change, patchSet);
            } else {
                throw new IllegalArgumentException("Invalid patch set: " + patchSetString);
            }
        } else {
            patchSet = parsePatchSet(patchSetString);
            revisionB = getRevision(change, patchSet);
        }
    }

    private static String getRevision(ChangeInfo change, int patchSet) {
        for (RevisionInfo rev : Natives.asList(change.revisions().values())) {
            if (rev.is_edit()) {
                return rev.commit().commit();
            }
            if (rev._number() == patchSet) {
                return rev.ref();
            }
        }
        throw new IllegalArgumentException("Patch set " + patchSet + " not found.");
    }

    private static int parsePatchSet(String patchSet) {
        try {
            return Integer.valueOf(patchSet);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Invalid patch set: " + patchSet);
        }
    }

    private void addHeader(ChangeInfo change) {
        HorizontalPanel p = new HorizontalPanel();
        p.setStyleName("xdocs-header");
        p.add(getPathHeader(change));

        iconPanel = new FlowPanel();
        iconPanel.setStyleName("xdocs-icon-panel");
        p.add(iconPanel);
        additionalIconPanel = new FlowPanel();
        iconPanel.add(additionalIconPanel);
        addNavigationButtons(change);

        add(p);
    }

    protected void init() {
    }

    private Widget getPathHeader(ChangeInfo change) {
        HorizontalPanel p = new HorizontalPanel();
        p.setStyleName("xdocs-file-header");
        p.add(new InlineHyperlink(change.project(), "/admin/projects/" + change.project()));
        p.add(new Label("/"));

        SafeHtmlBuilder html = new SafeHtmlBuilder();
        if (FileInfo.COMMIT_MSG.equals(path)) {
            html.append("Commit Message");
        } else {
            int s = path.lastIndexOf('/') + 1;
            html.append(path.substring(0, s));
            html.openElement("b");
            html.append(path.substring(s));
            html.closeElement("b");
        }
        p.add(new InlineHTML(html.toSafeHtml()));

        return p;
    }

    private void addNavigationButtons(final ChangeInfo change) {
        DiffApi.list(changeId, patchSet, base, new AsyncCallback<NativeMap<FileInfo>>() {
            @Override
            public void onSuccess(NativeMap<FileInfo> result) {
                JsArray<FileInfo> files = result.values();
                FileInfo.sortFileInfoByPath(files);
                int index = 0;
                for (int i = 0; i < files.length(); i++) {
                    if (path.equals(files.get(i).path())) {
                        index = i;
                        break;
                    }
                }

                FileInfo prevInfo = index == 0 ? null : files.get(index - 1);
                if (prevInfo != null) {
                    iconPanel.add(createNavLink(XDocsPlugin.RESOURCES.goPrev(), change, patchSet, base, prevInfo));
                }

                iconPanel.add(createIcon(XDocsPlugin.RESOURCES.goUp(), "Up to change", toChange(change)));

                FileInfo nextInfo = index == files.length() - 1 ? null : files.get(index + 1);
                if (nextInfo != null) {
                    iconPanel.add(createNavLink(XDocsPlugin.RESOURCES.goNext(), change, patchSet, base, nextInfo));
                }
            }

            @Override
            public void onFailure(Throwable caught) {
                showError("Unable to load files of change " + changeId + ": " + caught.getMessage());
            }
        });
    }

    private InlineHyperlink createNavLink(ImageResource res, final ChangeInfo change, final int patchSet,
            final Integer base, final FileInfo file) {
        final InlineHyperlink link = createIcon(res, FileInfo.getFileName(file.path()),
                toFile(change, patchSet, base, file));
        XDocApi.checkHtml(XDocApi.getUrl(change.project(), getRevision(change, patchSet), file.path()),
                new AsyncCallback<VoidResult>() {
                    @Override
                    public void onSuccess(VoidResult result) {
                        link.setTargetHistoryToken(toPreview(change, patchSet, base, file));
                    }

                    @Override
                    public void onFailure(Throwable caught) {
                    }
                });
        return link;
    }

    protected static InlineHyperlink createIcon(ImageResource res, String tooltip, String target) {
        InlineHyperlink l = new InlineHyperlink(AbstractImagePrototype.create(res).getHTML(), true, target);
        if (tooltip != null) {
            l.setTitle(tooltip);
        }
        return l;
    }

    protected void addIcon(InlineHyperlink icon) {
        additionalIconPanel.add(icon);
    }

    private String toPreview(ChangeInfo change, int patchSet, Integer base, FileInfo file) {
        String panel = getPanel();
        return "/x/" + Plugin.get().getName() + toPatchSet(change, patchSet, base) + file.path()
                + (panel != null ? "," + panel : "");
    }

    private String toFile(ChangeInfo change, int patchSet, Integer base, FileInfo file) {
        String panel = file.binary() ? "unified" : getPanel();
        return toPatchSet(change, patchSet, base) + file.path() + (panel != null ? "," + panel : "");
    }

    protected String getPanel() {
        return null;
    }

    private static String toPatchSet(ChangeInfo change, int patchSet, Integer base) {
        return toChange(change) + (base != null ? patchSet + ".." + base : patchSet) + "/";
    }

    private static String toChange(ChangeInfo change) {
        return "/c/" + change._number() + "/";
    }

    protected void showError(String message) {
        Label l = new Label(message);
        l.setStyleName("xdocs-error");
        add(l);
    }

    protected static int addRow(FlexTable table) {
        int row = table.getRowCount();
        table.insertRow(row);
        return row;
    }
}