com.google.gerrit.client.diff.CodeMirrorDemo.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gerrit.client.diff.CodeMirrorDemo.java

Source

// Copyright (C) 2013 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.google.gerrit.client.diff;

import com.google.gerrit.client.diff.DiffInfo.Region;
import com.google.gerrit.client.rpc.CallbackGroup;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.ScreenLoadCallback;
import com.google.gerrit.client.ui.Screen;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Window;

import net.codemirror.lib.CodeMirror;
import net.codemirror.lib.CodeMirror.LineClassWhere;
import net.codemirror.lib.Configuration;
import net.codemirror.lib.ModeInjector;

public class CodeMirrorDemo extends Screen {
    private static final int HEADER_FOOTER = 60 + 15 * 2 + 38;
    private final PatchSet.Id base;
    private final PatchSet.Id revision;
    private final String path;

    private DiffTable diffTable;
    private CodeMirror cmA;
    private CodeMirror cmB;
    private HandlerRegistration resizeHandler;

    public CodeMirrorDemo(PatchSet.Id base, PatchSet.Id revision, String path) {
        this.base = base;
        this.revision = revision;
        this.path = path;
    }

    @Override
    protected void onInitUI() {
        super.onInitUI();
        add(diffTable = new DiffTable());
    }

    @Override
    protected void onLoad() {
        super.onLoad();

        CallbackGroup group = new CallbackGroup();
        CodeMirror.initLibrary(group.add(new GerritCallback<Void>() {
            @Override
            public void onSuccess(Void result) {
            }
        }));
        DiffApi.diff(revision, path).base(base).wholeFile().ignoreWhitespace(DiffApi.IgnoreWhitespace.NONE)
                .get(group.add(new GerritCallback<DiffInfo>() {
                    @Override
                    public void onSuccess(final DiffInfo diff) {
                        new ModeInjector().add(getContentType(diff.meta_a())).add(getContentType(diff.meta_b()))
                                .inject(new ScreenLoadCallback<Void>(CodeMirrorDemo.this) {
                                    @Override
                                    protected void preDisplay(Void result) {
                                        display(diff);
                                    }
                                });
                    }
                }));
    }

    @Override
    public void onShowView() {
        super.onShowView();
        if (cmA != null) {
            cmA.refresh();
        }
        if (cmB != null) {
            cmB.refresh();
        }
    }

    @Override
    protected void onUnload() {
        super.onUnload();
        if (resizeHandler != null) {
            resizeHandler.removeHandler();
            resizeHandler = null;
        }
        if (cmA != null) {
            cmA.getWrapperElement().removeFromParent();
            cmA = null;
        }
        if (cmB != null) {
            cmB.getWrapperElement().removeFromParent();
            cmB = null;
        }
    }

    private void display(DiffInfo diff) {
        cmA = displaySide(diff.meta_a(), diff.text_a(), diffTable.getCmA());
        cmB = displaySide(diff.meta_b(), diff.text_b(), diffTable.getCmB());
        render(diff);
        resizeHandler = Window.addResizeHandler(new ResizeHandler() {
            @Override
            public void onResize(ResizeEvent event) {
                if (cmA != null) {
                    cmA.setHeight(event.getHeight() - HEADER_FOOTER);
                    cmA.refresh();
                }
                if (cmB != null) {
                    cmB.setHeight(event.getHeight() - HEADER_FOOTER);
                    cmB.refresh();
                }
            }
        });
    }

    private CodeMirror displaySide(DiffInfo.FileMeta meta, String contents, Element ele) {
        if (meta == null) {
            contents = "";
        }
        Configuration cfg = Configuration.create().set("readOnly", true).set("lineNumbers", true).set("tabSize", 2)
                .set("mode", getContentType(meta)).set("value", contents).setInfinity("viewportMargin");
        final CodeMirror cm = CodeMirror.create(ele, cfg);
        cm.setWidth("100%");
        cm.setHeight(Window.getClientHeight() - HEADER_FOOTER);
        return cm;
    }

    private void render(DiffInfo diff) {
        JsArray<Region> regions = diff.content();
        int lineA = 0, lineB = 0;
        for (int i = 0; i < regions.length(); i++) {
            Region current = regions.get(i);
            if (current.ab() != null) {
                lineA += current.ab().length();
                lineB += current.ab().length();
            } else if (current.a() == null && current.b() != null) {
                int delta = current.b().length();
                insertEmptyLines(cmA, lineA, delta);
                lineB = colorLines(cmB, lineB, delta);
            } else if (current.a() != null && current.b() == null) {
                int delta = current.a().length();
                insertEmptyLines(cmB, lineB, delta);
                lineA = colorLines(cmA, lineA, delta);
            } else { // TODO: Implement intraline
                int aLength = current.a().length();
                int bLength = current.b().length();
                lineA = colorLines(cmA, lineA, aLength);
                lineB = colorLines(cmB, lineB, bLength);
                if (aLength < bLength) {
                    insertEmptyLines(cmA, lineA, bLength - aLength);
                } else if (aLength > bLength) {
                    insertEmptyLines(cmB, lineB, aLength - bLength);
                }
            }
        }
    }

    private void insertEmptyLines(CodeMirror cm, int line, int cnt) {
        Element div = DOM.createDiv();
        div.setClassName(diffTable.style.padding());
        div.getStyle().setHeight(cnt, Unit.EM);
        Configuration config = Configuration.create().set("coverGutter", true).set("above", line == 0);
        cm.addLineWidget(line == 0 ? 0 : (line - 1), div, config);
    }

    private int colorLines(CodeMirror cm, int line, int cnt) {
        for (int i = 0; i < cnt; i++) {
            cm.addLineClass(line + i, LineClassWhere.WRAP, diffTable.style.diff());
        }
        return line + cnt;
    }

    private static String getContentType(DiffInfo.FileMeta meta) {
        return meta != null && meta.content_type() != null ? ModeInjector.getContentType(meta.content_type())
                : null;
    }
}