DBE: Grid position widget

(cherry picked from commit 295d2ba)
This commit is contained in:
dmitriy.tseyler
2017-03-13 21:12:08 +03:00
parent b830ec36b5
commit 48aa8017fb
5 changed files with 166 additions and 59 deletions
@@ -16,6 +16,7 @@
package com.intellij.ide.actions;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.util.EditorGotoLineNumberDialog;
import com.intellij.ide.util.GotoLineNumberDialog;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.command.CommandProcessor;
@@ -33,14 +34,14 @@ public class GotoLineAction extends AnAction implements DumbAware {
final Project project = e.getData(CommonDataKeys.PROJECT);
final Editor editor = e.getData(CommonDataKeys.EDITOR_EVEN_IF_INACTIVE);
if (Boolean.TRUE.equals(e.getData(PlatformDataKeys.IS_MODAL_CONTEXT))) {
GotoLineNumberDialog dialog = new GotoLineNumberDialog(project, editor);
GotoLineNumberDialog dialog = new EditorGotoLineNumberDialog(project, editor);
dialog.show();
}
else {
CommandProcessor processor = CommandProcessor.getInstance();
processor.executeCommand(
project, () -> {
GotoLineNumberDialog dialog = new GotoLineNumberDialog(project, editor);
GotoLineNumberDialog dialog = new EditorGotoLineNumberDialog(project, editor);
dialog.show();
IdeDocumentHistory.getInstance(project).includeCurrentCommandAsNavigation();
},
@@ -0,0 +1,79 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* 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.intellij.ide.util;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.IdeFocusManager;
import org.jetbrains.annotations.NotNull;
public class EditorGotoLineNumberDialog extends GotoLineNumberDialog {
private final Editor myEditor;
public EditorGotoLineNumberDialog(Project project, Editor editor) {
super(project);
myEditor = editor;
init();
}
protected void doOKAction() {
Coordinates coordinates = getCoordinates();
if (coordinates == null) return;
LogicalPosition position = new LogicalPosition(coordinates.row, coordinates.column);
myEditor.getCaretModel().removeSecondaryCarets();
myEditor.getCaretModel().moveToLogicalPosition(position);
myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
myEditor.getSelectionModel().removeSelection();
IdeFocusManager.getGlobalInstance().requestFocus(myEditor.getContentComponent(), true);
super.doOKAction();
}
@Override
protected int getLine() {
return myEditor.getCaretModel().getLogicalPosition().line;
}
@Override
protected int getColumn() {
return myEditor.getCaretModel().getLogicalPosition().column;
}
@Override
protected int getOffset() {
return myEditor.getCaretModel().getOffset();
}
@Override
protected int getMaxOffset() {
return myEditor.getDocument().getTextLength();
}
@Override
protected int coordinatesToOffset(@NotNull Coordinates coordinates) {
LogicalPosition position = new LogicalPosition(coordinates.row, coordinates.column);
return myEditor.logicalPositionToOffset(position);
}
@NotNull
@Override
protected Coordinates offsetToCoordinates(int offset) {
LogicalPosition position = myEditor.offsetToLogicalPosition(offset);
return new Coordinates(position.line, position.column);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,15 +16,13 @@
package com.intellij.ide.util;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.ui.DocumentAdapter;
import com.intellij.util.PatternUtil;
import com.intellij.util.ui.JBUI;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -33,39 +31,15 @@ import java.awt.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GotoLineNumberDialog extends DialogWrapper {
private JTextField myField;
private JTextField myOffsetField;
private final Editor myEditor;
public abstract class GotoLineNumberDialog extends DialogWrapper {
private final Pattern myPattern = PatternUtil.compileSafe("\\s*(\\d+)?\\s*(?:[,:]?\\s*(\\d+)?)?\\s*", null);
public GotoLineNumberDialog(Project project, Editor editor) {
private JTextField myField;
private JTextField myOffsetField;
public GotoLineNumberDialog(Project project) {
super(project, true);
myEditor = editor;
setTitle("Go to Line/Column");
init();
}
protected void doOKAction() {
LogicalPosition position = getLogicalPosition();
if (position == null) return;
myEditor.getCaretModel().removeSecondaryCarets();
myEditor.getCaretModel().moveToLogicalPosition(position);
myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
myEditor.getSelectionModel().removeSelection();
IdeFocusManager.getGlobalInstance().requestFocus(myEditor.getContentComponent(), true);
super.doOKAction();
}
@Nullable
private LogicalPosition getLogicalPosition() {
Matcher m = myPattern.matcher(getText());
if (!m.matches()) return null;
int l = StringUtil.parseInt(m.group(1), myEditor.getCaretModel().getLogicalPosition().line + 1);
int c = StringUtil.parseInt(m.group(2), -1);
return l > 0 ? new LogicalPosition(l - 1, Math.max(0, c - 1)) : null;
}
private static boolean isInternal() {
@@ -84,6 +58,24 @@ public class GotoLineNumberDialog extends DialogWrapper {
return myField.getText();
}
@Nullable
protected final Coordinates getCoordinates() {
Matcher m = myPattern.matcher(getText());
if (!m.matches()) return null;
int l = StringUtil.parseInt(m.group(1), getLine() + 1);
int c = StringUtil.parseInt(m.group(2), -1);
return l > 0 ? new Coordinates(l - 1, Math.max(0, c - 1)) : null;
}
protected abstract int getLine();
protected abstract int getColumn();
protected abstract int getOffset();
protected abstract int getMaxOffset();
protected abstract int coordinatesToOffset(@NotNull Coordinates coordinates);
@NotNull
protected abstract Coordinates offsetToCoordinates(int offset);
protected JComponent createNorthPanel() {
class MyTextField extends JTextField {
public MyTextField() {
@@ -99,7 +91,7 @@ public class GotoLineNumberDialog extends DialogWrapper {
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbConstraints = new GridBagConstraints();
gbConstraints.insets = new Insets(4, 0, 8, 8);
gbConstraints.insets = JBUI.insets(4, 0, 8, 8);
gbConstraints.fill = GridBagConstraints.VERTICAL;
gbConstraints.weightx = 0;
gbConstraints.weighty = 1;
@@ -111,8 +103,7 @@ public class GotoLineNumberDialog extends DialogWrapper {
gbConstraints.weightx = 1;
myField = new MyTextField();
panel.add(myField, gbConstraints);
LogicalPosition position = myEditor.getCaretModel().getLogicalPosition();
myField.setText(String.format("%d:%d", position.line + 1, position.column + 1));
myField.setText(String.format("%d:%d", getLine() + 1, getColumn() + 1));
if (isInternal()) {
gbConstraints.gridy = 1;
@@ -126,7 +117,7 @@ public class GotoLineNumberDialog extends DialogWrapper {
gbConstraints.weightx = 1;
myOffsetField = new MyTextField();
panel.add(myOffsetField, gbConstraints);
myOffsetField.setText(String.valueOf(myEditor.getCaretModel().getOffset()));
myOffsetField.setText(String.valueOf(getOffset()));
DocumentAdapter valueSync = new DocumentAdapter() {
boolean inSync;
@@ -140,15 +131,14 @@ public class GotoLineNumberDialog extends DialogWrapper {
try {
if (e.getDocument() == myField.getDocument()) {
f = myOffsetField;
LogicalPosition p = getLogicalPosition();
s = p == null ? s : String.valueOf(myEditor.logicalPositionToOffset(p));
Coordinates p = getCoordinates();
s = p == null ? s : String.valueOf(coordinatesToOffset(p));
}
else {
f = myField;
int offset = StringUtil.parseInt(myOffsetField.getText(), -1);
LogicalPosition p = offset >= 0 ? myEditor.offsetToLogicalPosition(
Math.min(myEditor.getDocument().getTextLength() - 1, offset)) : null;
s = p == null ? s : String.format("%d:%d", p.line + 1, p.column + 1);
Coordinates p = offset >= 0 ? offsetToCoordinates(Math.min(getMaxOffset() - 1, offset)) : null;
s = p == null ? s : String.format("%d:%d", p.row + 1, p.column + 1);
}
f.setText(s);
}
@@ -166,4 +156,14 @@ public class GotoLineNumberDialog extends DialogWrapper {
return panel;
}
protected static class Coordinates {
public final int row;
public final int column;
public Coordinates(int row, int column) {
this.row = row;
this.column = column;
}
}
}
@@ -144,7 +144,7 @@ public class IdeStatusBarImpl extends JComponent implements Accessible, StatusBa
WidgetBean eachBean = myWidgetMap.get(eachId);
if (eachBean.widget instanceof StatusBarWidget.Multiframe) {
StatusBarWidget copy = ((StatusBarWidget.Multiframe)eachBean.widget).copy();
bar.addWidget(copy, eachBean.position);
UIUtil.invokeLaterIfNeeded(() -> bar.addWidget(copy, eachBean.position, eachBean.anchor));
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.wm.impl.status;
import com.intellij.ide.util.EditorGotoLineNumberDialog;
import com.intellij.ide.util.GotoLineNumberDialog;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
@@ -22,6 +23,8 @@ import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.event.*;
import com.intellij.openapi.editor.ex.DocumentBulkUpdateListener;
import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.editor.ex.EditorEventMulticasterEx;
import com.intellij.openapi.editor.ex.FocusChangeListener;
import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory;
import com.intellij.openapi.project.Project;
@@ -30,6 +33,7 @@ import com.intellij.openapi.wm.StatusBarWidget;
import com.intellij.ui.UIBundle;
import com.intellij.util.Alarm;
import com.intellij.util.Consumer;
import com.intellij.util.ObjectUtils;
import com.intellij.util.messages.MessageBusConnection;
import org.jetbrains.annotations.NotNull;
@@ -39,7 +43,14 @@ import java.awt.event.MouseEvent;
public class PositionPanel extends EditorBasedWidget
implements StatusBarWidget.Multiframe, StatusBarWidget.TextPresentation,
CaretListener, SelectionListener, DocumentListener, DocumentBulkUpdateListener {
CaretListener, SelectionListener, DocumentListener, DocumentBulkUpdateListener,
FocusChangeListener {
public static final String SPACE = " ";
public static final String SEPARATOR = ":";
public static final String MAX_POSSIBLE_TEXT = "0000000000000";
public static final String ID = "Position";
private static final int CHAR_COUNT_SYNC_LIMIT = 500_000;
private static final String CHAR_COUNT_UNKNOWN = "...";
@@ -60,7 +71,7 @@ public class PositionPanel extends EditorBasedWidget
@NotNull
public String ID() {
return "Position";
return ID;
}
@Override
@@ -79,7 +90,7 @@ public class PositionPanel extends EditorBasedWidget
@NotNull
public String getMaxPossibleText() {
return "0000000000000";
return MAX_POSSIBLE_TEXT;
}
@Override
@@ -93,14 +104,15 @@ public class PositionPanel extends EditorBasedWidget
public Consumer<MouseEvent> getClickConsumer() {
return mouseEvent -> {
final Project project = getProject();
if (project == null) return;
final Editor editor = getEditor();
if (editor == null) return;
final CommandProcessor processor = CommandProcessor.getInstance();
Project project = getProject();
Editor editor = getEditor();
if (project == null || editor == null) return;
CommandProcessor processor = CommandProcessor.getInstance();
processor.executeCommand(
project, () -> {
final GotoLineNumberDialog dialog = new GotoLineNumberDialog(project, editor);
project,
() -> {
GotoLineNumberDialog dialog = new EditorGotoLineNumberDialog(project, editor);
dialog.show();
IdeDocumentHistory.getInstance(project).includeCurrentCommandAsNavigation();
},
@@ -112,12 +124,17 @@ public class PositionPanel extends EditorBasedWidget
public void install(@NotNull StatusBar statusBar) {
super.install(statusBar);
final EditorEventMulticaster multicaster = EditorFactory.getInstance().getEventMulticaster();
EditorEventMulticaster multicaster = EditorFactory.getInstance().getEventMulticaster();
multicaster.addCaretListener(this, this);
multicaster.addSelectionListener(this, this);
multicaster.addDocumentListener(this, this);
MessageBusConnection connection = ApplicationManager.getApplication().getMessageBus().connect(this);
connection.subscribe(DocumentBulkUpdateListener.TOPIC, this);
ObjectUtils.consumeIfCast(
multicaster,
EditorEventMulticasterEx.class,
multicasterEx -> multicasterEx.addFocusChangeListner(this, this)
);
}
@Override
@@ -159,6 +176,16 @@ public class PositionPanel extends EditorBasedWidget
onDocumentUpdate(doc);
}
@Override
public void focusGained(Editor editor) {
updatePosition(editor);
}
@Override
public void focusLost(Editor editor) {
updatePosition(getEditor());
}
private void onDocumentUpdate(Document document) {
Editor[] editors = EditorFactory.getInstance().getEditors(document);
Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
@@ -225,11 +252,11 @@ public class PositionPanel extends EditorBasedWidget
message.append(", ");
message.append(UIBundle.message("position.panel.selected.line.breaks.count", selectionEndLine - selectionStartLine));
}
message.append(" ");
message.append(SPACE);
}
}
LogicalPosition caret = editor.getCaretModel().getLogicalPosition();
message.append(caret.line + 1).append(":").append(caret.column + 1);
message.append(caret.line + 1).append(SEPARATOR).append(caret.column + 1);
}
return message.toString();