Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Trofimov
2015-05-12 16:44:35 +02:00
33 changed files with 328 additions and 320 deletions
@@ -23,6 +23,8 @@ import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.projectRoots.*;
import com.intellij.openapi.roots.AnnotationOrderRootType;
@@ -62,8 +64,40 @@ public class JavaSdkImpl extends JavaSdk {
private static final String JAVA_VERSION_PREFIX = "java version ";
private static final String OPENJDK_VERSION_PREFIX = "openjdk version ";
public JavaSdkImpl() {
public JavaSdkImpl(final VirtualFileManager fileManager, final FileTypeManager fileTypeManager) {
super("JavaSDK");
fileManager.addVirtualFileListener(new VirtualFileAdapter() {
public void fileDeleted(@NotNull VirtualFileEvent event) {
updateCache(event);
}
@Override
public void contentsChanged(@NotNull VirtualFileEvent event) {
updateCache(event);
}
@Override
public void fileCreated(@NotNull VirtualFileEvent event) {
updateCache(event);
}
private void updateCache(VirtualFileEvent event) {
final VirtualFile file = event.getFile();
if (FileTypes.ARCHIVE.equals(fileTypeManager.getFileTypeByFileName(event.getFileName()))) {
final String filePath = file.getPath();
synchronized (myCachedVersionStrings) {
for (String sdkHome : myCachedVersionStrings.keySet()) {
if (FileUtil.isAncestor(sdkHome, filePath, false)) {
myCachedVersionStrings.remove(sdkHome);
break;
}
}
}
}
}
});
}
@Override
@@ -428,7 +462,7 @@ public class JavaSdkImpl extends JavaSdk {
modificator.addRoot(root, annoType);
}
private final Map<String, String> myCachedVersionStrings = new HashMap<String, String>();
private final Map<String, String> myCachedVersionStrings = Collections.synchronizedMap(new HashMap<String, String>());
@Override
public final String getVersionString(String sdkHome) {
@@ -30,13 +30,24 @@ import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/*
* Executor to perform <possibly> long operations on pooled thread
* Is is used to reduce blinking, in case of fast end of background task.
*/
public class BackgroundTaskUtil {
private static final Runnable TOO_SLOW_OPERATION = new EmptyRunnable();
/*
* Executor to perform <possibly> long operations on pooled thread
* It can be used to reduce blinking if background task completed fast. In this case callback will be called without invokeLater().
*
* Simple approach:
*
* onSlowAction.run() // show "Loading..."
* executeOnPooledThread({
* Runnable callback = backgroundTask(); // some background computations
* invokeLater(callback); // apply changes
* });
*
* will lead to "Loading..." visible between current moment and execution of invokeLater() event.
* This period can be very short and looks like 'jumping' if background operation is fast.
*/
@CalledInAwt
@NotNull
public static ProgressIndicator executeAndTryWait(@NotNull final Function<ProgressIndicator, Runnable> backgroundTask,
@@ -37,7 +37,6 @@ import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.fileTypes.LanguageFileType;
@@ -143,9 +142,6 @@ public class TypedHandler extends TypedActionHandlerBase {
}
if (!CodeInsightUtilBase.prepareEditorForWrite(originalEditor)) return;
if (!FileDocumentManager.getInstance().requestWriting(originalEditor.getDocument(), project)) {
return;
}
final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
final Document originalDocument = originalEditor.getDocument();
@@ -40,7 +40,6 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorModificationUtil;
import com.intellij.openapi.editor.actionSystem.TypedActionHandler;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
@@ -68,7 +67,7 @@ public class LookupTypedHandler extends TypedActionHandlerBase {
return;
}
if (!CodeInsightUtilBase.prepareEditorForWrite(originalEditor) || !FileDocumentManager.getInstance().requestWriting(originalEditor.getDocument(), project)) {
if (!CodeInsightUtilBase.prepareEditorForWrite(originalEditor)) {
return;
}
@@ -92,7 +92,7 @@ public class IncrementalSearchHandler {
EditorActionManager actionManager = EditorActionManager.getInstance();
TypedAction typedAction = actionManager.getTypedAction();
typedAction.setupHandler(new MyTypedHandler(typedAction.getHandler()));
typedAction.setupRawHandler(new MyTypedHandler(typedAction.getRawHandler()));
actionManager.setActionHandler(IdeActions.ACTION_EDITOR_BACKSPACE, new BackSpaceHandler(actionManager.getActionHandler(IdeActions.ACTION_EDITOR_BACKSPACE)));
actionManager.setActionHandler(IdeActions.ACTION_EDITOR_MOVE_CARET_UP, new UpHandler(actionManager.getActionHandler(IdeActions.ACTION_EDITOR_MOVE_CARET_UP)));
@@ -35,6 +35,7 @@ import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.TabsListener;
import com.intellij.ui.tabs.UiDecorator;
import com.intellij.ui.tabs.impl.JBEditorTabs;
import com.intellij.ui.tabs.impl.TabLabel;
import com.intellij.ui.tabs.impl.singleRow.ScrollableSingleRowLayout;
import com.intellij.ui.tabs.impl.singleRow.SingleRowLayout;
import com.intellij.util.containers.HashSet;
@@ -114,6 +115,16 @@ public class GridCellImpl implements GridCell {
public void resetDropOver(TabInfo tabInfo) {
((RunnerContentUi)myContext).myTabs.resetDropOver(tabInfo);
}
@Override
protected TabLabel createTabLabel(TabInfo info) {
return new TabLabel(this, info) {
@Override
public void setAlignmentToCenter(boolean toCenter) {
super.setAlignmentToCenter(false);
}
};
}
}.setDataProvider(new DataProvider() {
@Override
@Nullable
@@ -26,8 +26,16 @@ import com.intellij.openapi.projectRoots.*;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import com.intellij.util.containers.SmartHashSet;
import com.intellij.util.messages.MessageBus;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.messages.impl.MessageListenerList;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
@@ -35,10 +43,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
@State(
name = "ProjectJdkTable",
@@ -60,37 +65,60 @@ public class ProjectJdkTableImpl extends ProjectJdkTable implements ExportableCo
myMessageBus = ApplicationManager.getApplication().getMessageBus();
myListenerList = new MessageListenerList<Listener>(myMessageBus, JDK_TABLE_TOPIC);
// support external changes to jdk libraries (Endorsed Standards Override)
VirtualFileManager.getInstance().addVirtualFileListener(new VirtualFileAdapter() {
final MessageBusConnection connection = ApplicationManager.getApplication().getMessageBus().connect();
connection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() {
private FileTypeManager myFileTypeManager = FileTypeManager.getInstance();
@Override
public void fileCreated(@NotNull VirtualFileEvent event) {
updateJdks(event.getFile());
public void before(@NotNull List<? extends VFileEvent> events) {
}
private void updateJdks(VirtualFile file) {
if (file.isDirectory() ||
// avoid calling getFileType() because it will try to detect file type from content for unknown/text file types
!FileTypes.ARCHIVE.equals(myFileTypeManager.getFileTypeByFileName(file.getName()))) {
// consider only archive files that may contain libraries
return;
}
for (Sdk sdk : mySdks) {
final SdkType sdkType = (SdkType)sdk.getSdkType();
if (!(sdkType instanceof JavaSdkType)) {
continue;
public void after(@NotNull List<? extends VFileEvent> events) {
if (!events.isEmpty()) {
final Set<Sdk> affected = new SmartHashSet<Sdk>();
for (VFileEvent event : events) {
addAffectedJavaSdk(event, affected);
}
final VirtualFile home = sdk.getHomeDirectory();
if (home == null) {
continue;
}
if (VfsUtilCore.isAncestor(home, file, true)) {
sdkType.setupSdkPaths(sdk);
// no need to iterate further assuming the file cannot be under the home of several SDKs
break;
if (!affected.isEmpty()) {
for (Sdk sdk : affected) {
((SdkType)sdk.getSdkType()).setupSdkPaths(sdk);
}
}
}
}
private void addAffectedJavaSdk(VFileEvent event, Set<Sdk> affected) {
final VirtualFile file = event.getFile();
String fileName = null;
if (file != null && file.isValid()) {
if (file.isDirectory()) {
return;
}
fileName = file.getName();
}
final String eventPath = event.getPath();
if (fileName == null) {
fileName = VfsUtil.extractFileName(eventPath);
}
if (fileName != null) {
// avoid calling getFileType() because it will try to detect file type from content for unknown/text file types
// consider only archive files that may contain libraries
if (!FileTypes.ARCHIVE.equals(myFileTypeManager.getFileTypeByFileName(fileName))) {
return;
}
}
for (Sdk sdk : mySdks) {
if (sdk.getSdkType() instanceof JavaSdkType && !affected.contains(sdk)) {
final String homePath = sdk.getHomePath();
if (!StringUtil.isEmpty(homePath) && FileUtil.isAncestor(homePath, eventPath, true)) {
affected.add(sdk);
// no need to iterate further assuming the file cannot be under the home of several SDKs
break;
}
}
}
}
});
}
@@ -23,7 +23,6 @@ import com.intellij.openapi.command.UndoConfirmationPolicy;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -33,11 +32,14 @@ import org.jetbrains.annotations.Nullable;
* @see EditorActionManager#getTypedAction()
*/
public class TypedAction {
@NotNull
private TypedActionHandler myRawHandler;
private TypedActionHandler myHandler;
private boolean myHandlersLoaded;
public TypedAction() {
myHandler = new Handler();
myRawHandler = new DefaultRawHandler();
}
private void ensureHandlersLoaded() {
@@ -55,11 +57,6 @@ public class TypedAction {
if (editor.isViewer()) return;
Document doc = editor.getDocument();
Project project = CommonDataKeys.PROJECT.getData(dataContext);
if (!FileDocumentManager.getInstance().requestWriting(doc, project)) {
return;
}
doc.startGuardedBlockChecking();
try {
final String str = String.valueOf(charTyped);
@@ -99,43 +96,73 @@ public class TypedAction {
return tmp;
}
public final void actionPerformed(@Nullable final Editor editor, final char charTyped, final DataContext dataContext) {
if (editor == null) return;
Runnable command = new TypingCommand(editor, charTyped, dataContext);
CommandProcessor.getInstance().executeCommand(CommonDataKeys.PROJECT.getData(dataContext), command, "", editor.getDocument(), UndoConfirmationPolicy.DEFAULT, editor.getDocument());
/**
* Gets the current 'raw' typing handler.
*
* @see #setupRawHandler(TypedActionHandler)
*/
@NotNull
public TypedActionHandler getRawHandler() {
return myRawHandler;
}
private class TypingCommand implements Runnable {
private final Editor myEditor;
private final char myCharTyped;
private final DataContext myDataContext;
public TypingCommand(Editor editor, char charTyped, DataContext dataContext) {
myEditor = editor;
myCharTyped = charTyped;
myDataContext = dataContext;
}
/**
* Replaces current 'raw' typing handler with the specified handler. The handler should pass unprocessed typing to the
* previously registered 'raw' handler.
* <p>
* 'Raw' handler is a handler directly invoked by the code which handles typing in editor. Default 'raw' handler
* performs some generic logic that has to be done on typing (like checking whether file has write access, creating a command
* instance for undo subsystem, initiating write action, etc), but delegates to 'normal' handler for actual typing logic.
*
* @param handler the handler to set.
* @return the previously registered handler.
*
* @see #getRawHandler()
* @see #getHandler()
* @see #setupHandler(TypedActionHandler)
*/
@NotNull
public TypedActionHandler setupRawHandler(@NotNull TypedActionHandler handler) {
TypedActionHandler tmp = myRawHandler;
myRawHandler = handler;
return tmp;
}
public final void actionPerformed(@Nullable final Editor editor, final char charTyped, final DataContext dataContext) {
if (editor == null) return;
myRawHandler.execute(editor, charTyped, dataContext);
}
private class DefaultRawHandler implements TypedActionHandler {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new DocumentRunnable(myEditor.getDocument(), myEditor.getProject()) {
@Override
public void run() {
Document doc = myEditor.getDocument();
doc.startGuardedBlockChecking();
try {
getHandler().execute(myEditor, myCharTyped, myDataContext);
public void execute(@NotNull final Editor editor, final char charTyped, @NotNull final DataContext dataContext) {
CommandProcessor.getInstance().executeCommand(
CommonDataKeys.PROJECT.getData(dataContext),
new Runnable() {
@Override
public void run() {
if (!FileDocumentManager.getInstance().requestWriting(editor.getDocument(), editor.getProject())) {
return;
}
ApplicationManager.getApplication().runWriteAction(new DocumentRunnable(editor.getDocument(), editor.getProject()) {
@Override
public void run() {
Document doc = editor.getDocument();
doc.startGuardedBlockChecking();
try {
getHandler().execute(editor, charTyped, dataContext);
}
catch (ReadOnlyFragmentModificationException e) {
EditorActionManager.getInstance().getReadonlyFragmentModificationHandler(doc).handle(e);
}
finally {
doc.stopGuardedBlockChecking();
}
}
});
}
catch (ReadOnlyFragmentModificationException e) {
EditorActionManager.getInstance().getReadonlyFragmentModificationHandler(doc).handle(e);
}
finally {
doc.stopGuardedBlockChecking();
}
}
});
},
"", editor.getDocument(), UndoConfirmationPolicy.DEFAULT, editor.getDocument());
}
}
}
@@ -16,6 +16,8 @@
package com.intellij.ui;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
@@ -25,7 +27,7 @@ import java.awt.*;
* @author Konstantin Bulenkov
*/
public abstract class ColoredTableCellRenderer extends SimpleColoredRenderer implements TableCellRenderer {
public final Component getTableCellRendererComponent(JTable table, Object value,
public final Component getTableCellRendererComponent(JTable table, @Nullable Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
clear();
setPaintFocusBorder(hasFocus && table.getCellSelectionEnabled());
@@ -35,5 +37,5 @@ public abstract class ColoredTableCellRenderer extends SimpleColoredRenderer imp
return this;
}
protected abstract void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column);
protected abstract void customizeCellRenderer(JTable table, @Nullable Object value, boolean selected, boolean hasFocus, int row, int column);
}
@@ -45,6 +45,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.impl.ToolWindowImpl;
import com.intellij.openapi.wm.impl.ToolWindowManagerImpl;
import com.intellij.ui.*;
@@ -584,7 +585,10 @@ public class Switcher extends AnAction implements DumbAware {
}
}.registerCustomShortcutSet(TW_SHORTCUT, this, myPopup);
final Window window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow();
Window window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow();
if (window == null) {
window = WindowManager.getInstance().getFrame(project);
}
myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, myPopup);
myPopup.showInCenterOf(window);
}
@@ -180,6 +180,7 @@ class EditorCoordinateMapper {
FoldRegion outermostCollapsed = myFoldingModel.getCollapsedRegionAtOffset(offset);
if (outermostCollapsed != null && offset > outermostCollapsed.getStartOffset()) {
assert outermostCollapsed.isValid();
offset = outermostCollapsed.getStartOffset();
}
@@ -37,6 +37,7 @@ import com.intellij.ui.JBColor;
import com.intellij.util.Processor;
import com.intellij.util.ui.UIUtil;
import gnu.trove.TFloatArrayList;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
@@ -259,8 +260,10 @@ class EditorPainter {
@Override
public void paint(Graphics2D g, VisualLineFragmentsIterator.Fragment fragment, int start, int end,
TextAttributes attributes, float xStart, float xEnd, int y) {
g.setColor(attributes.getForegroundColor());
fragment.draw(g, xStart, y, start, end);
if (attributes != null && attributes.getForegroundColor() != null) {
g.setColor(attributes.getForegroundColor());
fragment.draw(g, xStart, y, start, end);
}
if (fragment.getCurrentFoldRegion() == null) {
int logicalLine = fragment.getStartLogicalLine();
if (logicalLine != currentLogicalLine[0]) {
@@ -269,7 +272,7 @@ class EditorPainter {
}
paintWhitespace(g, text, xStart, y, start, end, whitespacePaintingStrategy, fragment);
}
if (hasTextEffect(attributes.getEffectColor(), attributes.getEffectType())) {
if (attributes != null && hasTextEffect(attributes.getEffectColor(), attributes.getEffectType())) {
paintTextEffect(g, xStart, xEnd, y, attributes.getEffectColor(), attributes.getEffectType());
}
}
@@ -283,7 +286,8 @@ class EditorPainter {
}
}
float paintLineLayoutWithEffect(Graphics2D g, LineLayout layout, float x, float y, Color effectColor, EffectType effectType) {
float paintLineLayoutWithEffect(Graphics2D g, LineLayout layout, float x, float y,
@Nullable Color effectColor, @Nullable EffectType effectType) {
float initialX = x;
for (LineLayout.VisualFragment fragment : layout.getFragmentsInVisualOrder(x)) {
fragment.draw(g, x, y);
@@ -296,7 +300,7 @@ class EditorPainter {
return x;
}
private static boolean hasTextEffect(Color effectColor, EffectType effectType) {
private static boolean hasTextEffect(@Nullable Color effectColor, @Nullable EffectType effectType) {
return effectColor != null && (effectType == EffectType.LINE_UNDERSCORE ||
effectType == EffectType.BOLD_LINE_UNDERSCORE ||
effectType == EffectType.BOLD_DOTTED_LINE ||
@@ -299,7 +299,9 @@ public class EditorView implements Disposable {
LineLayout getFoldRegionLayout(FoldRegion foldRegion) {
LineLayout layout = foldRegion.getUserData(FOLD_REGION_TEXT_LAYOUT);
if (layout == null) {
layout = new LineLayout(this, foldRegion.getPlaceholderText(), myEditor.getFoldingModel().getPlaceholderAttributes().getFontType(),
TextAttributes placeholderAttributes = myEditor.getFoldingModel().getPlaceholderAttributes();
layout = new LineLayout(this, foldRegion.getPlaceholderText(),
placeholderAttributes == null ? Font.PLAIN : placeholderAttributes.getFontType(),
myFontRenderContext);
foldRegion.putUserData(FOLD_REGION_TEXT_LAYOUT, layout);
}
@@ -18,6 +18,7 @@ package com.intellij.openapi.editor.impl.view;
import com.intellij.openapi.editor.colors.FontPreferences;
import com.intellij.openapi.editor.impl.ComplementaryFontsRegistry;
import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.util.text.CharArrayUtil;
import org.intellij.lang.annotations.JdkConstants;
import org.jetbrains.annotations.NotNull;
@@ -109,6 +110,7 @@ class LineLayout {
}
private static List<BidiRun> createRuns(char[] text) {
if (Registry.is("editor.disable.rtl")) return Collections.singletonList(new BidiRun((byte)0, 0, text.length));
Bidi bidi = new Bidi(text, 0, null, 0, text.length, Bidi.DIRECTION_LEFT_TO_RIGHT);
int runCount = bidi.getRunCount();
List<BidiRun> runs = new ArrayList<BidiRun>(runCount);
@@ -19,17 +19,16 @@ import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphJustificationInfo;
import java.awt.font.GlyphMetrics;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
/**
* Fragment of text using a common font
*/
class TextFragment implements LineFragment {
// glyph location that should definitely be outside of painted region
private static final Point NOWHERE = new Point(Integer.MIN_VALUE, Integer.MIN_VALUE);
@NotNull
private final GlyphVector myGlyphVector;
@NotNull
@@ -78,18 +77,42 @@ class TextFragment implements LineFragment {
assert startOffset >= 0;
assert endOffset <= myCharPositions.length;
assert startOffset < endOffset;
GlyphVector vector;
if (startOffset == 0 && endOffset == myCharPositions.length) {
vector = myGlyphVector;
g.drawGlyphVector(myGlyphVector, x, y);
}
else {
boolean isRtl = isRtl();
vector = new GlyphVectorWindow(myGlyphVector,
isRtl ? myCharPositions.length - endOffset : startOffset,
isRtl ? myCharPositions.length - startOffset : endOffset,
getX(startOffset));
// We cannot use our own GlyphVector implementation, as it wouldn't support
// Mac-specific automatic font fallback (negative glyph indices will be rejected,
// even though they are used inside StandardGlyphVector in that case).
// We also cannot clone myGlyphVector without casting to sun.font.StandardGlyphVector,
// as clone() method is not public in GlyphVector (even though it's Cloneable).
// So we are modifying glyph positions in-place, and restore them after painting.
int logicalStartOffset = isRtl() ? myCharPositions.length - endOffset : startOffset;
int logicalEndOffset = isRtl() ? myCharPositions.length - startOffset : endOffset;
int glyphCount = myGlyphVector.getNumGlyphs();
Point2D[] savedPositions = new Point2D[glyphCount + 1];
int lastPaintedGlyph = -1;
for (int i = 0; i < glyphCount; i++) {
savedPositions[i] = myGlyphVector.getGlyphPosition(i);
int c = myGlyphVector.getGlyphCharIndex(i);
if (c >= logicalStartOffset && c < logicalEndOffset) {
lastPaintedGlyph = i;
}
else {
myGlyphVector.setGlyphPosition(i, NOWHERE);
}
}
savedPositions[glyphCount] = myGlyphVector.getGlyphPosition(glyphCount);
myGlyphVector.setGlyphPosition(glyphCount, savedPositions[lastPaintedGlyph + 1]);
try {
g.drawGlyphVector(myGlyphVector, x - getX(startOffset), y);
}
finally {
for (int i = 0; i <= glyphCount; i++) {
myGlyphVector.setGlyphPosition(i, savedPositions[i]);
}
}
}
g.drawGlyphVector(vector, x, y);
}
private boolean isRtl() {
@@ -144,188 +167,6 @@ class TextFragment implements LineFragment {
return startX + getX(column);
}
/**
* GlyphVector that represents a portion of another (previously laid out) GlyphVector
*/
private static class GlyphVectorWindow extends GlyphVector {
private final GlyphVector myDelegate;
private final int[] myGlyphMap;
private final int myStartChar;
private final float myStartX;
GlyphVectorWindow(@NotNull GlyphVector delegate, int startOffset, int endOffset, float startX) {
myDelegate = delegate;
myStartChar = startOffset;
myStartX = startX;
int glyphCount = 0;
for (int i = 0; i < delegate.getNumGlyphs(); i++) {
int c = delegate.getGlyphCharIndex(i);
if (c >= startOffset && c < endOffset) {
glyphCount++;
}
}
assert glyphCount > 0;
myGlyphMap = new int[glyphCount];
int p = 0;
for (int i = 0; i < delegate.getNumGlyphs(); i++) {
int c = delegate.getGlyphCharIndex(i);
if (c >= startOffset && c < endOffset) {
myGlyphMap[p++] = i;
}
}
}
@Override
public Font getFont() {
return myDelegate.getFont();
}
@Override
public FontRenderContext getFontRenderContext() {
return myDelegate.getFontRenderContext();
}
@Override
public int getNumGlyphs() {
return myGlyphMap.length;
}
@Override
public int getGlyphCode(int glyphIndex) {
return myDelegate.getGlyphCode(myGlyphMap[glyphIndex]);
}
@Override
public int[] getGlyphCodes(int beginGlyphIndex, int numEntries, int[] codeReturn) {
if (codeReturn == null) {
codeReturn = new int[numEntries];
}
for (int i = 0; i < numEntries; i++) {
codeReturn[i] = myDelegate.getGlyphCode(myGlyphMap[beginGlyphIndex + i]);
}
return codeReturn;
}
@Override
public int getLayoutFlags() {
return myDelegate.getLayoutFlags() | FLAG_HAS_POSITION_ADJUSTMENTS;
}
@Override
public int getGlyphCharIndex(int glyphIndex) {
return myDelegate.getGlyphCharIndex(myGlyphMap[glyphIndex]) - myStartChar;
}
@Override
public int[] getGlyphCharIndices(int beginGlyphIndex, int numEntries, int[] codeReturn) {
if (codeReturn == null) {
codeReturn = new int[numEntries];
}
for (int i = 0; i < numEntries; i++) {
codeReturn[i] = myDelegate.getGlyphCharIndex(myGlyphMap[beginGlyphIndex + i]) - myStartChar;
}
return codeReturn;
}
@Override
public Point2D getGlyphPosition(int glyphIndex) {
Point2D.Float pos = (Point2D.Float) myDelegate.getGlyphPosition(glyphIndex < myGlyphMap.length ?
myGlyphMap[glyphIndex] :
myGlyphMap[glyphIndex - 1] + 1);
pos.x -= myStartX;
return pos;
}
@Override
public float[] getGlyphPositions(int beginGlyphIndex, int numEntries, float[] positionReturn) {
if (positionReturn == null) {
positionReturn = new float[numEntries * 2];
}
for (int i = 0; i < numEntries; i++) {
int index = beginGlyphIndex + i;
int delegateIndex = index < myGlyphMap.length ? myGlyphMap[index] : myGlyphMap[index - 1] + 1;
Point2D.Float pos = (Point2D.Float) myDelegate.getGlyphPosition(delegateIndex);
positionReturn[i * 2] = pos.x - myStartX;
positionReturn[i * 2 + 1] = pos.y;
}
return positionReturn;
}
@Override
public AffineTransform getGlyphTransform(int glyphIndex) {
return myDelegate.getGlyphTransform(myGlyphMap[glyphIndex]);
}
@Override
public void performDefaultLayout() {
throw new UnsupportedOperationException();
}
@Override
public Rectangle2D getLogicalBounds() {
throw new UnsupportedOperationException();
}
@Override
public Rectangle2D getVisualBounds() {
throw new UnsupportedOperationException();
}
@Override
public Shape getOutline() {
throw new UnsupportedOperationException();
}
@Override
public Shape getOutline(float x, float y) {
throw new UnsupportedOperationException();
}
@Override
public Shape getGlyphOutline(int glyphIndex) {
throw new UnsupportedOperationException();
}
@Override
public void setGlyphPosition(int glyphIndex, Point2D newPos) {
throw new UnsupportedOperationException();
}
@Override
public void setGlyphTransform(int glyphIndex, AffineTransform newTX) {
throw new UnsupportedOperationException();
}
@Override
public Shape getGlyphLogicalBounds(int glyphIndex) {
throw new UnsupportedOperationException();
}
@Override
public Shape getGlyphVisualBounds(int glyphIndex) {
throw new UnsupportedOperationException();
}
@Override
public GlyphMetrics getGlyphMetrics(int glyphIndex) {
throw new UnsupportedOperationException();
}
@Override
public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex) {
throw new UnsupportedOperationException();
}
@SuppressWarnings("CovariantEquals")
@Override
public boolean equals(GlyphVector set) {
throw new UnsupportedOperationException();
}
}
private class TextFragmentWindow implements LineFragment {
private final int myStartOffset;
private final int myEndOffset;
@@ -271,7 +271,9 @@ class VisualLineFragmentsIterator implements Iterator<VisualLineFragmentsIterato
if (myDelegate == null) {
LineLayout foldRegionLayout = myView.getFoldRegionLayout(myFoldRegion);
TextAttributes attributes = myView.getEditor().getFoldingModel().getPlaceholderAttributes();
myView.getPainter().paintLineLayoutWithEffect(g, foldRegionLayout, x, y, attributes.getEffectColor(), attributes.getEffectType());
myView.getPainter().paintLineLayoutWithEffect(g, foldRegionLayout, x, y,
attributes == null ? null : attributes.getEffectColor(),
attributes == null ? null : attributes.getEffectType());
}
else {
int lineStartOffset = myDocument.getLineStartOffset(myCurrentStartLogicalLine);
@@ -389,7 +389,12 @@ public class ProjectJdkImpl extends UserDataHolderBase implements JDOMExternaliz
}
public void update() {
myRootContainer.update();
try {
myRootContainer.update();
}
finally {
resetVersionString();
}
}
@Override
@@ -18,6 +18,7 @@ package com.intellij.vcs.log.ui.frame;
import com.intellij.icons.AllIcons;
import com.intellij.ide.CopyProvider;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ide.CopyPasteManager;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.Pair;
@@ -69,6 +70,7 @@ import java.util.*;
import java.util.List;
public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, CopyProvider {
private static final Logger LOG = Logger.getInstance(VcsLogGraphTable.class);
public static final int ROOT_INDICATOR_COLORED_WIDTH = 8;
public static final int ROOT_INDICATOR_WHITE_WIDTH = 5;
@@ -336,9 +338,16 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C
}
private VcsLogHighlighter.VcsCommitStyle getStyle(int row, int column, String text, boolean hasFocus, final boolean selected) {
final RowInfo<Integer> rowInfo = myDataPack.getVisibleGraph().getRowInfo(row);
Component dummyRendererComponent = myDummyRenderer.getTableCellRendererComponent(this, text, selected, hasFocus, row, column);
VisibleGraph<Integer> visibleGraph = myDataPack.getVisibleGraph();
if (row < 0 || row >= visibleGraph.getVisibleCommitCount()) {
LOG.error("Visible graph has " + visibleGraph.getVisibleCommitCount() + " commits, yet we want row " + row);
return VcsCommitStyleFactory.createStyle(dummyRendererComponent.getForeground(), dummyRendererComponent.getBackground());
}
final RowInfo<Integer> rowInfo = visibleGraph.getRowInfo(row);
VcsLogHighlighter.VcsCommitStyle defaultStyle = VcsCommitStyleFactory
.createStyle(rowInfo.getRowType() == RowType.UNMATCHED ? JBColor.GRAY : dummyRendererComponent.getForeground(),
dummyRendererComponent.getBackground());
@@ -43,7 +43,7 @@ public class GitTaskHandler extends DvcsTaskHandler<GitRepository> {
@Override
protected void checkout(@NotNull String taskName, @NotNull List<GitRepository> repos, @Nullable Runnable callInAwtLater) {
myBrancher.checkout(taskName, repos, callInAwtLater);
myBrancher.checkout(taskName, false, repos, callInAwtLater);
}
@Override
@@ -28,7 +28,7 @@ public class GitCheckoutRevisionAction extends GitLogSingleCommitAction {
@Override
protected void actionPerformed(@NotNull GitRepository repository, @NotNull VcsFullCommitDetails commit) {
GitBrancher brancher = ServiceManager.getService(repository.getProject(), GitBrancher.class);
brancher.checkout(commit.getId().asString(), Collections.singletonList(repository), null);
brancher.checkout(commit.getId().asString(), false, Collections.singletonList(repository), null);
}
}
@@ -92,12 +92,12 @@ public final class GitBranchWorker {
public void checkoutNewBranchStartingFrom(@NotNull String newBranchName, @NotNull String startPoint,
@NotNull List<GitRepository> repositories) {
updateInfo(repositories);
new GitCheckoutOperation(myProject, myFacade, myGit, myUiHandler, repositories, startPoint, newBranchName).execute();
new GitCheckoutOperation(myProject, myFacade, myGit, myUiHandler, repositories, startPoint, false, newBranchName).execute();
}
public void checkout(@NotNull final String reference, @NotNull List<GitRepository> repositories) {
public void checkout(@NotNull final String reference, boolean detach, @NotNull List<GitRepository> repositories) {
updateInfo(repositories);
new GitCheckoutOperation(myProject, myFacade, myGit, myUiHandler, repositories, reference, null).execute();
new GitCheckoutOperation(myProject, myFacade, myGit, myUiHandler, repositories, reference, detach, null).execute();
}
@@ -60,18 +60,21 @@ public interface GitBrancher {
* If local changes prevent the checkout, shows the list of them and proposes to make a "smart checkout":
* stash-checkout-unstash.</p>
* <p>Doesn't check the reference for validity.</p>
*
* @param reference reference to be checked out.
* @param detach if true, checkout operation will put the repository into the detached HEAD state
* (useful if one wants to checkout a remote branch position, but not create a new tracking local branch);
* if false, it will behave the same as {@code git checkout} command does, i.e. switch to the local branch,
* create a local branch tracking the given remote branch, checkout hash or tag into the detached HEAD.
* @param repositories repositories to operate on.
* @param callInAwtLater the Runnable that should be called after execution of the method (both successful and unsuccessful).
* If given, it will be called in the EDT {@link javax.swing.SwingUtilities#invokeLater(Runnable) later}.
* If given, it will be called in the EDT {@link javax.swing.SwingUtilities#invokeLater(Runnable) later}.
*/
void checkout(@NotNull String reference, @NotNull List<GitRepository> repositories, @Nullable Runnable callInAwtLater);
void checkout(@NotNull String reference, boolean detach, @NotNull List<GitRepository> repositories, @Nullable Runnable callInAwtLater);
/**
* Creates and checks out a new local branch starting from the given reference:
* {@code git checkout -b <branchname> <start-point>}. <br/>
* Provides the "smart checkout" procedure the same as in {@link #checkout(String, java.util.List, Runnable)}.
* Provides the "smart checkout" procedure the same as in {@link #checkout(String, boolean, List, Runnable)}.
*
* @param newBranchName the name of the new local branch.
* @param startPoint the reference to checkout.
@@ -69,11 +69,13 @@ class GitBrancherImpl implements GitBrancher {
}
@Override
public void checkout(@NotNull final String reference, @NotNull final List<GitRepository> repositories,
public void checkout(@NotNull final String reference,
final boolean detach,
@NotNull final List<GitRepository> repositories,
@Nullable Runnable callInAwtLater) {
new CommonBackgroundTask(myProject, "Checking out " + reference, callInAwtLater) {
@Override public void execute(@NotNull ProgressIndicator indicator) {
newWorker(indicator).checkout(reference, repositories);
newWorker(indicator).checkout(reference, detach, repositories);
}
}.runInBackground();
}
@@ -104,7 +104,7 @@ class GitCheckoutNewBranchOperation extends GitBranchOperation {
GitCompoundResult deleteResult = new GitCompoundResult(myProject);
Collection<GitRepository> repositories = getSuccessfulRepositories();
for (GitRepository repository : repositories) {
GitCommandResult result = myGit.checkout(repository, myCurrentHeads.get(repository), null, true);
GitCommandResult result = myGit.checkout(repository, myCurrentHeads.get(repository), null, true, false);
checkoutResult.append(repository, result);
if (result.success()) {
deleteResult.append(repository, myGit.branchDelete(repository, myNewBranchName, false));
@@ -52,13 +52,20 @@ class GitCheckoutOperation extends GitBranchOperation {
public static final String ROLLBACK_PROPOSAL_FORMAT = "You may rollback (checkout back to previous branch) not to let branches diverge.";
@NotNull private final String myStartPointReference;
private final boolean myDetach;
@Nullable private final String myNewBranch;
GitCheckoutOperation(@NotNull Project project, GitPlatformFacade facade, @NotNull Git git, @NotNull GitBranchUiHandler uiHandler,
GitCheckoutOperation(@NotNull Project project,
GitPlatformFacade facade,
@NotNull Git git,
@NotNull GitBranchUiHandler uiHandler,
@NotNull Collection<GitRepository> repositories,
@NotNull String startPointReference, @Nullable String newBranch) {
@NotNull String startPointReference,
boolean detach,
@Nullable String newBranch) {
super(project, facade, git, uiHandler, repositories);
myStartPointReference = startPointReference;
myDetach = detach;
myNewBranch = newBranch;
}
@@ -78,8 +85,8 @@ class GitCheckoutOperation extends GitBranchOperation {
GitUntrackedFilesOverwrittenByOperationDetector untrackedOverwrittenByCheckout =
new GitUntrackedFilesOverwrittenByOperationDetector(root);
GitCommandResult result = myGit.checkout(repository, myStartPointReference, myNewBranch, false,
localChangesDetector, unmergedFiles, untrackedOverwrittenByCheckout);
GitCommandResult result = myGit.checkout(repository, myStartPointReference, myNewBranch, false, myDetach,
localChangesDetector, unmergedFiles, untrackedOverwrittenByCheckout);
if (result.success()) {
refresh(repository);
markSuccessful(repository);
@@ -171,7 +178,7 @@ class GitCheckoutOperation extends GitBranchOperation {
GitCompoundResult checkoutResult = new GitCompoundResult(myProject);
GitCompoundResult deleteResult = new GitCompoundResult(myProject);
for (GitRepository repository : getSuccessfulRepositories()) {
GitCommandResult result = myGit.checkout(repository, myCurrentHeads.get(repository), null, true);
GitCommandResult result = myGit.checkout(repository, myCurrentHeads.get(repository), null, true, false);
checkoutResult.append(repository, result);
if (result.success() && myNewBranch != null) {
/*
@@ -235,7 +242,7 @@ class GitCheckoutOperation extends GitBranchOperation {
@NotNull String reference, @Nullable String newBranch, boolean force) {
GitCompoundResult compoundResult = new GitCompoundResult(myProject);
for (GitRepository repository : repositories) {
compoundResult.append(repository, myGit.checkout(repository, reference, newBranch, force));
compoundResult.append(repository, myGit.checkout(repository, reference, newBranch, force, myDetach));
}
if (compoundResult.totalSuccess()) {
return true;
@@ -77,7 +77,11 @@ public interface Git {
@NotNull GitLineHandlerListener... listeners);
@NotNull
GitCommandResult checkout(@NotNull GitRepository repository, @NotNull String reference, @Nullable String newBranch, boolean force,
GitCommandResult checkout(@NotNull GitRepository repository,
@NotNull String reference,
@Nullable String newBranch,
boolean force,
boolean detach,
@NotNull GitLineHandlerListener... listeners);
@NotNull
@@ -236,10 +236,11 @@ public class GitImpl implements Git {
@NotNull
@Override
public GitCommandResult checkout(@NotNull GitRepository repository,
@NotNull String reference,
@Nullable String newBranch,
boolean force,
@NotNull GitLineHandlerListener... listeners) {
@NotNull String reference,
@Nullable String newBranch,
boolean force,
boolean detach,
@NotNull GitLineHandlerListener... listeners) {
final GitLineHandler h = new GitLineHandler(repository.getProject(), repository.getRoot(), GitCommand.CHECKOUT);
h.setSilent(false);
h.setStdoutSuppressed(false);
@@ -247,7 +248,7 @@ public class GitImpl implements Git {
h.addParameters("--force");
}
if (newBranch == null) { // simply checkout
h.addParameters(reference);
h.addParameters(detach ? reference + "^0" : reference); // we could use `--detach` here, but it is supported only since 1.7.5.
}
else { // checkout reference as new branch
h.addParameters("-b", newBranch, reference);
@@ -89,8 +89,10 @@ public class GitRebaseEditor extends DialogWrapper implements DataProvider {
myCommitsTable.setDefaultRenderer(String.class, new ColoredTableCellRenderer() {
@Override
protected void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
append(value.toString());
SpeedSearchUtil.applySpeedSearchHighlighting(myCommitsTable, this, true, selected);
if (value != null) {
append(value.toString());
SpeedSearchUtil.applySpeedSearchHighlighting(myCommitsTable, this, true, selected);
}
}
});
@@ -113,7 +113,7 @@ class GitBranchPopupActions {
.showInputDialog(myProject, "Enter reference (branch, tag) name or commit hash", "Checkout", Messages.getQuestionIcon());
if (reference != null) {
GitBrancher brancher = ServiceManager.getService(myProject, GitBrancher.class);
brancher.checkout(reference, Collections.singletonList(myRepository), null);
brancher.checkout(reference, true, Collections.singletonList(myRepository), null);
}
}
@@ -194,7 +194,7 @@ class GitBranchPopupActions {
@Override
public void actionPerformed(AnActionEvent e) {
GitBrancher brancher = ServiceManager.getService(myProject, GitBrancher.class);
brancher.checkout(myBranchName, myRepositories, null);
brancher.checkout(myBranchName, false, myRepositories, null);
}
}
@@ -646,7 +646,7 @@ class GitBranchWorkerTest extends GitPlatformTest {
def checkoutBranch(String name, def uiHandler) {
GitBranchWorker brancher = new GitBranchWorker(myProject, myPlatformFacade, myGit, uiHandler as GitBranchUiHandler)
brancher.checkout(name, myRepositories)
brancher.checkout(name, false, myRepositories)
}
def mergeBranch(String name, def uiHandler) {
@@ -33,6 +33,7 @@ public class TrelloIntegrationTest extends LiveIntegrationTestCase<TrelloReposit
private static final String CARD_1_1_1_NAME = "Card 1-1-1";
private static final String CARD_1_1_1_ID = "53c416d8b4bd36fb078446e5";
private static final String CARD_1_1_1_NUMBER = "1";
// Labels and colors
private static final String LABELS_AND_COLORS_BOARD_NAME = "Labels and Colors";
@@ -217,6 +218,14 @@ public class TrelloIntegrationTest extends LiveIntegrationTestCase<TrelloReposit
assertEquals(BACKLOG_LIST_ID, card.getIdList());
}
// IDEA-139903
public void testCardBoardLocalNumber() throws Exception {
final TrelloCard card = myRepository.fetchCardById(CARD_1_1_1_ID);
assertNotNull(card);
assertEquals(CARD_1_1_1_ID, card.getId());
assertEquals(CARD_1_1_1_NUMBER, new TrelloTask(card, myRepository).getNumber());
}
static void assertObjectsNamed(@NotNull String message, @NotNull Collection<? extends TrelloModel> objects, @NotNull String... names) {
assertEquals(message, ContainerUtil.newHashSet(names), ContainerUtil.map2Set(objects, new Function<TrelloModel, String>() {
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -15,6 +15,8 @@
*/
package com.intellij.uiDesigner;
import com.intellij.ui.Gray;
import com.intellij.ui.JBColor;
import com.intellij.uiDesigner.core.Spacer;
import java.awt.*;
@@ -32,7 +34,7 @@ abstract class DesignSpacer extends Spacer{
protected static final int SPRING_PRERIOD = 4;
protected static final Color ourColor1 = new Color(8,8,108);
protected static final Color ourColor2 = new Color(3,26,142);
protected static final Color ourColor3 = Color.BLACK;
protected static final Color ourColor1 = new JBColor(new Color(8,8,108), Gray._168);
protected static final Color ourColor2 = new JBColor(new Color(3, 26, 142), Gray._128);
protected static final Color ourColor3 = new JBColor(Gray._0, Gray._128);
}
@@ -8,7 +8,7 @@
<fileEditorProvider implementation="org.jetbrains.plugins.ipnb.editor.IpnbEditorProvider"/>
<fileTypeFactory implementation="org.jetbrains.plugins.ipnb.IpnbFileTypeFactory"/>
<projectConfigurable groupId="tools" instance="org.jetbrains.plugins.ipnb.configuration.IpnbConfigurable"
<projectConfigurable groupId="language" instance="org.jetbrains.plugins.ipnb.configuration.IpnbConfigurable"
id="org.jetbrains.plugins.ipnb.configuration.IpnbConfigurable" displayName="IPython Notebook"
nonDefaultProject="true"/>
<projectService serviceInterface="org.jetbrains.plugins.ipnb.configuration.IpnbSettings"