InlineEdit: Allow to save/load user preferences in Codemirror

Change-Id: Ice334364cdb952eaa93118362c438dcc291db2af
This commit is contained in:
David Ostrovsky 2014-11-15 23:18:48 +01:00
parent 0ca0182ab8
commit 8018fbbc1e
9 changed files with 707 additions and 15 deletions

View File

@ -154,11 +154,6 @@ Alternatively change edits can be accessed through "My => Edits" dashboard.
[[not-implemented-features]]
== Not Implemented Features
* [PENDING CHANGE]
The inline editor uses settings decided from the user's diff preferences, but those
preferences are only modifiable from the side-by-side diff screen. It should be possible
to open the preferences also from within the editor.
* Support default configuration options for inline editor that an
administrator has set in `refs/users/default:preferences.config` file.

View File

@ -46,6 +46,7 @@ import com.google.gerrit.client.ui.Screen;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.common.data.HostPageData;
import com.google.gerrit.common.data.SystemInfoService;
import com.google.gerrit.extensions.client.EditPreferencesInfo;
import com.google.gerrit.extensions.client.GerritTopMenu;
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
import com.google.gerrit.reviewdb.client.Project;
@ -118,6 +119,7 @@ public class Gerrit implements EntryPoint {
private static HostPageData.Theme myTheme;
private static String defaultScreenToken;
private static AccountDiffPreference myAccountDiffPref;
private static EditPreferencesInfo editPrefs;
private static String xGerritAuth;
private static boolean isNoteDbEnabled;
@ -327,6 +329,14 @@ public class Gerrit implements EntryPoint {
myAccountDiffPref = accountDiffPref;
}
public static EditPreferencesInfo getEditPreferences() {
return editPrefs;
}
public static void setEditPreferences(EditPreferencesInfo p) {
editPrefs = p;
}
/** @return true if the user is currently authenticated */
public static boolean isSignedIn() {
return xGerritAuth != null;

View File

@ -37,6 +37,17 @@ public class AccountApi {
return new RestApi("/accounts/").view("self");
}
/** Retrieve the account edit preferences */
public static void getEditPreferences(AsyncCallback<EditPreferences> cb) {
self().view("preferences.edit").get(cb);
}
/** Put the account edit preferences */
public static void putEditPreferences(EditPreferences in,
AsyncCallback<VoidResult> cb) {
self().view("preferences.edit").put(in, cb);
}
public static void suggest(String query, int limit,
AsyncCallback<JsArray<AccountInfo>> cb) {
new RestApi("/accounts/")

View File

@ -0,0 +1,76 @@
// 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.google.gerrit.client.account;
import com.google.gerrit.extensions.client.EditPreferencesInfo;
import com.google.gerrit.extensions.client.Theme;
import com.google.gwt.core.client.JavaScriptObject;
public class EditPreferences extends JavaScriptObject {
public static EditPreferences create(EditPreferencesInfo in) {
EditPreferences p = createObject().cast();
p.tabSize(in.tabSize);
p.lineLength(in.lineLength);
p.hideTopMenu(in.hideTopMenu);
p.showTabs(in.showTabs);
p.showWhitespaceErrors(in.showWhitespaceErrors);
p.syntaxHighlighting(in.syntaxHighlighting);
p.hideLineNumbers(in.hideLineNumbers);
p.theme(in.theme);
return p;
}
public final void copyTo(EditPreferencesInfo p) {
p.tabSize = tabSize();
p.lineLength = lineLength();
p.hideTopMenu = hideTopMenu();
p.showTabs = showTabs();
p.showWhitespaceErrors = showWhitespaceErrors();
p.syntaxHighlighting = syntaxHighlighting();
p.hideLineNumbers = hideLineNumbers();
p.theme = theme();
}
public final void theme(Theme i) {
setThemeRaw(i != null ? i.toString() : Theme.DEFAULT.toString());
}
private final native void setThemeRaw(String i) /*-{ this.theme = i }-*/;
public final native void tabSize(int t) /*-{ this.tab_size = t }-*/;
public final native void lineLength(int c) /*-{ this.line_length = c }-*/;
public final native void hideTopMenu(boolean s) /*-{ this.hide_top_menu = s }-*/;
public final native void showTabs(boolean s) /*-{ this.show_tabs = s }-*/;
public final native void showWhitespaceErrors(boolean s) /*-{ this.show_whitespace_errors = s }-*/;
public final native void syntaxHighlighting(boolean s) /*-{ this.syntax_highlighting = s }-*/;
public final native void hideLineNumbers(boolean s) /*-{ this.hide_line_numbers = s }-*/;
public final Theme theme() {
String s = themeRaw();
return s != null ? Theme.valueOf(s) : Theme.DEFAULT;
}
private final native String themeRaw() /*-{ return this.theme }-*/;
public final int tabSize() {return get("tab_size", 8); }
public final int lineLength() {return get("line_length", 100); }
public final native boolean hideTopMenu() /*-{ return this.hide_top_menu || false }-*/;
public final native boolean showTabs() /*-{ return this.show_tabs || false }-*/;
public final native boolean showWhitespaceErrors() /*-{ return this.show_whitespace_errors || false }-*/;
public final native boolean syntaxHighlighting() /*-{ return this.syntax_highlighting || false }-*/;
public final native boolean hideLineNumbers() /*-{ return this.hide_line_numbers || false }-*/;
private final native int get(String n, int d) /*-{ return this.hasOwnProperty(n) ? this[n] : d }-*/;
protected EditPreferences() {
}
}

View File

@ -0,0 +1,69 @@
// 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.google.gerrit.client.editor;
import com.google.gerrit.client.account.EditPreferences;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
class EditPreferencesAction {
private final EditScreen view;
private final EditPreferences prefs;
private PopupPanel popup;
private EditPreferencesBox current;
EditPreferencesAction(EditScreen view, EditPreferences prefs) {
this.view = view;
this.prefs = prefs;
}
void show() {
if (popup != null) {
hide();
return;
}
current = new EditPreferencesBox(view);
current.set(prefs);
popup = new PopupPanel(true, false);
popup.setStyleName(current.style.dialog());
popup.add(current);
popup.addCloseHandler(new CloseHandler<PopupPanel>() {
@Override
public void onClose(CloseEvent<PopupPanel> event) {
view.getEditor().focus();
popup = null;
current = null;
}
});
popup.setPopupPositionAndShow(new PositionCallback() {
@Override
public void setPosition(int offsetWidth, int offsetHeight) {
popup.setPopupPosition(300, 120);
}
});
}
void hide() {
if (popup != null) {
popup.hide();
popup = null;
current = null;
}
}
}

View File

@ -0,0 +1,213 @@
// 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.google.gerrit.client.editor;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.VoidResult;
import com.google.gerrit.client.account.AccountApi;
import com.google.gerrit.client.account.EditPreferences;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.ui.NpIntTextBox;
import com.google.gerrit.extensions.client.Theme;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.ToggleButton;
import net.codemirror.theme.ThemeLoader;
/** Displays current edit preferences. */
class EditPreferencesBox extends Composite {
interface Binder extends UiBinder<HTMLPanel, EditPreferencesBox> {}
private static final Binder uiBinder = GWT.create(Binder.class);
interface Style extends CssResource {
String dialog();
}
private final EditScreen view;
private EditPreferences prefs;
@UiField Style style;
@UiField Anchor close;
@UiField NpIntTextBox tabWidth;
@UiField NpIntTextBox lineLength;
@UiField ToggleButton topMenu;
@UiField ToggleButton syntaxHighlighting;
@UiField ToggleButton showTabs;
@UiField ToggleButton whitespaceErrors;
@UiField ToggleButton lineNumbers;
@UiField ListBox theme;
@UiField Button apply;
@UiField Button save;
EditPreferencesBox(EditScreen view) {
this.view = view;
initWidget(uiBinder.createAndBindUi(this));
initTheme();
}
void set(EditPreferences prefs) {
this.prefs = prefs;
tabWidth.setIntValue(prefs.tabSize());
lineLength.setIntValue(prefs.lineLength());
topMenu.setValue(!prefs.hideTopMenu());
syntaxHighlighting.setValue(prefs.syntaxHighlighting());
showTabs.setValue(prefs.showTabs());
whitespaceErrors.setValue(prefs.showWhitespaceErrors());
lineNumbers.setValue(prefs.hideLineNumbers());
setTheme(prefs.theme());
}
@UiHandler("tabWidth")
void onTabWidth(ValueChangeEvent<String> e) {
String v = e.getValue();
if (v != null && v.length() > 0) {
prefs.tabSize(Math.max(1, Integer.parseInt(v)));
view.getEditor().setOption("tabSize", v);
}
}
@UiHandler("lineLength")
void onLineLength(ValueChangeEvent<String> e) {
String v = e.getValue();
if (v != null && v.length() > 0) {
prefs.lineLength(Math.max(1, Integer.parseInt(v)));
view.setLineLength(prefs.lineLength());
}
}
@UiHandler("topMenu")
void onTopMenu(ValueChangeEvent<Boolean> e) {
prefs.hideTopMenu(!e.getValue());
Gerrit.setHeaderVisible(!prefs.hideTopMenu());
view.resizeCodeMirror();
}
@UiHandler("showTabs")
void onShowTabs(ValueChangeEvent<Boolean> e) {
prefs.showTabs(e.getValue());
view.setShowTabs(prefs.showTabs());
}
@UiHandler("whitespaceErrors")
void onshowTrailingSpace(ValueChangeEvent<Boolean> e) {
prefs.showWhitespaceErrors(e.getValue());
view.setShowWhitespaceErrors(prefs.showWhitespaceErrors());
}
@UiHandler("lineNumbers")
void onLineNumbers(ValueChangeEvent<Boolean> e) {
prefs.hideLineNumbers(e.getValue());
view.setShowLineNumbers(prefs.hideLineNumbers());
}
@UiHandler("syntaxHighlighting")
void onSyntaxHighlighting(ValueChangeEvent<Boolean> e) {
prefs.syntaxHighlighting(e.getValue());
view.setSyntaxHighlighting(prefs.syntaxHighlighting());
}
@UiHandler("theme")
void onTheme(@SuppressWarnings("unused") ChangeEvent e) {
final Theme newTheme = Theme.valueOf(theme.getValue(theme.getSelectedIndex()));
prefs.theme(newTheme);
ThemeLoader.loadTheme(newTheme, new GerritCallback<Void>() {
@Override
public void onSuccess(Void result) {
view.getEditor().operation(new Runnable() {
@Override
public void run() {
String t = newTheme.name().toLowerCase();
view.getEditor().setOption("theme", t);
}
});
}
});
}
@UiHandler("apply")
void onApply(@SuppressWarnings("unused") ClickEvent e) {
close();
}
@UiHandler("save")
void onSave(@SuppressWarnings("unused") ClickEvent e) {
AccountApi.putEditPreferences(prefs, new GerritCallback<VoidResult>() {
@Override
public void onSuccess(VoidResult n) {
prefs.copyTo(Gerrit.getEditPreferences());
}
});
close();
}
@UiHandler("close")
void onClose(ClickEvent e) {
e.preventDefault();
close();
}
private void close() {
((PopupPanel) getParent()).hide();
}
private void setTheme(Theme v) {
String name = v != null ? v.name() : Theme.DEFAULT.name();
for (int i = 0; i < theme.getItemCount(); i++) {
if (theme.getValue(i).equals(name)) {
theme.setSelectedIndex(i);
return;
}
}
theme.setSelectedIndex(0);
}
private void initTheme() {
theme.addItem(
Theme.DEFAULT.name().toLowerCase(),
Theme.DEFAULT.name());
theme.addItem(
Theme.ECLIPSE.name().toLowerCase(),
Theme.ECLIPSE.name());
theme.addItem(
Theme.ELEGANT.name().toLowerCase(),
Theme.ELEGANT.name());
theme.addItem(
Theme.NEAT.name().toLowerCase(),
Theme.NEAT.name());
theme.addItem(
Theme.MIDNIGHT.name().toLowerCase(),
Theme.MIDNIGHT.name());
theme.addItem(
Theme.NIGHT.name().toLowerCase(),
Theme.NIGHT.name());
theme.addItem(
Theme.TWILIGHT.name().toLowerCase(),
Theme.TWILIGHT.name());
}
}

View File

@ -0,0 +1,228 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:x='urn:import:com.google.gerrit.client.ui'>
<ui:style type='com.google.gerrit.client.editor.EditPreferencesBox.Style'>
@external .gwt-TextBox;
@external .gwt-ToggleButton .html-face;
@external .gwt-ToggleButton-up;
@external .gwt-ToggleButton-up-hovering;
@external .gwt-ToggleButton-up-disabled;
@external .gwt-ToggleButton-down;
@external .gwt-ToggleButton-down-hovering;
@external .gwt-ToggleButton-down-disabled;
.dialog {
background: rgba(0, 0, 0, 0.85) none repeat scroll 0 50%;
color: #ffffff;
font-family: arial,sans-serif;
font-weight: bold;
overflow: hidden;
text-align: left;
text-shadow: 1px 1px 7px #000000;
min-width: 300px;
z-index: 200;
border-radius: 10px;
}
@if user.agent safari {
.dialog {
\-webkit-border-radius: 10px;
}
}
@if user.agent gecko1_8 {
.dialog {
\-moz-border-radius: 10px;
}
}
.box { margin: 10px; }
.box .gwt-TextBox { padding: 0; }
.context { vertical-align: bottom; }
.table tr { min-height: 23px; }
.table th,
.table td {
white-space: nowrap;
color: #ffffff;
}
.table th {
padding-right: 8px;
text-align: right;
}
.box a,
.box a:visited,
.box a:hover {
color: #dddd00;
}
.box .gwt-ToggleButton {
position: relative;
height: 19px;
width: 140px;
background: #fff;
color: #000;
text-shadow: none;
}
.box .gwt-ToggleButton .html-face {
position: absolute;
top: 0;
width: 68px;
height: 17px;
line-height: 17px;
text-align: center;
border-width: 1px;
}
.box .gwt-ToggleButton-up,
.box .gwt-ToggleButton-up-hovering,
.box .gwt-ToggleButton-up-disabled,
.box .gwt-ToggleButton-down,
.box .gwt-ToggleButton-down-hovering,
.box .gwt-ToggleButton-down-disabled {
padding: 0;
border: 0;
}
.box .gwt-ToggleButton-up .html-face,
.box .gwt-ToggleButton-up-hovering .html-face {
left: 0;
background: #cacaca;
border-style: outset;
}
.box .gwt-ToggleButton-down .html-face,
.box .gwt-ToggleButton-down-hovering .html-face {
right: 0;
background: #bcf;
border-style: inset;
}
.box button {
margin: 6px 3px 0 0;
border-color: rgba(0, 0, 0, 0.1);
text-align: center;
font-size: 8pt;
font-weight: bold;
border: 1px solid;
cursor: pointer;
color: #444;
background-color: #f5f5f5;
background-image: -webkit-linear-gradient(top, #f5f5f5, #f1f1f1);
-webkit-border-radius: 2px;
-webkit-box-sizing: content-box;
}
.box button div {
color: #444;
height: 10px;
min-width: 54px;
line-height: 10px;
white-space: nowrap;
}
button.apply {
background-color: #4d90fe;
background-image: -webkit-linear-gradient(top, #4d90fe, #4d90fe);
}
button.apply div { color: #fff; }
button.save {
margin-left: 10px;
color: #d14836;
background-color: #d14836;
background-image: -webkit-linear-gradient(top, #d14836, #d14836);
}
button.save div { color: #fff; }
</ui:style>
<g:HTMLPanel styleName='{style.box}'>
<table style='width: 100%'>
<tr>
<td><ui:msg>Edit Preferences</ui:msg></td>
<td style='text-align: right'>
<g:Anchor ui:field='close' href='javascript:;'><ui:msg>Close</ui:msg></g:Anchor>
</td>
</tr>
</table>
<hr/>
<table class='{style.table}'>
<tr>
<th><ui:msg>Theme</ui:msg></th>
<td><g:ListBox ui:field='theme'/></td>
</tr>
<tr>
<th><ui:msg>Tab Width</ui:msg></th>
<td><x:NpIntTextBox ui:field='tabWidth'
visibleLength='4'
alignment='RIGHT'/></td>
</tr>
<tr>
<th><ui:msg>Columns</ui:msg></th>
<td><x:NpIntTextBox ui:field='lineLength'
visibleLength='4'
alignment='RIGHT'/></td>
</tr>
<tr>
<th><ui:msg>Top Menu</ui:msg></th>
<td><g:ToggleButton ui:field='topMenu'>
<g:upFace><ui:msg>Hide</ui:msg></g:upFace>
<g:downFace><ui:msg>Show</ui:msg></g:downFace>
</g:ToggleButton></td>
</tr>
<tr>
<th><ui:msg>Syntax Highlighting</ui:msg></th>
<td><g:ToggleButton ui:field='syntaxHighlighting'>
<g:upFace><ui:msg>Hide</ui:msg></g:upFace>
<g:downFace><ui:msg>Show</ui:msg></g:downFace>
</g:ToggleButton></td>
</tr>
<tr>
<th><ui:msg>Show Tabs</ui:msg></th>
<td><g:ToggleButton ui:field='showTabs'>
<g:upFace><ui:msg>Hide</ui:msg></g:upFace>
<g:downFace><ui:msg>Show</ui:msg></g:downFace>
</g:ToggleButton></td>
</tr>
<tr>
<th><ui:msg>Whitespace Errors</ui:msg></th>
<td><g:ToggleButton ui:field='whitespaceErrors'>
<g:upFace><ui:msg>Hide</ui:msg></g:upFace>
<g:downFace><ui:msg>Show</ui:msg></g:downFace>
</g:ToggleButton></td>
</tr>
<tr>
<th><ui:msg>Line Numbers</ui:msg></th>
<td><g:ToggleButton ui:field='lineNumbers'>
<g:upFace><ui:msg>Hide</ui:msg></g:upFace>
<g:downFace><ui:msg>Show</ui:msg></g:downFace>
</g:ToggleButton></td>
</tr>
<tr>
<td></td>
<td>
<g:Button ui:field='apply' styleName='{style.apply}'>
<div><ui:msg>Apply</ui:msg></div>
</g:Button>
<g:Button ui:field='save' styleName='{style.save}'>
<div><ui:msg>Save</ui:msg></div>
</g:Button>
</td>
</tr>
</table>
</g:HTMLPanel>
</ui:UiBinder>

View File

@ -22,7 +22,8 @@ import com.google.gerrit.client.Dispatcher;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.JumpKeys;
import com.google.gerrit.client.VoidResult;
import com.google.gerrit.client.account.DiffPreferences;
import com.google.gerrit.client.account.AccountApi;
import com.google.gerrit.client.account.EditPreferences;
import com.google.gerrit.client.changes.ChangeApi;
import com.google.gerrit.client.changes.ChangeEditApi;
import com.google.gerrit.client.diff.DiffApi;
@ -42,6 +43,7 @@ import com.google.gerrit.client.rpc.ScreenLoadCallback;
import com.google.gerrit.client.ui.InlineHyperlink;
import com.google.gerrit.client.ui.Screen;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.extensions.client.EditPreferencesInfo;
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.GWT;
@ -87,7 +89,8 @@ public class EditScreen extends Screen {
private final PatchSet.Id revision;
private final String path;
private final int startLine;
private DiffPreferences prefs;
private EditPreferences prefs;
private EditPreferencesAction editPrefsAction;
private CodeMirror cm;
private HttpResponse<NativeString> content;
private EditFileInfo editFileInfo;
@ -113,7 +116,6 @@ public class EditScreen extends Screen {
this.revision = patch.getParentKey();
this.path = patch.get();
this.startLine = startLine - 1;
prefs = DiffPreferences.create(Gerrit.getAccountDiffPreference());
add(uiBinder.createAndBindUi(this));
addDomHandler(GlobalKey.STOP_PROPAGATION, KeyPressEvent.getType());
}
@ -129,6 +131,26 @@ public class EditScreen extends Screen {
protected void onLoad() {
super.onLoad();
EditPreferencesInfo current = Gerrit.getEditPreferences();
if (current == null) {
AccountApi.getEditPreferences(
new GerritCallback<EditPreferences>() {
@Override
public void onSuccess(EditPreferences r) {
prefs = r;
EditPreferencesInfo global = new EditPreferencesInfo();
r.copyTo(global);
Gerrit.setEditPreferences(global);
onLoad2();
}
});
} else {
prefs = EditPreferences.create(current);
onLoad2();
}
}
private void onLoad2() {
CallbackGroup group1 = new CallbackGroup();
final CallbackGroup group2 = new CallbackGroup();
final CallbackGroup group3 = new CallbackGroup();
@ -163,7 +185,6 @@ public class EditScreen extends Screen {
}
}));
if (revision.get() == 0) {
ChangeEditApi.getMeta(revision, path,
group1.add(new AsyncCallback<EditFileInfo>() {
@ -224,7 +245,6 @@ public class EditScreen extends Screen {
@Override
protected void preDisplay(Void result) {
initEditor(content);
content = null;
renderLinks(editFileInfo, diffLinks);
editFileInfo = null;
@ -300,9 +320,8 @@ public class EditScreen extends Screen {
cm.adjustHeight(header.getOffsetHeight());
cm.on("cursorActivity", updateCursorPosition());
cm.extras().showTabs(prefs.showTabs());
cm.extras().lineLength(
Patch.COMMIT_MSG.equals(path) ? 72 : prefs.lineLength());
setShowTabs(prefs.showTabs());
setLineLength(prefs.lineLength());
cm.refresh();
cm.focus();
@ -310,6 +329,7 @@ public class EditScreen extends Screen {
cm.scrollToLine(startLine);
}
updateActiveLine();
editPrefsAction = new EditPreferencesAction(this, prefs);
}
@Override
@ -329,6 +349,15 @@ public class EditScreen extends Screen {
JumpKeys.enable(true);
}
CodeMirror getEditor() {
return cm;
}
@UiHandler("editSettings")
void onEditSetting(@SuppressWarnings("unused") ClickEvent e) {
editPrefsAction.show();
}
@UiHandler("save")
void onSave(@SuppressWarnings("unused") ClickEvent e) {
save().run();
@ -342,6 +371,52 @@ public class EditScreen extends Screen {
}
}
void setLineLength(int length) {
cm.extras().lineLength(
Patch.COMMIT_MSG.equals(path) ? 72 : length);
}
void setShowLineNumbers(boolean show) {
cm.setOption("lineNumbers", show);
}
void setShowWhitespaceErrors(final boolean show) {
cm.operation(new Runnable() {
@Override
public void run() {
cm.setOption("showTrailingSpace", show);
}
});
}
void setShowTabs(boolean show) {
cm.extras().showTabs(show);
}
void resizeCodeMirror() {
cm.adjustHeight(header.getOffsetHeight());
}
void setSyntaxHighlighting(boolean b) {
ModeInfo modeInfo = ModeInfo.findMode(content.getContentType(), path);
final String mode = modeInfo != null ? modeInfo.mode() : null;
if (b && mode != null && !mode.isEmpty()) {
injectMode(mode, new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
cm.setOption("mode", mode);
}
@Override
public void onFailure(Throwable caught) {
prefs.syntaxHighlighting(false);
}
});
} else {
cm.setOption("mode", (String) null);
}
}
private void upToChange() {
Gerrit.display(PageLinks.toChangeInEditMode(revision.getParentKey()));
}
@ -360,12 +435,12 @@ public class EditScreen extends Screen {
.set("readOnly", false)
.set("cursorBlinkRate", 0)
.set("cursorHeight", 0.85)
.set("lineNumbers", true)
.set("lineNumbers", prefs.hideLineNumbers())
.set("tabSize", prefs.tabSize())
.set("lineWrapping", false)
.set("scrollbarStyle", "overlay")
.set("styleSelectedText", true)
.set("showTrailingSpace", true)
.set("showTrailingSpace", prefs.showWhitespaceErrors())
.set("keyMap", "default")
.set("theme", prefs.theme().name().toLowerCase())
.set("mode", mode != null ? mode.mode() : null));

View File

@ -16,6 +16,7 @@ limitations under the License.
-->
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:with field='ico' type='com.google.gerrit.client.GerritResources'/>
<ui:style gss='false'>
@external .CodeMirror, .CodeMirror-cursor;
@ -115,6 +116,13 @@ limitations under the License.
padding-top: 2px;
padding-right: 3px;
}
.preferences {
position: relative;
top: 2px;
cursor: pointer;
outline: none;
}
</ui:style>
<g:HTMLPanel styleName='{style.header}'>
<div class='{style.headerLine}' ui:field='header'>
@ -135,6 +143,13 @@ limitations under the License.
<span class='{style.path}'><span ui:field='project'/> / <span ui:field='filePath'/></span>
<div class='{style.navigation}'>
<g:FlowPanel ui:field='linkPanel' styleName='{style.linkPanel}'/>
<g:Image
ui:field='editSettings'
styleName='{style.preferences}'
resource='{ico.gear}'
title='Edit screen preferences'>
<ui:attribute name='title'/>
</g:Image>
</div>
</div>
<div ui:field='editor' />