diff options
author | Tor Norbye <tnorbye@google.com> | 2014-01-06 10:22:20 -0800 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2014-01-06 10:22:24 -0800 |
commit | f2f7178ad6915927d918481b911e57a49785e4c4 (patch) | |
tree | c2b0f8906d38f5f1e2f5da853c67e09205816bf6 /platform | |
parent | 8668e1be0891658129cbc8f0965380f702c26755 (diff) | |
download | idea-f2f7178ad6915927d918481b911e57a49785e4c4.tar.gz |
Snapshot c11f3ac9bbde3f85d1f837ec3eb48a395ed7dd10 from idea/133.471 of git://git.jetbrains.org/idea/community.git
c11f3ac: faster xml properties indexing: don't process if no required namespace string present (cherry picked from commit 0845f9e) [r=Dmitry.Avdeev]
0be6c40: to get version sort copy of ClsStubBuilderFactory implementation array (cherry picked from commit c34b260) [r=Alexander.Podkhalusin]
8ed9df6: IDEA-116087 Warning when using new wrapper.gradleVersion construction (cherry picked from commit d3a81f0)
d33b33a: Gradle: fix check for gradle-related files (cherry picked from commit 140b618)
e8c50fa: Gradle: fix creation/sync of gradle wrapper files on project import
3fcf435: IDEA-99036 Changing breakpoint suspend policy from popup does not actually change the policy
033cdba: IDEA-116636 Android-Gradle facet is created when Gradle synchronization. related bug IDEA-116887 Gradle web artifacts do not contain compiled classes and JSP files (cherry picked from commit 64e7f51)
1f4d754: EA-52867 (null check)
3e2b5c5: proper processing of dom indices, 2 (cherry picked from commit e9d6759)
7061e85: proper processing of dom indices (cherry picked from commit e5401d6)
e04883d: proper implementation and usage of indices for DOMStubs
5fa6cf9: do not load/try to index inner classes content / delegate to ClsStubBuilder for inner class identification (cherry picked from commit a085c19) [r=Alexander.Podkhalusin]
3a8fd3f: - use all BinaryStubBuilders versions in stable order to calculate stub version - introduce version for ClassStubBuilderFactory and use all class stub builder factories in stable order to calculate version of ClassFileStubBuilder [r=Eugene.Zhuravlev, Alexander.Podkhalusin]
57e7213: IDEA-118436 Resource Bundle Editor converts UTF8 characters to ASCII even in UTF8 file
1dc12b4: IDEA-112730 PhpStorm goes crazy with collapsed comments and soft wraps until crash
eee52a9: IDEA-112730 PhpStorm goes crazy with collapsed comments and soft wraps until crash
c187921: IDEA-112730 PhpStorm goes crazy with collapsed comments and soft wraps until crash
2119489: ActionTestCase extracted from CoffeeScript and Puppet (cherry picked from commit be905df)
12e8b76: Overriding language in VariableInplaceRenamer. (CoffeeScript) (cherry picked from commit b459118)
c9069d1: IDEA-118587 IDEA may not exit with black window (cherry picked from commit a622b21)
6733c9e: WEB-9566 Debugger: optionally ignore certificate errors (cherry picked from commit af49f19)
da588bc: move CertificatesManager to platform (cherry picked from commit 6dc50e6)
f11ceb2: WEB-8262 Comment with line/block comment STILL doesn't work on HTML in ASP file (cherry picked from commit a83731c) [r=Rustam.Vyshnyakov]
8cfe207: WEB-849 "Comment with line comment" on empty line in <script> block generates HTML instead of JS comment (cherry picked from commit 73a14ec) [r=Rustam.Vyshnyakov]
36cf71c: WEB-6700 TODOs not recognized on multiple level language template (cherry picked from commit 9d00810) [r=Alexey.Gopachenko]
146d0c3: IDEA-118701 Multimodule project imported into IDEA via opening project file gets incorrect project name (cherry picked from commit 0912313)
25e5150: Bug fix: check not-null (cherry picked from commit 6b54183)
80932f6: IDEA-118601 New Module: Maven: click on "Create from archetype" reverts typed coordinates (cherry picked from commit d94c9a1)
a419509: IDEA-116593 improve choosing of Android and Java SDKs when creating new android-gradle project/module: choose only Android SDK location (if we don't know it) on first step, not build target; choose Java SDK (if there is no any) separately, set it as project sdk and as internal jdk for newly created android sdk entities (cherry picked from commit 2bf19b4)
e889183: Fixed IDEA-116006 Eclipse code style import: import the same xml does not pick up changes until manual synchronization (cherry picked from commit f6e9d9d)
fd2b92e: licenses missing licenses for libraries used by android
b5b25e5: Fixed IDEA-117788 Eclipse code style import: continuation indent is imported not multiplied to tab size (cherry picked from commit a9768ee)
074876e: remove all indexed state upon invalidateIndicesForFile (r=Eugene.Zhuravlev)
caa4032: EA-35422 - IOOBE: EditorImpl.offsetToLogicalLine (from debugger) (cherry picked from commit c21cd02) [r=Peter.Gromov]
b47b369: attach messages to root node if no running node found (cherry picked from commit 5c66005)
02cf0b4: [log] Flush & Close persistent enumerator on dispose()
f84ff13: better way to instantiate PersistentHashMap
36d590f: [git] Wrap the VcsException not to loose the cause
339dede: [log] IDEA-115407 Disable graph-only-actions if there is no graph
3773e2c: [log] IDEA-115568 Don't crash if the log is empty
cafe1a8: [log] IDEA-115901 Keep selection between refreshes and filtering
8169bbe: [log] rename type parameter to a more descriptive name
0548151: [log] remove pointless code
29f0909: [log] Don't use setFont(), instead supply value in getFont()
82f67f7: [log] IDEA-117816 small optimization in graph cell drawing
1acba78: IDEA-102942 Wrap always Chained methods calls over-format simple operations (cherry picked from commit 835ed38)
8ef13e9: IDEA-118613: catch all possible exceptions, that may be caused by corrupted storages
0654f14: IDEA-96131 Java: Braces placements don't work as expected for `Next Line` [CR-IC-3694] (cherry picked from commit 975cfe8)
ee689af: WEB-10387 Mocha console log statements are not correctly aligned to their encasing tests (cherry picked from commit 6018640)
b6b35e2: WEB-9517 Npm: Error loading package list (cherry picked from commit aa82d2a)
07d7344: test fix: explicit encoding is required
257ac80: cleanup
9b46832: IDEA-93034 SQL: MySQL: erasing the first backtick could erase the pair
6da1645: in case when some output and source roots intersect: do not stop rebuild if caches version is advanced (IDEA-118613)
631aea6: separate checks if compiler is enabled and compiler api is supported by compiler implementation
4ecc2a5: external build: added method to register output directory in source-to-output mapping instead of registering individual files to reduce occupied disk space (ZD-16651) [rev by Jeka]
f344db7: don't copy ui-designer runtime classes to output if only NetBeans *.form files are found (ZD-14954) [rev by Jeka]
88de860: standalone JPS build: propagate 'forceBuild' option to dependencies implicitly included into compile scope [rev by Jeka]
cbec9d7: [^Peter] EA-50899 - ISE: GrRegexImpl.createLiteralTextEscaper
3013e02: [^Peter] IDEA-117828 Groovy console: execute groovy code shortcut changed back
6ad8dbf: [^Peter] IDEA-117292 Groovy: checks for @Immutable class
8d2c8cf: EA-52292 fix (PHP template inside HTML comment case) (cherry picked from commit 41ccbd2)
1fc4a80: IDEA-118595
0f7f3a1: cleanup imports
09b3d12: style
efdd1aa: OutputSuppressed option added for HgCommandExecutor, style changed, unnecessary parameters removed (cherry picked from commit 4d55fdd)
12789c5: cosmetics: revision hash template changed to long. (cherry picked from commit f1c78e1)
57c3348: Parents revision hash template changed to long. (cherry picked from commit 32ab1db)
b70b45e: IDEA-118266 time measurements for all Mercurial commands added and log command debug output suppressed. (cherry picked from commit 75ec80e)
f44f8d8: [^maxmedvedev] gdsl: be prepared to multithreaded scripts (cherry picked from commit a240a44)
6121316: + "trie" (cherry picked from commit 669ae41)
3c8884d: IDEA-118552 Generated ANT scripts do not honour cross-compile settings
Change-Id: I18c031b09527bf8c7de6a529b546e66950a816d3
Diffstat (limited to 'platform')
41 files changed, 1091 insertions, 126 deletions
diff --git a/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/id/PlatformIdTableBuilding.java b/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/id/PlatformIdTableBuilding.java index 556db38f3b54..2661e6a6a069 100644 --- a/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/id/PlatformIdTableBuilding.java +++ b/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/id/PlatformIdTableBuilding.java @@ -163,7 +163,7 @@ public abstract class PlatformIdTableBuilding { highlighter = editorHighlighter; } else { - highlighter = HighlighterFactory.createHighlighter(null, myFile); + highlighter = HighlighterFactory.createHighlighter(inputData.getProject(), myFile); highlighter.setText(chars); } diff --git a/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java b/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java index b9f8ec632b3c..dca89ac7bf8a 100644 --- a/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java +++ b/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java @@ -28,6 +28,7 @@ import com.intellij.psi.search.IndexPatternProvider; import com.intellij.psi.tree.TokenSet; import com.intellij.util.indexing.*; import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.IntInlineKeyDescriptor; import com.intellij.util.io.KeyDescriptor; import com.intellij.util.messages.MessageBus; import org.jetbrains.annotations.NonNls; @@ -82,15 +83,10 @@ public class TodoIndex extends FileBasedIndexExtension<TodoIndexEntry, Integer> } }; - private final DataExternalizer<Integer> myValueExternalizer = new DataExternalizer<Integer>() { + private final DataExternalizer<Integer> myValueExternalizer = new IntInlineKeyDescriptor() { @Override - public void save(final DataOutput out, final Integer value) throws IOException { - out.writeInt(value.intValue()); - } - - @Override - public Integer read(final DataInput in) throws IOException { - return Integer.valueOf(in.readInt()); + protected boolean isCompactFormat() { + return true; } }; @@ -131,7 +127,7 @@ public class TodoIndex extends FileBasedIndexExtension<TodoIndexEntry, Integer> @Override public int getVersion() { - return 5; + return 6; } @Override diff --git a/platform/editor-ui-ex/src/com/intellij/psi/impl/search/IndexPatternSearcher.java b/platform/editor-ui-ex/src/com/intellij/psi/impl/search/IndexPatternSearcher.java index d108c6030e6c..adc24b1a1c95 100644 --- a/platform/editor-ui-ex/src/com/intellij/psi/impl/search/IndexPatternSearcher.java +++ b/platform/editor-ui-ex/src/com/intellij/psi/impl/search/IndexPatternSearcher.java @@ -29,6 +29,7 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; +import com.intellij.psi.impl.cache.CacheUtil; import com.intellij.psi.impl.cache.TodoCacheManager; import com.intellij.psi.search.IndexPattern; import com.intellij.psi.search.IndexPatternOccurrence; @@ -187,15 +188,7 @@ public class IndexPatternSearcher implements QueryExecutor<IndexPatternOccurrenc if (lexer.getTokenStart() >= range.getEndOffset()) break; } - boolean isComment = commentTokens.contains(tokenType); - if (!isComment) { - final Language commentLang = tokenType.getLanguage(); - final ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(commentLang); - if (parserDefinition != null) { - final TokenSet langCommentTokens = parserDefinition.getCommentTokens(); - isComment = langCommentTokens.contains(tokenType); - } - } + boolean isComment = commentTokens.contains(tokenType) || CacheUtil.isInComments(tokenType); if (isComment) { final int startDelta = builderForFile != null ? builderForFile.getCommentStartDelta(lexer.getTokenType()) : 0; diff --git a/platform/indexing-impl/src/com/intellij/psi/stubs/StubProcessingHelperBase.java b/platform/indexing-impl/src/com/intellij/psi/stubs/StubProcessingHelperBase.java index 978a6c80c9e4..27f7d10b1646 100644 --- a/platform/indexing-impl/src/com/intellij/psi/stubs/StubProcessingHelperBase.java +++ b/platform/indexing-impl/src/com/intellij/psi/stubs/StubProcessingHelperBase.java @@ -37,6 +37,7 @@ public abstract class StubProcessingHelperBase { PsiFile _psifile = PsiManager.getInstance(project).findFile(file); PsiFileWithStubSupport psiFile = null; + boolean customStubs = false; if (_psifile != null && !(_psifile instanceof PsiPlainTextFile)) { _psifile = _psifile.getViewProvider().getStubBindingRoot(); @@ -44,7 +45,9 @@ public abstract class StubProcessingHelperBase { psiFile = (PsiFileWithStubSupport)_psifile; stubTree = psiFile.getStubTree(); if (stubTree == null && psiFile instanceof PsiFileImpl) { - stubTree = ((PsiFileImpl)psiFile).calcStubTree(); + BinaryFileStubBuilder stubBuilder = BinaryFileStubBuilders.INSTANCE.forFileType(psiFile.getFileType()); + if (stubBuilder == null) stubTree = ((PsiFileImpl)psiFile).calcStubTree(); + else customStubs = true; } } } @@ -57,6 +60,9 @@ public abstract class StubProcessingHelperBase { if (objectStubTree == null) { return true; } + if (customStubs && !(objectStubTree instanceof StubTree)) { + return processor.process((Psi)psiFile); // e.g. dom indices + } stubTree = (StubTree)objectStubTree; final List<StubElement<?>> plained = stubTree.getPlainList(); for (int i = 0, size = value.size(); i < size; i++) { diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/ManageCodeStyleSchemesDialog.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/ManageCodeStyleSchemesDialog.java index bd324f7d7246..071330cc4d80 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/ManageCodeStyleSchemesDialog.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/ManageCodeStyleSchemesDialog.java @@ -217,6 +217,7 @@ public class ManageCodeStyleSchemesDialog extends DialogWrapper { VirtualFile[] selection = fileChooser.choose(CodeStyleSchemesUIConfiguration.Util.getRecentImportFile(), null); if (selection.length == 1) { VirtualFile selectedFile = selection[0]; + selectedFile.refresh(false, false); CodeStyleSchemesUIConfiguration.Util.setRecentImportFile(selectedFile); try { InputStream nameInputStream = selectedFile.getInputStream(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BackspaceHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BackspaceHandler.java index c4379e2f223b..6017a40b4a9b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BackspaceHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/BackspaceHandler.java @@ -129,7 +129,7 @@ public class BackspaceHandler extends EditorWriteActionHandler { editor.getDocument().deleteString(offset, offset + 1); } - else if (c == '"' || c == '\''){ + else if (c == '"' || c == '\'' || c == '`'){ char c1 = chars.charAt(offset); if (c1 != c) return true; if (wasClosingQuote) return true; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java index b6c0f77f1a9f..75ae804182d5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java @@ -213,8 +213,15 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler { int offset = myDocument.getLineStartOffset(myStartLine); offset = CharArrayUtil.shiftForward(myDocument.getCharsSequence(), offset, " \t"); - final Language languageSuitableForCompleteFragment = PsiUtilBase.reallyEvaluateLanguageInRange(offset, CharArrayUtil.shiftBackward( - myDocument.getCharsSequence(), myDocument.getLineEndOffset(myEndLine), " \t\n"), myFile); + int endOffset = CharArrayUtil.shiftBackward(myDocument.getCharsSequence(), myDocument.getLineEndOffset(myEndLine), " \t\n"); + final Language languageSuitableForCompleteFragment; + if (offset >= endOffset) { // we are on empty line + PsiElement element = myFile.findElementAt(offset); + if (element != null) languageSuitableForCompleteFragment = element.getParent().getLanguage(); + else languageSuitableForCompleteFragment = null; + } else { + languageSuitableForCompleteFragment = PsiUtilBase.reallyEvaluateLanguageInRange(offset, endOffset, myFile); + } Commenter blockSuitableCommenter = languageSuitableForCompleteFragment == null ? LanguageCommenters.INSTANCE.forLanguage(myFile.getLanguage()) : null; diff --git a/platform/lang-impl/src/com/intellij/execution/runners/AbstractConsoleRunnerWithHistory.java b/platform/lang-impl/src/com/intellij/execution/runners/AbstractConsoleRunnerWithHistory.java index 55d8c3940017..818ab3cb2126 100644 --- a/platform/lang-impl/src/com/intellij/execution/runners/AbstractConsoleRunnerWithHistory.java +++ b/platform/lang-impl/src/com/intellij/execution/runners/AbstractConsoleRunnerWithHistory.java @@ -246,7 +246,7 @@ public abstract class AbstractConsoleRunnerWithHistory<T extends LanguageConsole public static AnAction createConsoleExecAction(final LanguageConsoleImpl languageConsole, final ProcessHandler processHandler, final ConsoleExecuteActionHandler consoleExecuteActionHandler) { - return new ConsoleExecuteAction(languageConsole, consoleExecuteActionHandler, ConsoleExecuteAction.CONSOLE_EXECUTE_ACTION_ID, + return new ConsoleExecuteAction(languageConsole, consoleExecuteActionHandler, consoleExecuteActionHandler.getEmptyExecuteAction(), new LanguageConsoleBuilder.ProcessBackedExecutionEnabledCondition(processHandler)); } diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java index adbc722f6d10..376561535a1e 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java @@ -62,7 +62,7 @@ public class VariableInplaceRenamer extends InplaceRefactoring { ); private ResolveSnapshotProvider.ResolveSnapshot mySnapshot; private TextRange mySelectedRange; - private Language myLanguage; + protected Language myLanguage; public VariableInplaceRenamer(@NotNull PsiNamedElement elementToRename, Editor editor) { this(elementToRename, editor, elementToRename.getProject()); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index 6f803ce35d66..cfadaeedc1dc 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -1775,7 +1775,6 @@ public class FileBasedIndexImpl extends FileBasedIndex { // important: no hard referencing currentFC to avoid OOME, the methods introduced for this purpose! final Computable<Boolean> update = index.update(inputId, currentFC); - final FileType fileType = file.getFileType(); scheduleUpdate(indexId, createUpdateComputableWithBufferingDisabled(update), @@ -1972,7 +1971,6 @@ public class FileBasedIndexImpl extends FileBasedIndex { if (!fileIsDirectory && !isTooLarge(file)) { final List<ID<?, ?>> candidates = getAffectedIndexCandidates(file); //noinspection ForLoopReplaceableByForEach - FileType fileType = file.getFileType(); boolean scheduleForUpdate = false; boolean resetStamp = false; @@ -2039,7 +2037,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { cleanProcessedFlag(file); IndexingStamp.flushCache(file); - final List<ID<?, ?>> affectedIndexCandidates = getAffectedIndexCandidates(file); + final List<ID<?, ?>> affectedIndexCandidates = IndexingStamp.getIndexedIds(file); final List<ID<?, ?>> affectedIndices = new ArrayList<ID<?, ?>>(affectedIndexCandidates.size()); //noinspection ForLoopReplaceableByForEach @@ -2047,14 +2045,10 @@ public class FileBasedIndexImpl extends FileBasedIndex { final ID<?, ?> indexId = affectedIndexCandidates.get(i); try { if (!needsFileContentLoading(indexId)) { - if (shouldUpdateIndex(file, indexId)) { - updateSingleIndex(indexId, file, null); - } + updateSingleIndex(indexId, file, null); } else { // the index requires file content - if (shouldUpdateIndex(file, indexId)) { - affectedIndices.add(indexId); - } + affectedIndices.add(indexId); } } catch (StorageException e) { @@ -2069,7 +2063,6 @@ public class FileBasedIndexImpl extends FileBasedIndex { ApplicationManager.getApplication().runReadAction(new Runnable() { @Override public void run() { - FileType fileType = file.getFileType(); for (ID<?, ?> indexId : affectedIndices) { IndexingStamp.update(file, indexId, IndexInfrastructure.INVALID_STAMP2); } @@ -2408,11 +2401,6 @@ public class FileBasedIndexImpl extends FileBasedIndex { } } - private boolean shouldUpdateIndex(final VirtualFile file, final ID<?, ?> indexId) { - return getInputFilter(indexId).acceptInput(file) && - (isMock(file) || isFileIndexed(file, indexId)); - } - private boolean shouldIndexFile(final VirtualFile file, final ID<?, ?> indexId) { return getInputFilter(indexId).acceptInput(file) && (isMock(file) || !isFileIndexed(file, indexId)); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java b/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java index 8531bcf688eb..35a304ef77e5 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java @@ -18,18 +18,21 @@ package com.intellij.util.indexing; import com.intellij.openapi.vfs.InvalidVirtualFileAccessException; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileWithId; import com.intellij.openapi.vfs.newvfs.FileAttribute; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; +import com.intellij.util.SmartList; import com.intellij.util.containers.ConcurrentHashMap; import com.intellij.util.io.DataInputOutputUtil; import gnu.trove.TObjectLongHashMap; import gnu.trove.TObjectLongProcedure; +import gnu.trove.TObjectProcedure; import org.jetbrains.annotations.Nullable; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.List; +import java.util.Collections; import java.util.concurrent.ArrayBlockingQueue; /** @@ -178,6 +181,28 @@ public class IndexingStamp { } } + public static List<ID<?,?>> getIndexedIds(final VirtualFile file) { + synchronized (getStripedLock(file)) { + try { + Timestamps stamp = createOrGetTimeStamp(file); + if (stamp != null && stamp.myIndexStamps != null && !stamp.myIndexStamps.isEmpty()) { + final SmartList<ID<?, ?>> retained = new SmartList<ID<?, ?>>(); + stamp.myIndexStamps.forEach(new TObjectProcedure<ID<?, ?>>() { + @Override + public boolean execute(ID<?, ?> object) { + retained.add(object); + return true; + } + }); + return retained; + } + } + catch (InvalidVirtualFileAccessException ignored /*ok to ignore it here*/) { + } + } + return Collections.emptyList(); + } + public static void flushCaches() { flushCache(null); myTimestampsCache.clear(); diff --git a/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java b/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java index bfa99455c1a0..b18187610774 100644 --- a/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java +++ b/platform/lang-impl/src/com/intellij/webcore/packaging/InstalledPackagesPanel.java @@ -33,6 +33,7 @@ import java.util.*; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; public class InstalledPackagesPanel extends JPanel { protected final JButton myInstallButton; @@ -397,8 +398,11 @@ public class InstalledPackagesPanel extends JPanel { final Collection<InstalledPackage> finalPackages = packages; final Map<String, RepoPackage> cache = buildNameToPackageMap(packageManagementService.getAllPackagesCached()); + final boolean shouldFetchLatestVersionsForOnlyInstalledPackages = shouldFetchLatestVersionsForOnlyInstalledPackages(); if (cache.isEmpty()) { - refreshLatestVersions(); + if (!shouldFetchLatestVersionsForOnlyInstalledPackages) { + refreshLatestVersions(); + } } application.invokeLater(new Runnable() { @Override @@ -414,6 +418,9 @@ public class InstalledPackagesPanel extends JPanel { if (!cache.isEmpty()) { myPackagesTable.setPaintBusy(false); } + if (shouldFetchLatestVersionsForOnlyInstalledPackages) { + setLatestVersionsForInstalledPackages(); + } } } }, ModalityState.any()); @@ -423,6 +430,69 @@ public class InstalledPackagesPanel extends JPanel { }); } + private InstalledPackage getInstalledPackageAt(int index) { + return (InstalledPackage) myPackagesTableModel.getValueAt(index, 0); + } + + private void setLatestVersionsForInstalledPackages() { + final PackageManagementServiceEx serviceEx = getServiceEx(); + if (serviceEx == null) { + return; + } + final AtomicInteger restPackageCount = new AtomicInteger(0); + for (int i = 0; i < myPackagesTableModel.getRowCount(); ++i) { + final int finalIndex = i; + final InstalledPackage pkg = getInstalledPackageAt(finalIndex); + restPackageCount.incrementAndGet(); + serviceEx.fetchLatestVersion(pkg.getName(), new CatchingConsumer<String, Exception>() { + + private void decrement() { + if (restPackageCount.decrementAndGet() == 0) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + myPackagesTable.setPaintBusy(false); + } + }, ModalityState.any()); + } + } + + @Override + public void consume(Exception e) { + decrement(); + } + + @Override + public void consume(@Nullable final String latestVersion) { + if (latestVersion == null) { + decrement(); + return; + } + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + if (finalIndex < myPackagesTableModel.getRowCount()) { + InstalledPackage p = getInstalledPackageAt(finalIndex); + if (pkg == p) { + myPackagesTableModel.setValueAt(latestVersion, finalIndex, 2); + } + } + decrement(); + } + }, ModalityState.any()); + } + }); + } + } + + private boolean shouldFetchLatestVersionsForOnlyInstalledPackages() { + PackageManagementServiceEx serviceEx = getServiceEx(); + if (serviceEx != null) { + return serviceEx.shouldFetchLatestVersionsForOnlyInstalledPackages(); + } + return false; + } + private void refreshLatestVersions() { final Application application = ApplicationManager.getApplication(); application.executeOnPooledThread(new Runnable() { diff --git a/platform/lang-impl/src/com/intellij/webcore/packaging/PackageManagementServiceEx.java b/platform/lang-impl/src/com/intellij/webcore/packaging/PackageManagementServiceEx.java index 8b53fe6b2747..7fb47ac0dbce 100644 --- a/platform/lang-impl/src/com/intellij/webcore/packaging/PackageManagementServiceEx.java +++ b/platform/lang-impl/src/com/intellij/webcore/packaging/PackageManagementServiceEx.java @@ -1,5 +1,6 @@ package com.intellij.webcore.packaging; +import com.intellij.util.CatchingConsumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -12,4 +13,8 @@ public abstract class PackageManagementServiceEx extends PackageManagementServic @Nullable String version, @NotNull Listener listener); + public abstract boolean shouldFetchLatestVersionsForOnlyInstalledPackages(); + + public abstract void fetchLatestVersion(@NotNull String packageName, @NotNull final CatchingConsumer<String, Exception> consumer); + } diff --git a/platform/platform-api/src/com/intellij/util/net/CertificatesManager.java b/platform/platform-api/src/com/intellij/util/net/CertificatesManager.java new file mode 100644 index 000000000000..1a6618664756 --- /dev/null +++ b/platform/platform-api/src/com/intellij/util/net/CertificatesManager.java @@ -0,0 +1,318 @@ +package com.intellij.util.net; + +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.io.StreamUtil; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * {@code CertificatesManager} is responsible for negotiation SSL connection with server + * that using trusted or self-signed certificates. + * + * @author Mikhail Golubev + */ +public class CertificatesManager { + private static final Logger LOG = Logger.getInstance(CertificatesManager.class); + private static final X509Certificate[] NO_CERTIFICATES = new X509Certificate[0]; + + @NonNls private static final String DEFAULT_PATH = FileUtil.join(PathManager.getSystemPath(), "tasks", "cacerts"); + @NonNls private static final String DEFAULT_PASSWORD = "changeit"; + + @NotNull + public static CertificatesManager createDefault() { + return createInstance(DEFAULT_PATH, DEFAULT_PASSWORD); + } + + + @NotNull + public static CertificatesManager createInstance(@NotNull String cacertsPath, @NotNull String cacertsPassword) { + return new CertificatesManager(cacertsPath, cacertsPassword); + } + + private final String myCacertsPath; + private final String myPassword; + + private CertificatesManager(@NotNull String cacertsPath, @NotNull String cacertsPassword) { + myCacertsPath = cacertsPath; + myPassword = cacertsPassword; + } + + /** + * Creates special kind of {@code SSLContext} which X509TrustManager first checks certificate presence in + * in default system-wide trust store (usually located at {@code ${JAVA_HOME}/lib/security/cacerts} or specified by + * {@code javax.net.ssl.trustStore} property) and when in the one specified by first argument of factory method + * {@link CertificatesManager#createInstance(String, String)}. + * If certificate wasn't found in either, manager will ask user whether it can be + * accepted (like web-browsers do) and if can, certificate will be added to specified trust store. + * </p> + * This method may be used for transition to HttpClient 4.x (see {@code HttpClients.custom().setSslContext(SSLContext)}) + * + * @return instance of SSLContext with described behavior + */ + @NotNull + public SSLContext createSslContext() throws Exception { + // SSLContext context = SSLContext.getDefault(); + SSLContext context = SSLContext.getInstance("TLS"); + TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + factory.init((KeyStore)null); + // assume that only X509 TrustManagers exist + X509TrustManager systemManager = findX509TrustManager(factory.getTrustManagers()); + + MutableX509TrustManager customManager = new MutableX509TrustManager(myCacertsPath, myPassword); + MyX509TrustManager trustManager = new MyX509TrustManager(systemManager, customManager); + // use default key store and secure random + context.init(null, new TrustManager[]{trustManager}, null); + return context; + } + + + private static class MyX509TrustManager implements X509TrustManager { + private final X509TrustManager mySystemManager; + private final MutableX509TrustManager myCustomManager; + + + private MyX509TrustManager(X509TrustManager system, MutableX509TrustManager custom) { + mySystemManager = system; + myCustomManager = custom; + } + + @Override + public void checkClientTrusted(X509Certificate[] certificates, String s) throws CertificateException { + // Not called by client + throw new UnsupportedOperationException(); + } + + @Override + public void checkServerTrusted(final X509Certificate[] certificates, String s) throws CertificateException { + try { + mySystemManager.checkServerTrusted(certificates, s); + } + catch (CertificateException e1) { + X509Certificate certificate = certificates[0]; + // looks like self-signed certificate + if (certificates.length == 1 && certificateIsSelfSigned(certificate)) { + // check-then-act sequence + synchronized (myCustomManager) { + try { + myCustomManager.checkServerTrusted(certificates, s); + } + catch (CertificateException e2) { + if (myCustomManager.isBroken() || !updateTrustStore(certificate)) { + throw e1; + } + } + } + } + } + } + + private boolean updateTrustStore(final X509Certificate certificate) { + Application app = ApplicationManager.getApplication(); + if (app.isUnitTestMode() || app.isHeadlessEnvironment()) { + myCustomManager.addCertificate(certificate); + return true; + } + + // can't use Application#invokeAndWait because of ReadAction + final CountDownLatch proceeded = new CountDownLatch(1); + final AtomicBoolean accepted = new AtomicBoolean(); + app.invokeLater(new Runnable() { + @Override + public void run() { + try { + UntrustedCertificateWarningDialog dialog = + new UntrustedCertificateWarningDialog(certificate, myCustomManager.myPath, myCustomManager.myPassword); + accepted.set(dialog.showAndGet()); + if (accepted.get()) { + LOG.debug("Certificate was accepted"); + myCustomManager.addCertificate(certificate); + } + } + finally { + proceeded.countDown(); + } + } + }, ModalityState.any()); + try { + proceeded.await(); + } + catch (InterruptedException e) { + LOG.error(e); + } + return accepted.get(); + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return mySystemManager.getAcceptedIssuers(); + } + } + + /** + * Trust manager that supports addition of new certificates (most likely self-signed) to corresponding physical + * key store. + */ + private static class MutableX509TrustManager implements X509TrustManager { + private final String myPath; + private final String myPassword; + private final TrustManagerFactory myFactory; + private final KeyStore myKeyStore; + private volatile X509TrustManager myTrustManager; + private volatile boolean broken = false; + + private MutableX509TrustManager(@NotNull String path, @NotNull String password) { + myPath = path; + myPassword = password; + myKeyStore = loadKeyStore(path, password); + myFactory = createFactory(); + myTrustManager = initFactoryAndGetManager(); + } + + private TrustManagerFactory createFactory() { + try { + return TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + } + catch (NoSuchAlgorithmException e) { + LOG.error(e); + broken = true; + } + return null; + } + + private KeyStore loadKeyStore(String path, String password) { + KeyStore keyStore = null; + try { + keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + File cacertsFile = new File(path); + if (cacertsFile.exists()) { + FileInputStream stream = null; + try { + stream = new FileInputStream(path); + keyStore.load(stream, password.toCharArray()); + } + finally { + StreamUtil.closeStream(stream); + } + } + else { + FileUtil.createParentDirs(cacertsFile); + keyStore.load(null, password.toCharArray()); + } + } + catch (Exception e) { + LOG.error(e); + broken = true; + } + return keyStore; + } + + public boolean addCertificate(X509Certificate certificate) { + if (broken) { + return false; + } + String alias = certificate.getIssuerX500Principal().getName(); + FileOutputStream stream = null; + try { + myKeyStore.setCertificateEntry(alias, certificate); + stream = new FileOutputStream(myPath); + myKeyStore.store(stream, myPassword.toCharArray()); + // trust manager should be updated each time its key store was modified + myTrustManager = initFactoryAndGetManager(); + return true; + } + catch (Exception e) { + LOG.error(e); + return false; + } + finally { + StreamUtil.closeStream(stream); + } + } + + @Override + public void checkClientTrusted(X509Certificate[] certificates, String s) throws CertificateException { + if (keyStoreIsEmpty() || broken) { + throw new CertificateException(); + } + myTrustManager.checkClientTrusted(certificates, s); + } + + @Override + public void checkServerTrusted(X509Certificate[] certificates, String s) throws CertificateException { + if (keyStoreIsEmpty() || broken) { + throw new CertificateException(); + } + myTrustManager.checkServerTrusted(certificates, s); + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + // trust no one if broken + if (keyStoreIsEmpty() || broken) { + return NO_CERTIFICATES; + } + return myTrustManager.getAcceptedIssuers(); + } + + private boolean keyStoreIsEmpty() { + try { + return myKeyStore.size() == 0; + } + catch (KeyStoreException e) { + LOG.error(e); + return true; + } + } + + private X509TrustManager initFactoryAndGetManager() { + if (!broken) { + try { + myFactory.init(myKeyStore); + return findX509TrustManager(myFactory.getTrustManagers()); + } + catch (KeyStoreException e) { + LOG.error(e); + broken = true; + } + } + return null; + } + + public boolean isBroken() { + return broken; + } + } + + private static X509TrustManager findX509TrustManager(TrustManager[] managers) { + for (TrustManager manager : managers) { + if (manager instanceof X509TrustManager) { + return (X509TrustManager)manager; + } + } + return null; + } + + private static boolean certificateIsSelfSigned(X509Certificate certificate) { + return certificate.getIssuerX500Principal().equals(certificate.getSubjectX500Principal()); + } +} diff --git a/platform/platform-api/src/com/intellij/util/net/UntrustedCertificateWarningDialog.form b/platform/platform-api/src/com/intellij/util/net/UntrustedCertificateWarningDialog.form new file mode 100644 index 000000000000..c47867b508fe --- /dev/null +++ b/platform/platform-api/src/com/intellij/util/net/UntrustedCertificateWarningDialog.form @@ -0,0 +1,94 @@ +<?xml version="1.0" encoding="UTF-8"?> +<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.util.net.UntrustedCertificateWarningDialog"> + <grid id="27dc6" binding="myRootPanel" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <margin top="0" left="10" bottom="0" right="10"/> + <constraints> + <xy x="20" y="20" width="500" height="224"/> + </constraints> + <properties> + <minimumSize width="-1" height="-1"/> + <opaque value="false"/> + <preferredSize width="400" height="550"/> + </properties> + <border type="none"/> + <children> + <grid id="d0af6" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <margin top="0" left="0" bottom="0" right="0"/> + <constraints> + <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + </constraints> + <properties/> + <border type="none"/> + <children> + <component id="61118" class="javax.swing.JTextPane"> + <constraints> + <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"> + <preferred-size width="400" height="50"/> + </grid> + </constraints> + <properties> + <contentType value="text/plain"/> + <opaque value="false"/> + <text value="Server's certificate is untrusted and appears to be self-signed"/> + </properties> + </component> + <component id="7dcbe" class="javax.swing.JLabel" binding="myWarningSign"> + <constraints> + <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + </constraints> + <properties> + <text value=""/> + </properties> + </component> + </children> + </grid> + <grid id="ccf25" binding="myCertificateInfoPanel" layout-manager="BorderLayout" hgap="0" vgap="0"> + <constraints> + <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="2" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + </constraints> + <properties/> + <border type="empty"> + <title-color color="-16777216"/> + <size top="0" left="0" bottom="0" right="0"/> + </border> + <children> + <component id="63708" class="com.intellij.ui.components.JBLabel"> + <constraints border-constraint="North"/> + <properties> + <font style="1"/> + <requestFocusEnabled value="true"/> + <text value="Certificate details"/> + </properties> + </component> + </children> + </grid> + <grid id="7551" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <margin top="0" left="0" bottom="0" right="0"/> + <constraints> + <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + </constraints> + <properties/> + <border type="none"/> + <children> + <component id="2a804" class="javax.swing.JTextPane" binding="myNoticePane"> + <constraints> + <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="2" fill="1" indent="0" use-parent-layout="false"> + <preferred-size width="50" height="50"/> + </grid> + </constraints> + <properties> + <contentType value="text/html"/> + <opaque value="false"/> + <text value="<html> <head> </head> <body> <p style="margin-top: 0"> </p> </body> </html> "/> + </properties> + </component> + </children> + </grid> + <vspacer id="d6d14"> + <constraints> + <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/> + </constraints> + </vspacer> + </children> + </grid> +</form> diff --git a/platform/platform-api/src/com/intellij/util/net/UntrustedCertificateWarningDialog.java b/platform/platform-api/src/com/intellij/util/net/UntrustedCertificateWarningDialog.java new file mode 100644 index 000000000000..b2a74ab44b9e --- /dev/null +++ b/platform/platform-api/src/com/intellij/util/net/UntrustedCertificateWarningDialog.java @@ -0,0 +1,121 @@ +package com.intellij.util.net; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.ui.IdeBorderFactory; +import com.intellij.ui.TitledSeparator; +import com.intellij.ui.components.JBLabel; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.FormBuilder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.security.auth.x500.X500Principal; +import javax.swing.*; +import java.awt.*; +import java.security.cert.X509Certificate; +import java.text.DateFormat; +import java.util.Map; + +import static com.intellij.openapi.util.Pair.create; + +/** + * @author Mikhail Golubev + */ +public class UntrustedCertificateWarningDialog extends DialogWrapper { + private static final Logger LOG = Logger.getInstance(UntrustedCertificateWarningDialog.class); + private static DateFormat DATE_FORMAT = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT); + + private static final Map<String, String> FIELD_ABBREVIATIONS = ContainerUtil.newHashMap( + create("CN", "Common Name"), + create("O", "Organization"), + create("OU", "Organizational Unit"), + create("L", "Location"), + create("C", "Country"), + create("ST", "State") + ); + + private JPanel myRootPanel; + private JLabel myWarningSign; + private JPanel myCertificateInfoPanel; + private JTextPane myNoticePane; + private final X509Certificate myCertificate; + private final String myPath, myPassword; + + public UntrustedCertificateWarningDialog(@NotNull X509Certificate certificate, @NotNull String storePath, @NotNull String password) { + super((Project)null, false); + + myCertificate = certificate; + myPath = FileUtil.toCanonicalPath(storePath); + + myPassword = password; + + FormBuilder builder = FormBuilder.createFormBuilder(); + + // I'm not using separate panels and form builders to preserve alignment of labels + builder = updateBuilderWithTitle(builder, "Issued To"); + builder = updateBuilderWithPrincipalData(builder, myCertificate.getSubjectX500Principal()); + builder = updateBuilderWithTitle(builder, "Issued By"); + builder = updateBuilderWithPrincipalData(builder, myCertificate.getIssuerX500Principal()); + builder = updateBuilderWithTitle(builder, "Validity Period"); + builder = builder + .setIndent(IdeBorderFactory.TITLED_BORDER_INDENT) + .addLabeledComponent("Valid from", new JBLabel(DATE_FORMAT.format(myCertificate.getNotBefore()))) + .addLabeledComponent("Valid until", new JBLabel(DATE_FORMAT.format(myCertificate.getNotAfter()))); + myCertificateInfoPanel.add(builder.getPanel(), BorderLayout.CENTER); + + setTitle("Untrusted Server's Certificate"); + setOKButtonText("Accept"); + setCancelButtonText("Reject"); + myWarningSign.setIcon(AllIcons.General.WarningDialog); + + Messages.installHyperlinkSupport(myNoticePane); +// myNoticePane.setFont(myNoticePane.getFont().deriveFont((float)FontSize.SMALL.getSize())); + myNoticePane.setText( + String.format("<html><p><small>" + + "Accepted certificate will be saved in truststore <code>%s</code> with password <code>%s</code>" + + "</small></p><html>", + myPath, myPassword)); + + init(); + LOG.debug("Preferred size: " + getPreferredSize()); + } + + @SuppressWarnings("MethodMayBeStatic") + private FormBuilder updateBuilderWithPrincipalData(FormBuilder builder, X500Principal principal) { + builder = builder.setIndent(IdeBorderFactory.TITLED_BORDER_INDENT); + for (String field : principal.getName().split(",")) { + field = field.trim(); + String[] parts = field.split("=", 2); + if (parts.length != 2) { + continue; + } + + String name = parts[0]; + String value = parts[1]; + + String longName = FIELD_ABBREVIATIONS.get(name.toUpperCase()); + if (longName == null) { + continue; + } + + builder = builder.addLabeledComponent(String.format("<html>%s (<b>%s</b>)</html>", longName, name), new JBLabel(value)); + } + return builder.setIndent(0); + } + + @SuppressWarnings("MethodMayBeStatic") + private FormBuilder updateBuilderWithTitle(FormBuilder builder, String title) { + return builder.addComponent(new TitledSeparator(title), IdeBorderFactory.TITLED_BORDER_TOP_INSET); + } + + @Nullable + @Override + protected JComponent createCenterPanel() { + return myRootPanel; + } +} diff --git a/platform/platform-impl/src/com/intellij/execution/impl/EditorHyperlinkSupport.java b/platform/platform-impl/src/com/intellij/execution/impl/EditorHyperlinkSupport.java index 03e47c519a79..dfb004f3c150 100644 --- a/platform/platform-impl/src/com/intellij/execution/impl/EditorHyperlinkSupport.java +++ b/platform/platform-impl/src/com/intellij/execution/impl/EditorHyperlinkSupport.java @@ -330,7 +330,8 @@ public class EditorHyperlinkSupport { break; } } - int newIndex = i > 0 ? i % ranges.size() : 0; + int initial = i > 0 ? i % ranges.size() : 0; + int newIndex = initial; while (newIndex < ranges.size() && newIndex >= 0) { newIndex = (newIndex + delta + ranges.size()) % ranges.size(); final RangeHighlighter next = ranges.get(newIndex); @@ -342,7 +343,7 @@ public class EditorHyperlinkSupport { } }, newIndex == -1 ? -1 : newIndex + 1, ranges.size()); } - if (newIndex == i) { + if (newIndex == initial) { break; // cycled through everything, found no next/prev hyperlink } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java index f9243cacec09..ddcfa870e4b5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -31,6 +31,7 @@ import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.editor.impl.*; import com.intellij.openapi.editor.impl.softwrap.*; import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import org.intellij.lang.annotations.JdkConstants; import org.jetbrains.annotations.NotNull; @@ -340,7 +341,8 @@ public class SoftWrapApplianceManager implements SoftWrapFoldingListener, Docume notifyListenersOnVisualLineStart(myContext.lineStartPosition); - if (!myContext.exceedsVisualEdge(newX)) { + if (!myContext.exceedsVisualEdge(newX) + || (myContext.currentPosition.offset == myContext.lineStartPosition.offset) && !Registry.is("editor.wrap.collapsed.region.at.line.start")) { myContext.advance(foldRegion, placeholderWidthInPixels); return true; } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/DefaultRemoteContentProvider.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/DefaultRemoteContentProvider.java index 16034e113809..092588caeb0a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/DefaultRemoteContentProvider.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/http/DefaultRemoteContentProvider.java @@ -27,8 +27,12 @@ import com.intellij.openapi.vfs.VfsBundle; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.PathUtil; import com.intellij.util.io.UrlConnectionUtil; +import com.intellij.util.net.CertificatesManager; import org.jetbrains.annotations.NotNull; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; @@ -66,6 +70,21 @@ public class DefaultRemoteContentProvider extends RemoteContentProvider { HttpURLConnection connection = (HttpURLConnection)new URL(url).openConnection(); connection.setConnectTimeout(CONNECT_TIMEOUT); connection.setReadTimeout(READ_TIMEOUT); + if (connection instanceof HttpsURLConnection) { + try { + HttpsURLConnection httpsConnection = (HttpsURLConnection)connection; + httpsConnection.setHostnameVerifier(new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }); + httpsConnection.setSSLSocketFactory(CertificatesManager.createDefault().createSslContext().getSocketFactory()); + } + catch (Exception e) { + LOG.warn(e); + } + } input = UrlConnectionUtil.getConnectionInputStreamWithException(connection, new EmptyProgressIndicator()); final int responseCode = connection.getResponseCode(); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameImpl.java index 96b5818f59f3..eaa1e63977c5 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameImpl.java @@ -480,7 +480,9 @@ public class IdeFrameImpl extends JFrame implements IdeFrameEx, DataProvider { } public void storeFullScreenStateIfNeeded() { - storeFullScreenStateIfNeeded(myFrameDecorator.isInFullScreen()); + if (myFrameDecorator != null) { + storeFullScreenStateIfNeeded(myFrameDecorator.isInFullScreen()); + } } public void storeFullScreenStateIfNeeded(boolean state) { diff --git a/platform/platform-impl/src/org/jetbrains/io/ChannelRegistrar.java b/platform/platform-impl/src/org/jetbrains/io/ChannelRegistrar.java index 96bb850d0899..5565e77a8cfb 100644 --- a/platform/platform-impl/src/org/jetbrains/io/ChannelRegistrar.java +++ b/platform/platform-impl/src/org/jetbrains/io/ChannelRegistrar.java @@ -6,6 +6,8 @@ import io.netty.channel.group.DefaultChannelGroup; import io.netty.util.concurrent.ImmediateEventExecutor; import org.jetbrains.annotations.NotNull; +import java.util.concurrent.TimeUnit; + @ChannelHandler.Sharable public final class ChannelRegistrar extends ChannelInboundHandlerAdapter { private final ChannelGroup openChannels = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE); @@ -43,7 +45,7 @@ public final class ChannelRegistrar extends ChannelInboundHandlerAdapter { } try { - openChannels.close().awaitUninterruptibly(); + openChannels.close().awaitUninterruptibly(30, TimeUnit.SECONDS); } finally { if (eventLoopGroup != null) { diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index caaef0b5491b..fdc8e12b4bce 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -355,4 +355,5 @@ show.all.look.and.feels=false show.all.look.and.feels.description=Make accessible all available Look and Feels cvs.roots.refresh.uses.vfs=true cvs.roots.refresh.uses.vfs.description=Should CVS roots refresh after update use VFS +editor.wrap.collapsed.region.at.line.start=false diff --git a/platform/platform-tests/testSrc/com/intellij/ide/bookmarks/BookmarkManagerTest.java b/platform/platform-tests/testSrc/com/intellij/ide/bookmarks/BookmarkManagerTest.java index 842ecfc5f160..6c0a9f10886b 100644 --- a/platform/platform-tests/testSrc/com/intellij/ide/bookmarks/BookmarkManagerTest.java +++ b/platform/platform-tests/testSrc/com/intellij/ide/bookmarks/BookmarkManagerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -18,7 +18,7 @@ package com.intellij.ide.bookmarks; import com.intellij.openapi.editor.CaretModel; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.LogicalPosition; -import com.intellij.openapi.editor.impl.AbstractEditorProcessingOnDocumentModificationTest; +import com.intellij.openapi.editor.impl.AbstractEditorTest; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.vfs.VfsUtil; @@ -34,7 +34,7 @@ import java.util.List; * @author Denis Zhdanov * @since 12/27/10 1:43 PM */ -public class BookmarkManagerTest extends AbstractEditorProcessingOnDocumentModificationTest { +public class BookmarkManagerTest extends AbstractEditorTest { private final List<Bookmark> myBookmarks = new ArrayList<Bookmark>(); @Override diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/AbstractEditorProcessingOnDocumentModificationTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/AbstractEditorTest.java index c49532ca9315..be8801949905 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/AbstractEditorProcessingOnDocumentModificationTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/AbstractEditorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -44,7 +44,7 @@ import java.util.regex.Pattern; * @author Denis Zhdanov * @since 11/18/10 7:43 PM */ -public abstract class AbstractEditorProcessingOnDocumentModificationTest extends LightPlatformCodeInsightTestCase { +public abstract class AbstractEditorTest extends LightPlatformCodeInsightTestCase { protected void init(@NotNull @NonNls String fileText, @NotNull TestFileType type) throws IOException { configureFromFileText(getFileName(type), fileText); } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapTest.java new file mode 100644 index 000000000000..770d05621ad6 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapTest.java @@ -0,0 +1,102 @@ +/* + * Copyright 2000-2013 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.openapi.editor.impl.softwrap; + +import com.intellij.openapi.editor.FoldRegion; +import com.intellij.openapi.editor.SoftWrap; +import com.intellij.openapi.editor.impl.AbstractEditorTest; +import com.intellij.testFramework.EditorTestUtil; +import com.intellij.testFramework.TestFileType; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SoftWrapTest extends AbstractEditorTest { + + public void testCollapsedRegionWithLongPlaceholderAtLineStart1() throws IOException { + doTestSoftWraps(10, "<fold text='veryVeryVeryLongPlaceholder'>foo</fold>"); + } + + public void testCollapsedRegionWithLongPlaceholderAtLineStart2() throws IOException { + doTestSoftWraps(10, "<fold text='veryVeryVeryLongPlaceholder'>foo</fold><wrap>bar"); + } + + public void testCollapsedRegionWithLongPlaceholderAtLineStart3() throws IOException { + doTestSoftWraps(10, "<fold text='veryVeryVeryLongPlaceholder'>foo</fold>\nvery long <wrap>text"); + } + + private static final String TAGS_PATTERN = "(<fold(\\stext=\'([^\']*)\')?>)|(</fold>)|<wrap>"; + + private void doTestSoftWraps(int wrapWidth, String text) throws IOException { + List<MyFoldRegion> foldRegions = new ArrayList<MyFoldRegion>(); + List<Integer> wrapPositions = new ArrayList<Integer>(); + int foldInsertPosition = 0; + int pos = 0; + int docPos = 0; + Matcher matcher = Pattern.compile(TAGS_PATTERN).matcher(text); + StringBuilder cleanedText = new StringBuilder(); + while(matcher.find()) { + cleanedText.append(text.substring(pos, matcher.start())); + docPos += matcher.start() - pos; + pos = matcher.end(); + if (matcher.group(1) != null) { // <fold> + foldRegions.add(foldInsertPosition++, new MyFoldRegion(docPos, matcher.group(3), matcher.group(2) != null)); + } + else if (matcher.group(4) != null) { // </fold> + assertTrue("Misplaced closing fold marker tag: " + text, foldInsertPosition > 0); + foldRegions.get(--foldInsertPosition).endPos = docPos; + } + else { // <wrap> + wrapPositions.add(docPos); + } + } + assertTrue("Missing closing fold marker tag: " + text, foldInsertPosition == 0); + cleanedText.append(text.substring(pos)); + + init(cleanedText.toString(), TestFileType.TEXT); + + for (MyFoldRegion region : foldRegions) { + FoldRegion r = addFoldRegion(region.startPos, region.endPos, region.placeholder); + if (region.collapse) { + toggleFoldRegionState(r, false); + } + } + + EditorTestUtil.configureSoftWraps(myEditor, wrapWidth); + + List<Integer> actualWrapPositions = new ArrayList<Integer>(); + for (SoftWrap wrap : myEditor.getSoftWrapModel().getSoftWrapsForRange(0, myEditor.getDocument().getTextLength())) { + actualWrapPositions.add(wrap.getStart()); + } + assertEquals("Wrong wrap positions", wrapPositions, actualWrapPositions); + } + + private static class MyFoldRegion { + private final int startPos; + private int endPos; + private final String placeholder; + private final boolean collapse; + + private MyFoldRegion(int pos, String placeholder, boolean collapse) { + this.startPos = pos; + this.placeholder = placeholder; + this.collapse = collapse; + } + } +} diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java index bb15dbc655f2..c5e4b9555b6e 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java @@ -17,13 +17,13 @@ package com.intellij.openapi.editor.impl.softwrap.mapping; import com.intellij.codeInsight.folding.CodeFoldingManager; import com.intellij.openapi.editor.*; -import com.intellij.openapi.editor.impl.AbstractEditorProcessingOnDocumentModificationTest; -import com.intellij.openapi.editor.impl.DefaultEditorTextRepresentationHelper; +import com.intellij.openapi.editor.impl.AbstractEditorTest; import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.editor.impl.SoftWrapModelImpl; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.util.Ref; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; +import com.intellij.testFramework.EditorTestUtil; import com.intellij.testFramework.TestFileType; import gnu.trove.TIntHashSet; import gnu.trove.TIntProcedure; @@ -38,7 +38,7 @@ import java.util.List; * @author Denis Zhdanov * @since 09/16/2010 */ -public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorProcessingOnDocumentModificationTest { +public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorTest { private boolean mySmartHome; @@ -1055,28 +1055,7 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorP private void init(final int visibleWidth, @NotNull String fileText, @NotNull TestFileType fileType, final int symbolWidth) throws IOException { init(fileText, fileType); - myEditor.getSettings().setUseSoftWraps(true); - SoftWrapModelImpl model = (SoftWrapModelImpl)myEditor.getSoftWrapModel(); - model.reinitSettings(); - - SoftWrapApplianceManager applianceManager = model.getApplianceManager(); - applianceManager.setWidthProvider(new SoftWrapApplianceManager.VisibleAreaWidthProvider() { - @Override - public int getVisibleAreaWidth() { - return visibleWidth; - } - }); - - if (symbolWidth > 0) { - applianceManager.setRepresentationHelper(new DefaultEditorTextRepresentationHelper(myEditor) { - @Override - public int charWidth(char c, int fontType) { - return symbolWidth; - } - }); - } - - applianceManager.registerSoftWrapIfNecessary(); + EditorTestUtil.configureSoftWraps(myEditor, visibleWidth, symbolWidth); } private static void checkSoftWraps(int... startOffsets) { diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java index 80998a056091..22ebe09a45b2 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java @@ -137,6 +137,7 @@ public class GeneralIdBasedToSMTRunnerEventsConvertor extends GeneralTestEventsP if (node != null) { if (node.getState() == State.REGISTERED && startedNodeEvent.isRunning()) { node.setState(State.RUNNING); + myRunningNodes.add(node); node.getProxy().setStarted(); if (suite) { fireOnSuiteStarted(node.getProxy()); @@ -172,13 +173,13 @@ public class GeneralIdBasedToSMTRunnerEventsConvertor extends GeneralTestEventsP State initialState = startedNodeEvent.isRunning() ? State.RUNNING : State.REGISTERED; node = new Node(startedNodeEvent.getId(), parentNode, childProxy, initialState); myNodeByIdMap.put(startedNodeEvent.getId(), node); - myRunningNodes.add(node); if (myLocator != null) { childProxy.setLocator(myLocator); } parentNode.getProxy().addChild(childProxy); if (node.getState() == State.RUNNING) { + myRunningNodes.add(node); // progress started childProxy.setStarted(); if (suite) { @@ -512,7 +513,7 @@ public class GeneralIdBasedToSMTRunnerEventsConvertor extends GeneralTestEventsP } } if (runningLeaves.isEmpty()) { - throw new RuntimeException("No running leaves found, running nodes: " + myRunningNodes); + return myTestsRootNode; } if (runningLeaves.size() == 1) { return runningLeaves.iterator().next(); diff --git a/platform/testFramework/src/com/intellij/testFramework/ActionTestCase.java b/platform/testFramework/src/com/intellij/testFramework/ActionTestCase.java new file mode 100644 index 000000000000..7bc16e7db44b --- /dev/null +++ b/platform/testFramework/src/com/intellij/testFramework/ActionTestCase.java @@ -0,0 +1,100 @@ +/* + * Copyright 2000-2013 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.testFramework; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.CaretModel; +import com.intellij.openapi.editor.VisualPosition; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.psi.PsiFile; +import com.intellij.testFramework.fixtures.CodeInsightTestFixture; +import com.intellij.testFramework.fixtures.IdeaProjectTestFixture; +import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory; +import com.intellij.testFramework.fixtures.TestFixtureBuilder; +import com.intellij.testFramework.fixtures.impl.LightTempDirTestFixtureImpl; +import org.jetbrains.annotations.NotNull; + +/** + * User: Andrey.Vokin + * Date: 11/26/13 + */ +public abstract class ActionTestCase extends UsefulTestCase { + public static final String CARET_TAG_REPLACE_REGEX = EditorTestUtil.CARET_TAG_PREFIX + "(\\+\\d+)?>"; + protected CodeInsightTestFixture myFixture; + + protected abstract FileType getFileType(); + + protected abstract String getTestDataPath(); + + @Override + protected void setUp() throws Exception { + super.setUp(); + final IdeaTestFixtureFactory factory = IdeaTestFixtureFactory.getFixtureFactory(); + final TestFixtureBuilder<IdeaProjectTestFixture> fixtureBuilder = factory.createLightFixtureBuilder(null); + final IdeaProjectTestFixture fixture = fixtureBuilder.getFixture(); + myFixture = IdeaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(fixture, new LightTempDirTestFixtureImpl(true)); + myFixture.setUp(); + myFixture.setTestDataPath(getTestDataPath()); + } + + + @Override + protected void tearDown() throws Exception { + myFixture.tearDown(); + myFixture = null; + super.tearDown(); + } + + protected void doAction(@NotNull final String before, @NotNull String expected, @NotNull final Runnable action) { + int[] caretAndSelectionPositionInSourceFile = EditorTestUtil.getCaretAndSelectionPosition(before); + int[] caretAndSelectionPositionInExpectedFile = EditorTestUtil.getCaretAndSelectionPosition(expected); + + final String sourceFinal = before.replaceAll(CARET_TAG_REPLACE_REGEX, "").replace(EditorTestUtil.SELECTION_START_TAG, "").replace(EditorTestUtil.SELECTION_END_TAG, ""); + final String expectedFinal = expected.replaceAll(CARET_TAG_REPLACE_REGEX, "").replace(EditorTestUtil.SELECTION_START_TAG, "").replace(EditorTestUtil.SELECTION_END_TAG, ""); + + final PsiFile file = myFixture.configureByText(getFileType(), sourceFinal); + myFixture.getEditor().getSettings().setVirtualSpace(true); + if (caretAndSelectionPositionInSourceFile[0] >= 0) { + CaretModel caretModel = myFixture.getEditor().getCaretModel(); + caretModel.moveToOffset(caretAndSelectionPositionInSourceFile[0]); + if (caretAndSelectionPositionInSourceFile[1] != 0) { + int line = caretModel.getVisualPosition().getLine(); + int column = caretModel.getVisualPosition().getColumn(); + caretModel.moveToVisualPosition(new VisualPosition(line, column + caretAndSelectionPositionInSourceFile[1])); + } + } + + if (caretAndSelectionPositionInSourceFile[2] >= 0) { + myFixture.getEditor().getSelectionModel() + .setSelection(caretAndSelectionPositionInSourceFile[2], caretAndSelectionPositionInSourceFile[3]); + } + + ApplicationManager.getApplication().runWriteAction(action); + + if (caretAndSelectionPositionInExpectedFile[0] >= 0) { + assertEquals(caretAndSelectionPositionInExpectedFile[0], myFixture.getCaretOffset()); + if (caretAndSelectionPositionInExpectedFile[1] != 0) { + assertEquals(caretAndSelectionPositionInExpectedFile[1], myFixture.getEditor().getCaretModel().getVisualPosition().getColumn()); + } + } + if (caretAndSelectionPositionInExpectedFile[2] >= 0) { + assertEquals(caretAndSelectionPositionInExpectedFile[2], myFixture.getEditor().getSelectionModel().getSelectionStart()); + assertEquals(caretAndSelectionPositionInExpectedFile[3], myFixture.getEditor().getSelectionModel().getSelectionEnd()); + } + + assertEquals(expectedFinal, myFixture.getDocument(file).getText()); + } +} diff --git a/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java index 5f7eb538fedb..2400ed5ee355 100644 --- a/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -23,6 +23,9 @@ import com.intellij.openapi.editor.actionSystem.EditorActionManager; import com.intellij.openapi.editor.actionSystem.TypedAction; import com.intellij.openapi.editor.highlighter.EditorHighlighter; import com.intellij.openapi.editor.highlighter.HighlighterIterator; +import com.intellij.openapi.editor.impl.DefaultEditorTextRepresentationHelper; +import com.intellij.openapi.editor.impl.SoftWrapModelImpl; +import com.intellij.openapi.editor.impl.softwrap.mapping.SoftWrapApplianceManager; import com.intellij.psi.tree.IElementType; import junit.framework.Assert; import org.jetbrains.annotations.NotNull; @@ -132,4 +135,42 @@ public class EditorTestUtil { return new int[]{caretPosInSourceFile, visualColumnOffset, selectionStartInSourceFile, selectionEndInSourceFile}; } + + /** + * Configures given editor to wrap at given character count. + * + * @return whether any actual wraps of editor contents were created as a result of turning on soft wraps + */ + public static boolean configureSoftWraps(Editor editor, final int charCountToWrapAt) { + int charWidthInPixels = 7; + // we're adding 1 to charCountToWrapAt, to account for wrap character width, and 1 to overall width to overcome wrapping logic subtleties + return configureSoftWraps(editor, (charCountToWrapAt + 1) * charWidthInPixels + 1, charWidthInPixels); + } + + /** + * Configures given editor to wrap at given width, assuming characters are of given width + * + * @return whether any actual wraps of editor contents were created as a result of turning on soft wraps + */ + public static boolean configureSoftWraps(Editor editor, final int visibleWidth, final int charWidthInPixels) { + editor.getSettings().setUseSoftWraps(true); + SoftWrapModelImpl model = (SoftWrapModelImpl)editor.getSoftWrapModel(); + model.reinitSettings(); + + SoftWrapApplianceManager applianceManager = model.getApplianceManager(); + applianceManager.setWidthProvider(new SoftWrapApplianceManager.VisibleAreaWidthProvider() { + @Override + public int getVisibleAreaWidth() { + return visibleWidth; + } + }); + applianceManager.setRepresentationHelper(new DefaultEditorTextRepresentationHelper(editor) { + @Override + public int charWidth(char c, int fontType) { + return charWidthInPixels; + } + }); + applianceManager.registerSoftWrapIfNecessary(); + return !model.getRegisteredSoftWraps().isEmpty(); + } } diff --git a/platform/testFramework/src/com/intellij/testFramework/ParsingTestCase.java b/platform/testFramework/src/com/intellij/testFramework/ParsingTestCase.java index 071dd4b3a22b..ed629b9ca353 100644 --- a/platform/testFramework/src/com/intellij/testFramework/ParsingTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/ParsingTestCase.java @@ -34,7 +34,6 @@ import com.intellij.openapi.options.SchemesManagerFactory; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.impl.ProgressManagerImpl; import com.intellij.openapi.startup.StartupManager; -import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; @@ -46,7 +45,6 @@ import com.intellij.psi.impl.PsiFileFactoryImpl; import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry; import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistryImpl; import com.intellij.psi.util.CachedValuesManager; -import com.intellij.rt.execution.junit.FileComparisonFailure; import com.intellij.util.CachedValuesManagerImpl; import com.intellij.util.Function; import com.intellij.util.messages.MessageBus; @@ -57,7 +55,6 @@ import org.picocontainer.*; import org.picocontainer.defaults.AbstractComponentAdapter; import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.util.Set; @@ -272,22 +269,8 @@ public abstract class ParsingTestCase extends PlatformLiteFixture { } public static void doCheckResult(String fullPath, String targetDataName, String text) throws IOException { - text = text.trim(); String expectedFileName = fullPath + File.separatorChar + targetDataName; - if (OVERWRITE_TESTDATA) { - VfsTestUtil.overwriteTestData(expectedFileName, text); - System.out.println("File " + expectedFileName + " created."); - } - try { - String expectedText = doLoadFile(fullPath, targetDataName); - if (!Comparing.equal(expectedText, text)) { - throw new FileComparisonFailure(targetDataName, expectedText, text, expectedFileName); - } - } - catch(FileNotFoundException e){ - VfsTestUtil.overwriteTestData(expectedFileName, text); - fail("No output text found. File " + expectedFileName + " created."); - } + UsefulTestCase.assertSameLinesWithFile(expectedFileName, text); } protected static String toParseTreeText(final PsiElement file, boolean skipSpaces, boolean printRanges) { diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index 193fab53e851..5c262a0f0517 100644 --- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java @@ -30,6 +30,7 @@ import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileSystemUtil; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileVisitor; @@ -57,6 +58,7 @@ import org.jetbrains.annotations.Nullable; import java.awt.*; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -687,10 +689,14 @@ public abstract class UsefulTestCase extends TestCase { String fileText; try { if (OVERWRITE_TESTDATA) { - FileUtil.writeToFile(new File(filePath), actualText); + VfsTestUtil.overwriteTestData(filePath, actualText); System.out.println("File " + filePath + " created."); } - fileText = FileUtil.loadFile(new File(filePath)); + fileText = FileUtil.loadFile(new File(filePath), CharsetToolkit.UTF8); + } + catch (FileNotFoundException e) { + VfsTestUtil.overwriteTestData(filePath, actualText); + throw new AssertionFailedError("No output text found. File " + filePath + " created."); } catch (IOException e) { throw new RuntimeException(e); diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/mutable/GraphBuilder.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/mutable/GraphBuilder.java index 23c60fb3651d..e7c2e827cc06 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/mutable/GraphBuilder.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/mutable/GraphBuilder.java @@ -194,9 +194,6 @@ public class GraphBuilder { // local package @NotNull public MutableGraph runBuild(@NotNull List<? extends GraphCommit> commitParentses) { - if (commitParentses.size() == 0) { - throw new IllegalArgumentException("Empty list commitParentses"); - } for (GraphCommit vcsCommit : commitParentses) { append(vcsCommit); } diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graphmodel/impl/GraphModelImpl.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graphmodel/impl/GraphModelImpl.java index a6fd7c1a93ea..4f052f5209fc 100644 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graphmodel/impl/GraphModelImpl.java +++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graphmodel/impl/GraphModelImpl.java @@ -1,5 +1,6 @@ package com.intellij.vcs.log.graphmodel.impl; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.util.Consumer; import com.intellij.util.Function; import com.intellij.vcs.log.GraphCommit; @@ -30,6 +31,8 @@ public class GraphModelImpl implements GraphModel { private final List<Consumer<UpdateRequest>> listeners = new ArrayList<Consumer<UpdateRequest>>(); private final GraphBranchShowFixer branchShowFixer; + private static final Logger LOG = Logger.getInstance(GraphModelImpl.class); + private Function<Node, Boolean> isStartedBranchVisibilityNode = new Function<Node, Boolean>() { @NotNull @Override @@ -81,8 +84,15 @@ public class GraphModelImpl implements GraphModel { graph.updateVisibleRows(); int newSize = graph.getNodeRows().size(); - int newTo = newSize == 0 ? 0 : newSize - 1; - int oldTo = oldSize == 0 ? 0 : oldSize - 1; + if (newSize == 0) { // empty log. Possible only right after git init + return; + } + if (oldSize == 0) { // this shouldn't happen unless the log is empty + LOG.error("Old size can't be 0 if newSize is not 0. newSize: " + newSize); + return; + } + int newTo = newSize - 1; + int oldTo = oldSize - 1; UpdateRequest updateRequest = UpdateRequest.buildFromToInterval(0, oldTo, 0, newTo); callUpdateListener(updateRequest); } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java index 266cb14e271a..1b75ba5f7102 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java @@ -776,7 +776,7 @@ public class VcsLogDataHolder implements Disposable { } public boolean isFullLogReady() { - return myFullLog; + return myFullLog && getTopCommitsCount() > 0; } @NotNull diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java index 940add3775ad..11f7540afd3e 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java @@ -15,8 +15,12 @@ */ package com.intellij.vcs.log.data; +import com.intellij.openapi.Disposable; import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.ThrowableComputable; +import com.intellij.util.io.IOUtil; import com.intellij.util.io.KeyDescriptor; import com.intellij.util.io.Page; import com.intellij.util.io.PersistentEnumerator; @@ -33,15 +37,21 @@ import java.io.IOException; /** * Supports the int <-> Hash persistent mapping. */ -class VcsLogHashMap { +class VcsLogHashMap implements Disposable { private static final File LOG_CACHE_APP_DIR = new File(PathManager.getSystemPath(), "vcs-log"); + private static final Logger LOG = Logger.getInstance(VcsLogHashMap.class); private final PersistentEnumerator<Hash> myPersistentEnumerator; VcsLogHashMap(@NotNull Project project) throws IOException { - File myMapFile = new File(LOG_CACHE_APP_DIR, project.getName() + "." + project.getLocationHash()); - myPersistentEnumerator = new PersistentEnumerator<Hash>(myMapFile, new MyHashKeyDescriptor(), Page.PAGE_SIZE); + final File myMapFile = new File(LOG_CACHE_APP_DIR, project.getName() + "." + project.getLocationHash()); + myPersistentEnumerator = IOUtil.openCleanOrResetBroken(new ThrowableComputable<PersistentEnumerator<Hash>, IOException>() { + @Override + public PersistentEnumerator<Hash> compute() throws IOException { + return new PersistentEnumerator<Hash>(myMapFile, new MyHashKeyDescriptor(), Page.PAGE_SIZE); + } + }, myMapFile); } @Nullable @@ -53,6 +63,16 @@ class VcsLogHashMap { return myPersistentEnumerator.enumerate(hash); } + @Override + public void dispose() { + try { + myPersistentEnumerator.close(); + } + catch (IOException e) { + LOG.warn(e); + } + } + private static class MyHashKeyDescriptor implements KeyDescriptor<Hash> { @Override public void save(DataOutput out, Hash value) throws IOException { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUI.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUI.java index c15af9fd5afc..fae4fa71d63b 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUI.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUI.java @@ -3,6 +3,7 @@ package com.intellij.vcs.log.ui; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.Hash; import com.intellij.vcs.log.VcsLog; @@ -21,12 +22,14 @@ import com.intellij.vcs.log.impl.VcsLogImpl; import com.intellij.vcs.log.printmodel.SelectController; import com.intellij.vcs.log.ui.frame.MainFrame; import com.intellij.vcs.log.ui.frame.VcsLogGraphTable; +import com.intellij.vcs.log.ui.tables.AbstractVcsLogTableModel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.table.TableModel; import java.awt.*; import java.util.Collection; +import java.util.Set; /** * @author erokhins @@ -82,8 +85,49 @@ public class VcsLogUI { }); } - public void setModel(@NotNull TableModel model) { - myMainFrame.getGraphTable().setModel(model); + public void setModel(@NotNull AbstractVcsLogTableModel model) { + VcsLogGraphTable table = getTable(); + int[] selectedRows = table.getSelectedRows(); + TableModel previousModel = table.getModel(); + + table.setModel(model); + + if (previousModel instanceof AbstractVcsLogTableModel) { // initially it is an empty DefaultTableModel + restoreSelection(table, (AbstractVcsLogTableModel)previousModel, selectedRows, model); + } + } + + private static void restoreSelection(@NotNull VcsLogGraphTable table, @NotNull AbstractVcsLogTableModel previousModel, + int[] previousSelectedRows, @NotNull AbstractVcsLogTableModel newModel) { + Set<Hash> selectedHashes = getHashesAtRows(previousModel, previousSelectedRows); + Set<Integer> rowsToSelect = findNewRowsToSelect(newModel, selectedHashes); + for (Integer row : rowsToSelect) { + table.addRowSelectionInterval(row, row); + } + } + + @NotNull + private static Set<Hash> getHashesAtRows(@NotNull AbstractVcsLogTableModel model, int[] rows) { + Set<Hash> hashes = ContainerUtil.newHashSet(); + for (int row : rows) { + Hash hash = model.getHashAtRow(row); + if (hash != null) { + hashes.add(hash); + } + } + return hashes; + } + + @NotNull + private static Set<Integer> findNewRowsToSelect(@NotNull AbstractVcsLogTableModel model, @NotNull Set<Hash> selectedHashes) { + Set<Integer> rowsToSelect = ContainerUtil.newHashSet(); + for (int row = 0; row < model.getRowCount() && rowsToSelect.size() < selectedHashes.size(); row++) {//stop iterating if found all hashes + Hash hash = model.getHashAtRow(row); + if (hash != null && selectedHashes.contains(hash)) { + rowsToSelect.add(row); + } + } + return rowsToSelect; } public void updateUI() { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java index 44f58ddc67ae..f4401af18e4d 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/BranchesPanel.java @@ -61,6 +61,10 @@ public class BranchesPanel extends JPanel { addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { + if (!myUI.getMainFrame().areGraphActionsEnabled()) { + return; + } + final RefGroup group = findRef(e); if (group == null) { return; diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java index 248bfd932c5c..ef79df6275bd 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java @@ -188,8 +188,12 @@ class DetailsPanel extends JPanel implements ListSelectionListener { private final JTextField myBranchesList; ContainingBranchesPanel() { - JLabel label = new JBLabel("Contained in branches: "); - label.setFont(label.getFont().deriveFont(Font.ITALIC)); + JLabel label = new JBLabel("Contained in branches: ") { + @Override + public Font getFont() { + return UIUtil.getLabelFont().deriveFont(Font.ITALIC); + } + }; myLoadingIcon = new AsyncProcessIcon("Loading..."); myBranchesList = new JBTextField(""); myBranchesList.setEditable(false); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java index 8c6fd2f2486a..b41f98fb24f6 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java @@ -24,6 +24,7 @@ import com.intellij.vcs.log.data.VcsLogUiProperties; import com.intellij.vcs.log.ui.VcsLogUI; import com.intellij.vcs.log.ui.filter.VcsLogClassicFilterUi; import com.intellij.vcs.log.ui.filter.VcsLogFilterUi; +import com.intellij.vcs.log.ui.tables.GraphTableModel; import icons.VcsLogIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -151,14 +152,14 @@ public class MainFrame extends JPanel implements TypeSafeDataProvider { } private JComponent createActionsToolbar() { - AnAction hideBranchesAction = new DumbAwareAction("Collapse linear branches", "Collapse linear branches", VcsLogIcons.CollapseBranches) { + AnAction hideBranchesAction = new GraphAction("Collapse linear branches", "Collapse linear branches", VcsLogIcons.CollapseBranches) { @Override public void actionPerformed(AnActionEvent e) { myUI.hideAll(); } }; - AnAction showBranchesAction = new DumbAwareAction("Expand all branches", "Expand all branches", VcsLogIcons.ExpandBranches) { + AnAction showBranchesAction = new GraphAction("Expand all branches", "Expand all branches", VcsLogIcons.ExpandBranches) { @Override public void actionPerformed(AnActionEvent e) { myUI.showAll(); @@ -227,6 +228,10 @@ public class MainFrame extends JPanel implements TypeSafeDataProvider { return myToolbar; } + public boolean areGraphActionsEnabled() { + return myGraphTable.getModel() instanceof GraphTableModel && myGraphTable.getRowCount() > 0; + } + private class CommitSelectionListener implements ListSelectionListener { private final ChangesBrowser myChangesBrowser; @@ -290,5 +295,23 @@ public class MainFrame extends JPanel implements TypeSafeDataProvider { public void setSelected(AnActionEvent e, boolean state) { myUI.setLongEdgeVisibility(state); } + + @Override + public void update(AnActionEvent e) { + super.update(e); + e.getPresentation().setEnabled(areGraphActionsEnabled()); + } + } + + private abstract class GraphAction extends DumbAwareAction { + + public GraphAction(String text, String description, Icon icon) { + super(text, description, icon); + } + + @Override + public void update(AnActionEvent e) { + e.getPresentation().setEnabled(areGraphActionsEnabled()); + } } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java index 0752ce3ebdbc..5b253d7d49e0 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java @@ -51,16 +51,16 @@ public class GraphCommitCellRender extends AbstractPaddingCellRender { @Override protected int getLeftPadding(JTable table, @Nullable Object value) { GraphCommitCell cell = (GraphCommitCell)value; - if (cell == null) { return 0; } + return calcPaddingBeforeText(cell, (Graphics2D)table.getGraphics()); + } - int refPadding = calcRefsPadding(cell.getRefsToThisCommit(), (Graphics2D)table.getGraphics()); - + private int calcPaddingBeforeText(GraphCommitCell cell, Graphics2D g) { + int refPadding = calcRefsPadding(cell.getRefsToThisCommit(), g); int countCells = cell.getPrintCell().countCell(); int graphPadding = countCells * WIDTH_NODE; - return refPadding + graphPadding; } @@ -82,9 +82,9 @@ public class GraphCommitCellRender extends AbstractPaddingCellRender { return; } - BufferedImage image = UIUtil.createImage(1000, HEIGHT_CELL, BufferedImage.TYPE_INT_ARGB); + int width = calcPaddingBeforeText(cell, (Graphics2D)g); + BufferedImage image = UIUtil.createImage(width, HEIGHT_CELL, BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = image.createGraphics(); - g2.setBackground(new Color(0, 0, 0, 0)); graphPainter.draw(g2, cell.getPrintCell()); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java index 1e26910d938e..25c0397b9979 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java @@ -14,9 +14,9 @@ import javax.swing.table.AbstractTableModel; import java.util.List; /** - * @param <T> commit column class + * @param <CommitColumnClass> commit column class */ -public abstract class AbstractVcsLogTableModel<T> extends AbstractTableModel { +public abstract class AbstractVcsLogTableModel<CommitColumnClass> extends AbstractTableModel { public static final VirtualFile FAKE_ROOT = NullVirtualFile.INSTANCE; @@ -80,10 +80,10 @@ public abstract class AbstractVcsLogTableModel<T> extends AbstractTableModel { protected abstract VirtualFile getRoot(int rowIndex); @NotNull - protected abstract T getCommitColumnCell(int index, @Nullable VcsShortCommitDetails details); + protected abstract CommitColumnClass getCommitColumnCell(int index, @Nullable VcsShortCommitDetails details); @NotNull - protected abstract Class<T> getCommitColumnClass(); + protected abstract Class<CommitColumnClass> getCommitColumnClass(); /** * Returns the Hash of the commit displayed in the given row. |