summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2013-10-15 19:49:27 -0700
committerTor Norbye <tnorbye@google.com>2013-10-15 19:49:46 -0700
commit767536605379e492929a763f4a585cb4f499b9f6 (patch)
treeb82400bd5a1609a29dfb9d40d4b54cfac2daaabd /platform
parent32218cc024d27dc92563b5b45007c94057c1c423 (diff)
downloadidea-767536605379e492929a763f4a585cb4f499b9f6.tar.gz
Snapshot 246ebf4786ef75849985fa5fba6015155ebac527 from idea/132.637 of git://git.jetbrains.org/idea/community.git
246ebf4: better gradient colors for Darcula 8833be9: should be opaque 9a1a2f2: fix darcula text fields 001ed5d: add "perflib" from tools-base module to build c348af4: Github: do not provide Git AuthData for wrong host 7424aca: Github: compare hosts case-insensitive 7ce90f4: fix double Shift on Windows 050b38c: check value of Required annotation; do not check required attributes of dom elements in XmlHighlightingVisitor; revive testing of required attribute validation in PluginXmlFunctionalTest 59d7274: IDEA-114873 (Add Package Info item to New submenu) c4d7c3e: codestyle fix 9f3e60a: trace about substitutor once per derived class, in order to avoid excessive logging 27952b2: moved FinderRecursivePanel to platform-impl 94b9f06: IDEA-114850 Unreadable "No files are open" text 1fd5b2d: removing nested frameworks 4098566: capitalization (IDEA-81968) 10f8420: diagnose incorrect MixinEP registration (IDEA-113506) 35689ca: add apiVersion parameter to build.xml so that Android Studio can use exact platform build they're compatible with (IDEA-114596) cb53ae1: Multiline support for regexp editor ddef70e: Lens mode (hint location fixes) f8d6bf8: disable escaper for balloons 99d486d: check for language 26fa119: support for java regexp modifiers 925000e: Ability to handle regexps with modifiers 67f1c14: automake is run only for the project where current user activity is going on (IDEA-104064) d5cad13: fix naturalCompare() edge case c1f7724: Merge remote-tracking branch 'origin/master' 862fb67: proper bounds for search everywhere button d21dc3f: new shortcut for search everywhere 4283182: completely new UI 50e5c52: colors for white theme 08f4c9e: don't paint parent's background 0ed4058: active icon for Search Everywhere 17a6674: don't reset row height 52f84a7: IDEA-114694 Shift-Space is a terrible default shortcut for Search Everywhere 099ead0: dfa: exception handling reworked no more gosub-return causing equal states differing by offset stack only don't visit outer finally without visiting inner one 3744d2c: IDEA-114736 Bug in code completion inside instanceof block 377acad: correctly initialize semaphore for all BasicFuture implementations 81bfb1e: Lens mode (mouse wheel support & many fixes) 81d90a7: Get rid of extra UISettings notifications 2fb0092: Github: fix UrlToHost function 75f4e1f3: plugin advertisement: show disabled plugin name 8ed1b68: plugins advertisement: enabled installed plugin 53ad76d: IDEA-114708 Wrong Up/Down action interpretation in consoles (irb/Bash) e818b6e: use fileEditor's editor instead of some random editor from dataContext bd152a4: IDEA-89857 automatically adds required attributes in dom-based xml; insert correct endings for View/ViewGroup tags 7988d09: test for not building stubs for java files in module but not under source roots, in library but not in class root 131353b: IDEA-112134 $SELECTION$ variable doesn't work as true variable, but as $END$ cac9208f: item 1 of IDEA-95649 (Darcula: Settings -> File Templates doesn't follow theme colors) ab2d2ca: remove color to display file template descriptions nicely under Darcula 7fb7911: use correct company name in version info (IDEA-82623) 5bd4249: WEB-8027 long single line values in debugger hang IntelliJ + review 4710a08: show editor notification for text mapped files about known plugins from the repository 62c87af: logging for incorrect move eab3d4c: plugin advertising: stop if update was disabled 25584ad: Add MONTH_NAME_SHORT and MONTH_NAME_FULL definition & improve file template descriptions 4f10bd1: CR-IC-2706 (logging added) eef188b: Add diagnostic info of invalid template ranges fd7c9d0: EA-50616 618a573: license added? d29c66e: Drivers management refactored f280f8b: update netty (attempt to understand why nodejs disconnected on second run, but it was not netty fault) 15d9033: selecting right project type 4111497: http://ea.jetbrains.com/browser/ea_problems/50978 65eff28: EA-50605 - NPE: AbstractExternalSystemTaskConfigurationType.generateName f43865d: Slightly reworked formatter markers' UI in accordance with IDEA-114583 8e51528: give file template description a bit more room 9d2f4f9: CR-IC-2705, fixed for Mac 55b6603: fix default file template descriptions 6fd90c1: Revert optimization, because MAC tests fail. d11966f: IDEA-114766 Gradle: module dependency scope ignored while project info resolving 359ddf8: IDEA-114647 (fsnotifier size check updated) 0f10404: license added 780fa6e: allow watching exFAT (IDEA-114647) f8dc1eb: lib license added efb3281: testdata for IDEA-67591 993fb34: highlighting for incompatible return types in type parameter inheritors (IDEA-57274) e03245e: Cleanup (comment) 51a77de: platform: garbage production by FIleWatcher reduced 06b198e: Cleanup (typo; dead code) d8729d5: platform: partial refresh fixed af0637c: Merge remote-tracking branch 'origin/master' 121ee3e: Add helper method for pretty-printing JSON in TaskUtil class. Improve logging in GenericRepository. 461c6d7: testng: parameterized template (IDEA-114746) 5a50ed8: do not detach copyright updater on project closed (IDEA-114186) f06771b: restart infer nullity when library already exist (IDEA-114163) b33fa7f: effectively final: check flow at variable start (IDEA-114737) 46e9f4b: testdata for IDEA-57252 82b6b16: testdata for IDEA-67518 6a9313c: type parameter in bounds check: separate wildcards with type param in bound efc19ab: new inference: do not ignore meaningful upper bounds cbff339: Optimization: don't use FileUtil.pathsEqual() , paths returned by FileWatcher is already canonical. 2723de7: don't fold already concise getters (EA-50804) 17dae78: IDEA-114699 Live template without description shows "NULL" 56e5602: a simpler way to setup live templates in tests 3ea2e38: Jediterm updated. a47f9d3: Change cache lookup logic in XML and JSON response handlers 4ce5dec: Don't urlencode "serverUrl" template variable in GenericRepository fields 38c05d9: IDEA-114076 Unit tests can't be executed with a JRE 1.5 because junit-rt.jar is compiled with JRE 6.0 as target bb8bb2a: moved to analysis 376fe99: moved to analysis ff48d6d: moved to analysis 3fcf2d5: moved to analysis 1825351: moved to analysis 563ffda: moved to analysis dc477a1: moved to analysis 3c18086: moved to analysis 472bab7: moved to analysis 473e45d: moved to analysis 65f35d7: moved to analysis a36aaf6: moved to analysis 5f10c64: moved to analysis c3bf35d: moved to analysis b6fbbb6: moved to analysis 6a9d91b: moved to analysis 7582706: moved to analysis ef37a6c: moved to analysis 1ea667f: moved to analysis 8985a7e: moved to analysis 37691e0: moved to analysis 08ba033: moved to analysis f069df4: moved to analysis 3ac7210: moved to analysis 5e9a1e1: moved to analysis 74ecd51: moved to analysis 33f20b1: moved to analysis 936f232: read action da37289: moved to analysis e0e3724: moved to analysis 53e0050: moved to analysis 5240818: moved to analysis 50f7722: moved to analysis 8b64b6d: moved to analysis 62c27c4: moved to analysis 0dba483: moved to analysis c7bfbeb: moved to analysis 6bf16de: moved to analysis 180ea57: moved to analysis b8fcd01: moved to analysis b19c765: moved to analysis 636378c: moved to analysis 7c63c331: moved to analysis b47e90d: moved to analysis 44e0bd5: moved to analysis 4957a2c: moved to analysis bad582a: moved to analysis 2a4c6df: moved to analysis bf5ae61: moved to analysis f547ee5: moved to analysis c6d5ca6: moved to analysis c3dc3f2: moved to analysis 27f40d2: moved to analysis 82cc0c1: moved to analysis e309872: moved to analysis c6806d7: moved to analysis 66b131c: test fix 5819121: moved to analysis ace2035: moved to analysis 300fed6: moved to analysis 73d5646: moved to analysis 1efaa3b: moved to analysis 930eabe: moved to analysis 34c381d: moved to analysis 8094570: moved to analysis bb3273c: moved to analysis aec65a6: moved to analysis cbc892a: moved to analysis b42dc77: moved to analysis ba6923d: moved to analysis 2283aa0: moved to analysis 1aeb0d3: moved to analysis e08c9f1: moved to analysis 03cd373: moved to analysis caaf810: moved to analysis 0e924cf: moved to analysis f3e0d0a: moved to analysis 51ec5ea: moved to analysis 94fb66f: moved to analysis 6aaaaae: moved to analysis 08e51ae: moved to analysis cf12745: moved to analysis b34f44f: moved to analysis 37f3cdc: moved to analysis 036a2b6: moved to analysis 4931ffa: moved to analysis 8e59ca1: moved to analysis 02c0c01: moved to analysis 89a55b0: moved to analysis cba23f4: moved to analysis 1b1fb1c: moved to analysis bd725cd: moved to analysis dfcc51d: moved to analysis fad8af3: moved to analysis 827e5a5: moved to analysis 2360dcd: moved to analysis 008c56a: moved to analysis 758ba60: moved to analysis 731c642: moved to analysis d5adf28: moved to analysis b892f8b: moved to analysis 7513254: moved to analysis e3a752c: moved to analysis 03219ce: moved to analysis f06ad8a: moved to analysis 2c4614a: moved to analysis 4e076dd: moved to analysis 7f3ee23: moved to analysis 50835cc: moved to analysis ff01a67: moved to analysis 084113a: moved to analysis e197319: moved to analysis 1d7f251: moved to analysis e2fc894: moved to analysis d48b36b: EA-50870 - IAE: GroovyPropertyUtils.getGetterNameNonBoolean 0fb3c6e: IDEA-57747 (Idea X - CTRL+SHIFT+Left/Right Arrow functionality) 2cbff34: Github: use standard YesNoDialog 53782b5: Github: use strict class check a42b1d9: when launching build process or javac server suppress libraries from 'ext' directories to ensure compiler is loaded from correct location f40dfd1: OC-8512 Exception when typing on empty line at non-zero column during indexing 917a3a1: cleanup c821ba0: moved to analysis 56da4ee: moved to core 38dbce1: cleanup d8bd506: ForkJoin support 9f4a9d0: moved to analysis da9996b: moved to analysis f44d265: fix due to CR-IC-2640 comment 75b7026: Merge remote-tracking branch 'origin/master' 48e70d3: used lower level char buffer instead of document.getText() due to CR-IC-2640 comment 1271549: project structure: increased default size of source roots tree a24ebae: Merge remote-tracking branch 'origin/master' a9fc3c6: cleanup adb2f16: diagnostics for EA-50397 - assert: TextRange.<init> 2244946: EA-50612 - NPE: EditorWindow$.run a64cbc3: Logger renamed to more specific name 2cbf40b: EA-50756 - NPE: DefaultXmlExtension.getAvailableTagNames diagnostics c25431e: new inference: skip inference for nested call when nested call was initially requested to be inferred 5fda195: detailed diagnostic for compiler class loading problems c178ebf: workaround for EA-49915, EA-50599 5e7f578: go to the errors first by default 42ad23d: when matching local variables slots and variable names from sources take into account loop and catch statements 69424d4: run test method from abstract class: ignore non-runnable inheritors; try to retrieve from context implicitly selected inheritor (IDEA-114551) 8e51c80: override: fix param names in javadoc (IDEA-114557) 977e332: PY-11027 (ignore placeholder argument from non-compliant DEs) c3af1f1: Merge remote-tracking branch 'origin/master' fa5fa39: Test skipped for Win XP bad439d: execution tests probably fixed 1e54387: range changed (IDEA-114528) 93c8631: infer nullity: more pessimistic check: check variables first (IDEA-114630) 6fb01cd: global inspections documentation cleanup 087b52a: WEB-445 "Select word at caret" a bit to grabby in class attributes 046efd8: highlight missing package-info.java in editor too b525330: Errors beef6c6: GroovyDirectInheritorsSearcher: avoid unnecessary collection->array copying 0596f3d: remove @NotNull from SortedMap#comparator (IDEA-114655) eb9828f: IDEA-114203: Add new "Options" tab in YouTrack repository editor where user can customize states names 4371063: Delete repository problem notification b8d1054: CR-IC-2693 3f3b474: CR-IC-2690 0ce5ae9: displaying version number in tree 2271eaf: IDEA-114633 (symlink deletion regression fixed) 569a70d: Cleanup (FileUtil tests grouped) 9fdcf65: Cleanup (formatting) ca49f7d: Cleanup (unnecessary condition) 46d04cb: FrameworkLibraryVersion separated from FrameworkVersion a8fc158: recognize IBM JDK from WebSphere 8 (IDEA-90661) 65f1157: Merge branch 'svn1_8_new' f165eb7: named NodeRendererImpl constructor; adjust test expectations 117f86f: corrected e173999: FrameworkGroupVersion dropped 9948d9d: Merge remote-tracking branch 'origin/master' 76f6788: fix exception on some linux machines f6f6664: IDEA-114517 Use server url (and not repository url) as authentication realm for https server certificate 5e77c10: IDEA-114517 Force certificate errors checking before credentials error checking 13c6c0a: Merge remote-tracking branch 'origin/master' 784bfa5: Merge remote-tracking branch 'origin/master' 9f25ff8: jdk8 compilation 80265c1: plugin advertiser: escape # in feature implementation efc8a3d: EA-50528 - MJE: JsonReader.syntaxError 2e10f33: IDEA-99241 (Report package naming convention violations in the editor) 1cc2fa4: made fields final 4374c69: replace exception-driven control flow with the proper one f0cba21: moved to analysis d9b6c0f: moved to psi f8c15cf: moved to psi 836e381: cleanup 2e0029d: moved to analysis 6484602: make TempFileSystem extends LocalFileSystem to simplify clients and tests 662eb80: cleanup 0ebcf72: moved to analysis 250fff4: moved to analysis 3906227: moved to analysis a24ae6d: moved to analysis e8fc8c6: moved to psi 7a468ca: moved method to core 82060fd: cleanup 04c524c: reduce dependency on LocalFileSystem 8cdab66: frameworks tree refactored 9b45d86: WEB-9563 There is a bug with Emmet and BEM namings 29ecf27: guess DTD by public id #WEB-9546 fixed c697898: JavaEE frameworks sorted out 6dc8386: less side effects 99e0eae: test is back e2d2093: Gradle: gradle-native deps added 7507dc5: do not autoscroll when in focus, e.g. selection changing action may be triggered directly from structure 346c501: add model change support & some formatting d6ff1a1: Merge remote-tracking branch 'origin/master' b6a044a: Respect auto-save and auto-sync settings. e1f4afb: IDEA-60234 Automatically unwrap groovy.lang.Reference in the debugger 0dcb367: make topic final c5ce0b8: IDEA-114604 Evaluate Expression doesn't change context after navigating call stack +review f9411d3: cleanup 89d03b1: overrides 147d5ea: cleanup aef6c9e: extracted method to avoid code duplication 4cffaf3: on rebuild clear system caches for compilers run internally in IDEA f72bc3d: add darcula green color 31d24b4: better colors for darcula 4ef7b0c: glow color for IntelliJ laf 36aad83: refactor button and checkbox 9181562: search field style for IntelliJ LaF cff6f4b: use triangles in IntelliJ LaF trees c4ebcef: add IntelliJ LaF dee1ff7: IntelliJ laf a152352: customize Darcula LaF from IntelliJ LaF 6e97b12: tree icons for IntelliJ LaF 69dbc89: inference: do not check return type during inference; separate highlighting check 9e060c7: cast 51f471a: Format pom.xml on create new module. 2624ec6: IDEA-114593 Debugger: Show variable information when no debug info 1918d6e: overrides, nullability c463545: platform: race between JNA and environment loading fixed 943cea6: Accidentally forget to add annotator to plugin.xml 0dc87d5: IDEA-50801 Evaluate expression: expand root node automatically +review 79c7ba5: overrides 5e841a7: fix testdata 7c84b97: Update JqlAnnotator to highlight JqlIdentifiers as constants, not as strings, to be consistent with YouTrack queries colors e0ac1f1: Merge remote-tracking branch 'origin/master' dfc9912: fixed PY-10964 Extract variable doesn't work as expected inside brackets fixed PY-10221 Refactor->Extract->Variable may break square bracket symmetry and may break user input 9c38ae3: Extract pretty-printing of XML responses to helper method in TaskUtil, use StringUtil.notNullize in YouTrackIntellisense models. 6c49b66: IDEA-114523 Fixed svn executable version parsing - support arbitrary text after version (in executable output) 7157489: Make myWorkspaceMap and myUnresolvedCollector volatile. 35e76f4: Comment for getNameThroughCopies method added cb377a5: spelling fixed b5eeae5: svn: Refactored RootUrlInfo - utilize underlying Node instance (instead of just copying fields) b615000: IDEA-113670 Reformat+rearrange per-language setting [CR-IC-2682] b37e22e: Merge remote-tracking branch 'origin/master' 7a40a2c: svn: @NotNull/@Nullable for NestedCopyInfo and RootUrlInfo parameters 05e6734: cleanup 60b90f9: cleanup 6e534ce: update netty (07 oct 4.1 Alpha build) Updated, but ref error was our fault, it is not netty bug. b1d9994: inference: filter out inaccessible for method ref methods 56be1b2: svn: Updated detection if svn roots were changed - added error roots tracking 265806c: svn: Simplified svn executable validation logic - removed explicit major version check 3aadab0: svn: Removed check "if working copy format of project root is compatible with command line client" (during svn executable validation) be91b71: svn: Added notification about errors during svn roots detection 7e742f4: Merge remote-tracking branch 'origin/master' 1c1e2ee: svn: Extracted showing "Subversion Working Copies Information" panel to separate method 16b2321: EA-50707 - assert: TextRange.<init> 35546a0: new inference: ignore captured variables incorporation phase 8c0d7a1: testRunner: wording (IDEA-114500) as attached state is everywhere checked separately 9641ede: plugins notification: hide notification before dialog is shown 3ecdadc: ctors closed 199a379: framework roles 2d68bc5: platform: hidden Windows root dir with NIO2 attribute reader fixed 5ff5b2e: IDEA-113961 (ownership checking) 498d04f: IDEA-113961 (permissions in file attributes deprecated and interned) d9f1d4f: Cleanup (pointless assertion) 415b782: svn: Implemented ability to view svn roots detection errors in "Subversion Working Copies Information" panel f1ecb53: svn: Refactored RootUrlInfo - utilize Node instance on which RootUrlInfo is based b726526: svn: Implemented ability to detect svn roots when working copy format does not correspond to used client (SVNKit or executable could not perform commands on the working copy - for instance, when client is old or working copy upgrade required) 67bdd3a: svn: Implemented ability to resolve client factory and working copy format without checking detected svn roots b15784f: add some ways for reuse in DB part & cleanup 8dae62f: do not proceed with painting if placeHolder text was really painted, i.e. skip error markup, selection, etc 5795402: new inference: reject explicitly typed lambda as pertinent to applicability if its return statements are poly ae3b46c: new inference: temp: ignore inferred Object at first stage 8d2b3e3: new inference: accept methods in lambda return statement as poly without additional checks 5c40157: fixed NPE 5bf3698: Reimplement select word tests for CSS, CoffeeScript, Ruby, Python, Sass, Scss and Less a99db1d: Add test utility method for select word action testing 203e791: prefer variants without leading underscores when case sensitivity=first letter (OC-3547) 4af89f65: IDEA-114514 Grammar error in "Library already exists" dialog 215044f: Allow current element selection in StructureViewer for non-editors. 4ddd1f8: dont' copy editor markup model in language console f2ec48d: extends and implements clauses should always exist in type definitions c3ef7a1: GroovyBlockWithRange f0b2208: Merge remote-tracking branch 'origin/master' c495919: Merge remote-tracking branch 'origin/master' 7ae82a0: Save documents on switch to terminal refresh VFS on switch from it (PY-10944). 14cc2d5: IDEA-114534 Gradle: cancelation of gradle tasks for "out-of-process" mode 4684ba7: Add package-info.java checking to "Declaration has problems in Javadoc references" inspection 53c1eff: [log] Move logProvider extension point to the right place: vcs-log.xml b667798: decode file name for quickfix #WEB-9559 fixed bb34511: new inference: ignore inferred wildcards in return position 74aa35f: new inference: postpone resolve as long as possible 506188d: new inference: mark unresolved calls as poly expressions 3b99b77: Refactor annotator to use visitor 57f9383: Add annotator for inspecting some common errors in JQL queries c889c0a: svn: Refactored vcs roots detection - CopiesDetector moved/renamed to separate class, detection output extracted to separate class cf66975: svn: Forced status command result contain repository root url (resolved with corresponding info command) 2a7389c: svn: Refactored Node class to have notnull fields 69d918e: svn: Refactored WCInfo - utilize RootUrlInfo on which WCInfo is based (instead of just copying fields) a9da4bc: svn: Refactored RootUrlInfo - removed setType() usages where possible 5f09493: svn: Refactored nested copy detection - removed unused code 6eee591: svn: Refactored nested copy detection - extractions, renames, simplified logic b3eeb5e: svn: Refactored nested copy detection - use instance instead of static methods 238c879: svn: Refactored nested copy detection - removed Real class 38db9bf: svn: Refactored nested copy detection - moves, renames dd8b94c: svn: Refactored nested copy detection - simplified data structures for storing nested copies (while collecting changes with ChangeProvider) 8fbc758: svn: Refactored filtering roots that are not actually working copies - methods extracted, logic simplified 66608ee: svn: Refactored inner/external working copies detection - removed unused code 06f90ae: svn: Refactored inner/external working copies detection - methods extracted, logic simplified b44d86f: svn: Refactored nested copies detection by folder status - simplified code flow e397390: svn: Replaced working copy format detection using SVNStatus.getWorkingCopyFormat() with SvnVcs.getWorkingCopyFormat() (1.7 and 1.8 both have "12" entries file format and previously 1.7 was always returned for command line status command) f0a4f49: svn: Refactored working copy format detection for rollback missing files/directories - do not use SVNStatus.getWorkingCopyFormat() 0bdd518: svn: Refactored getting changelist name from SVNStatus - removed duplication and check if working copy format supports change lists 054bf7f: svn: Refactored CommandUtil.escape (simplified) e211be2: svn: Removed unused WorkingCopyFormat parameter from StatusReceiver 8d5fffd: svn: Fixed "upgrade working copy format" dialog - always make current working copy format enabled Change-Id: I928a2caf9bf9d566fb9f556ce39acb5111119c9c
Diffstat (limited to 'platform')
-rw-r--r--platform/analysis-api/src/com/intellij/codeInspection/GlobalInspectionTool.java26
-rw-r--r--platform/analysis-impl/src/com/intellij/codeInsight/daemon/DaemonCodeAnalyzerSettings.java2
-rw-r--r--platform/analysis-impl/src/com/intellij/codeInspection/SuppressionUtil.java4
-rw-r--r--platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionToolWrapper.java11
-rw-r--r--platform/analysis-impl/src/com/intellij/codeStyle/InconsistentLineSeparatorsInspection.java (renamed from platform/platform-impl/src/com/intellij/codeStyle/InconsistentLineSeparatorsInspection.java)11
-rw-r--r--platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java2
-rw-r--r--platform/bootstrap/src/com/intellij/idea/Main.java7
-rw-r--r--platform/core-api/src/com/intellij/concurrency/Job.java23
-rw-r--r--platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java24
-rw-r--r--platform/core-api/src/com/intellij/psi/util/PsiUtilCore.java27
-rw-r--r--platform/core-impl/src/com/intellij/codeInspection/SuppressionUtilCore.java22
-rw-r--r--platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java12
-rw-r--r--platform/core-impl/src/com/intellij/openapi/progress/util/ProgressWrapper.java4
-rw-r--r--platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java1
-rw-r--r--platform/editor-ui-ex/src/com/intellij/codeStyle/AbstractConvertLineSeparatorsAction.java (renamed from platform/platform-impl/src/com/intellij/codeStyle/AbstractConvertLineSeparatorsAction.java)17
-rw-r--r--platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTask.java15
-rw-r--r--platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskState.java2
-rw-r--r--platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskType.java2
-rw-r--r--platform/external-system-api/src/com/intellij/openapi/externalSystem/task/ExternalSystemTaskManager.java4
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/AbstractExternalSystemFacadeImpl.java11
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/RemoteExternalSystemFacade.java10
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/RemoteExternalSystemFacadeImpl.java7
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/AbstractExternalSystemTaskConfigurationType.java5
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java36
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/AbstractExternalSystemTask.java44
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemExecuteTaskTask.java14
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemResolveProjectTask.java14
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemTaskAware.java11
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ProjectStructureHelper.java58
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/AbstractDependencyDataService.java10
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ModuleDependencyDataService.java12
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemProjectResolver.java6
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemProjectResolverImpl.java7
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemTaskManager.java7
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemTaskManagerImpl.java8
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemFacadeWrapper.java9
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemProjectResolverWrapper.java16
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemTaskManagerWrapper.java13
-rw-r--r--platform/icons/src/actions/findWhite.pngbin0 -> 1220 bytes
-rw-r--r--platform/icons/src/actions/findWhite@2x.pngbin0 -> 1659 bytes
-rw-r--r--platform/icons/src/nodes/treeDownArrow.pngbin0 -> 216 bytes
-rw-r--r--platform/icons/src/nodes/treeDownArrow@2x.pngbin0 -> 327 bytes
-rw-r--r--platform/icons/src/nodes/treeRightArrow.pngbin0 -> 222 bytes
-rw-r--r--platform/icons/src/nodes/treeRightArrow@2x.pngbin0 -> 337 bytes
-rw-r--r--platform/indexing-api/src/com/intellij/util/indexing/IdFilter.java6
-rw-r--r--platform/lang-api/src/com/intellij/codeInsight/TailType.java6
-rw-r--r--platform/lang-api/src/com/intellij/codeInsight/completion/CompletionContributor.java4
-rw-r--r--platform/lang-api/src/com/intellij/codeInsight/completion/InsertionContext.java6
-rw-r--r--platform/lang-api/src/com/intellij/codeInsight/completion/SkipAutopopupInStrings.java6
-rw-r--r--platform/lang-api/src/com/intellij/formatting/FormattingDocumentModel.java1
-rw-r--r--platform/lang-api/src/com/intellij/framework/FrameworkGroupVersion.java7
-rw-r--r--platform/lang-api/src/com/intellij/framework/FrameworkVersion.java5
-rw-r--r--platform/lang-api/src/com/intellij/framework/PresentableVersion.java32
-rw-r--r--platform/lang-api/src/com/intellij/framework/library/FrameworkLibraryVersion.java3
-rw-r--r--platform/lang-api/src/com/intellij/ide/util/frameworkSupport/FrameworkRole.java49
-rw-r--r--platform/lang-api/src/com/intellij/ide/util/frameworkSupport/FrameworkSupportProvider.java4
-rw-r--r--platform/lang-api/src/com/intellij/ide/util/projectWizard/ModuleBuilder.java6
-rw-r--r--platform/lang-api/src/com/intellij/openapi/module/ModuleType.java8
-rw-r--r--platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java28
-rw-r--r--platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java25
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.form104
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.java31
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java25
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/additional/ForceArrangementPanel.java103
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.java25
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java13
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java6
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java2
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonEditorPopup.java15
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java4
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java45
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/editorActions/AutoHardWrapHandler.java13
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/editorActions/CodeDocumentationUtil.java6
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java6
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/editorActions/SelectWordUtil.java50
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java7
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/generation/DelegateMethodsHandler.java6
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/generation/ImplementMethodsHandler.java6
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/generation/OverrideMethodsHandler.java6
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/generation/actions/DelegateMethodsAction.java6
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/generation/actions/ImplementMethodsAction.java6
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/generation/actions/OverrideMethodsAction.java6
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java4
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java6
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowParameterInfoAction.java6
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.java3
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoSuperAction.java6
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/LiveTemplateBuilder.java14
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateLookupElement.java5
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java3
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java7
-rw-r--r--platform/lang-impl/src/com/intellij/codeInspection/LossyEncodingInspection.java11
-rw-r--r--platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java16
-rw-r--r--platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java3
-rw-r--r--platform/lang-impl/src/com/intellij/framework/library/impl/FrameworkLibraryVersionImpl.java11
-rw-r--r--platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java274
-rw-r--r--platform/lang-impl/src/com/intellij/ide/actions/ViewStructureAction.java36
-rw-r--r--platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java4
-rw-r--r--platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateConfigurable.java4
-rw-r--r--platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateManagerImpl.java10
-rw-r--r--platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateTab.java5
-rw-r--r--platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplatesLoader.java25
-rw-r--r--platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java2
-rw-r--r--platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java143
-rw-r--r--platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java139
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorPsiDataProvider.java8
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/CommonContentEntriesEditor.java1
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/JavaTestSourceRootEditHandler.java3
-rw-r--r--platform/lang-impl/src/com/intellij/psi/formatter/DocumentBasedFormattingModel.java5
-rw-r--r--platform/lang-impl/src/com/intellij/psi/formatter/FormattingDocumentModelImpl.java5
-rw-r--r--platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java1
-rw-r--r--platform/lang-impl/src/com/intellij/refactoring/extractMethod/SimpleDuplicatesFinder.java7
-rw-r--r--platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesHandler.java2
-rw-r--r--platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java13
-rw-r--r--platform/lang-impl/src/com/intellij/ui/tabs/FileColorConfigurationEditDialog.java2
-rw-r--r--platform/lang-impl/src/com/intellij/util/ui/classpath/SimpleClasspathElementFactory.java18
-rw-r--r--platform/platform-api/src/com/intellij/openapi/application/ApplicationInfo.java1
-rw-r--r--platform/platform-api/src/com/intellij/openapi/ui/MessageType.java8
-rw-r--r--platform/platform-api/src/com/intellij/openapi/vfs/VfsUtil.java25
-rw-r--r--platform/platform-api/src/com/intellij/ui/CheckedTreeNode.java4
-rw-r--r--platform/platform-api/src/com/intellij/ui/SearchTextField.java4
-rw-r--r--platform/platform-api/src/com/intellij/ui/components/OnOffButton.java7
-rw-r--r--platform/platform-api/src/com/intellij/util/MixinEP.java8
-rw-r--r--platform/platform-impl/src/com/intellij/concurrency/ApplierCompleter.java231
-rw-r--r--platform/platform-impl/src/com/intellij/concurrency/JobImpl.java245
-rw-r--r--platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java241
-rw-r--r--platform/platform-impl/src/com/intellij/concurrency/JobSchedulerImpl.java66
-rw-r--r--platform/platform-impl/src/com/intellij/concurrency/PrioritizedFutureTask.java126
-rw-r--r--platform/platform-impl/src/com/intellij/concurrency/SensitiveProgressWrapper.java34
-rw-r--r--platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java4
-rw-r--r--platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java10
-rw-r--r--platform/platform-impl/src/com/intellij/ide/plugins/RepositoryHelper.java2
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/AppearanceConfigurable.java6
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/AppearancePanel.form18
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/laf/IntelliJLaf.java40
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/laf/IntelliJLookAndFeelInfo.java37
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java6
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java46
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaUIUtil.java21
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties19
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaButtonUI.java53
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaCheckBoxUI.java63
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java11
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.css383
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties144
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_linux.properties7
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_windows.properties10
-rw-r--r--platform/platform-impl/src/com/intellij/idea/StartupUtil.java2
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java9
-rwxr-xr-xplatform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java19
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java4
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java3
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java8
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java5
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/editor/impl/ContextMenuImpl.java5
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java9
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java232
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java5
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java16
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableWrapper.java4
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java2
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginAdvertiserEditorNotificationProvider.java153
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiser.java138
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/UnknownFeaturesCollector.java8
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/vfs/ex/temp/TempFileSystem.java35
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/FileWatcher.java48
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshSessionImpl.java1
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/VfsImplUtil.java2
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java4
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java13
-rw-r--r--platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java496
-rw-r--r--platform/platform-impl/src/com/intellij/ui/popup/PopupComponent.java19
-rw-r--r--platform/platform-impl/src/com/intellij/util/IJSwingUtilities.java5
-rw-r--r--platform/platform-resources-en/src/messages/ApplicationBundle.properties17
-rw-r--r--platform/platform-resources-en/src/messages/IdeBundle.properties3
-rw-r--r--platform/platform-resources-en/src/messages/SMTestsRunnerBundle.properties2
-rw-r--r--platform/platform-resources-en/src/messages/XDebuggerBundle.properties1
-rw-r--r--platform/platform-resources-en/src/misc/registry.properties3
-rw-r--r--platform/platform-resources/src/META-INF/PlatformExtensions.xml1
-rw-r--r--platform/platform-resources/src/META-INF/VcsExtensionPoints.xml2
-rw-r--r--platform/platform-resources/src/idea/Keymap_Default.xml3
-rw-r--r--platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.java6
-rw-r--r--platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/LocalFileSystemTest.java36
-rw-r--r--platform/projectModel-api/src/com/intellij/openapi/projectRoots/ProjectJdkTable.java2
-rw-r--r--platform/projectModel-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdater.java25
-rw-r--r--platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtilTest.java3
-rw-r--r--platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java7
-rw-r--r--platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java8
-rw-r--r--platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java2
-rw-r--r--platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestUtil.java29
-rw-r--r--platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java18
-rw-r--r--platform/util/src/com/intellij/icons/AllIcons.java3
-rw-r--r--platform/util/src/com/intellij/openapi/util/NullableComputable.java3
-rw-r--r--platform/util/src/com/intellij/openapi/util/io/FileAttributes.java93
-rw-r--r--platform/util/src/com/intellij/openapi/util/io/FileSystemUtil.java290
-rw-r--r--platform/util/src/com/intellij/openapi/util/io/FileUtil.java17
-rw-r--r--platform/util/src/com/intellij/openapi/util/text/StringUtil.java30
-rw-r--r--platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java7711
-rw-r--r--platform/util/src/com/intellij/util/containers/Convertor.java3
-rw-r--r--platform/util/src/com/intellij/util/io/SafeFileOutputStream.java8
-rw-r--r--platform/util/src/com/intellij/util/ui/UIUtil.java9
-rw-r--r--platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java8
-rw-r--r--platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesNio2ReadingTest.java4
-rw-r--r--platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java22
-rw-r--r--platform/util/testSrc/com/intellij/openapi/util/io/FileUtilFindFileTest.java105
-rw-r--r--platform/util/testSrc/com/intellij/openapi/util/io/FileUtilHeavyTest.java217
-rw-r--r--platform/util/testSrc/com/intellij/openapi/util/io/FileUtilLightTest.java (renamed from platform/util/testSrc/com/intellij/openapi/util/io/FileUtilTest.java)83
-rw-r--r--platform/util/testSrc/com/intellij/util/text/StringUtilTest.java2
-rw-r--r--platform/util/util.iml1
-rw-r--r--platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserNode.java1
-rw-r--r--platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesTreeList.java104
-rw-r--r--platform/vcs-log/impl/src/META-INF/vcs-log.xml3
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java11
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java35
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java28
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/EvaluatingExpressionRootNode.java37
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/MessageTreeNode.java2
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java3
218 files changed, 11190 insertions, 2939 deletions
diff --git a/platform/analysis-api/src/com/intellij/codeInspection/GlobalInspectionTool.java b/platform/analysis-api/src/com/intellij/codeInspection/GlobalInspectionTool.java
index 5e72c932b71c..077afec102b8 100644
--- a/platform/analysis-api/src/com/intellij/codeInspection/GlobalInspectionTool.java
+++ b/platform/analysis-api/src/com/intellij/codeInspection/GlobalInspectionTool.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -30,6 +30,10 @@ import org.jetbrains.annotations.Nullable;
* complete graph of references between classes, methods and other elements in the scope
* selected for the analysis.
*
+ * Global inspections can use a shared local inspection tool for highlighting the cases
+ * that do not need global analysis in the editor by implementing {@link #getSharedLocalInspectionTool()}
+ * The shared local inspection tools shares settings and documentation with the global inspection tool.
+ *
* @author anna
* @see LocalInspectionTool
* @since 6.0
@@ -193,9 +197,25 @@ public abstract class GlobalInspectionTool extends InspectionProfileEntry {
return null;
}
- // In some cases we can do highlighting in annotator or high. visitor based on global inspection
+ /**
+ * In some cases we can do highlighting in annotator or high. visitor based on global inspection or use a shared local inspection tool
+ */
public boolean worksInBatchModeOnly() {
- return true;
+ return getSharedLocalInspectionTool() != null;
+ }
+
+ /**
+ * Returns the local inspection tool used for highlighting in the editor. Meant for global inspections which have a local component.
+ * The local inspection tool is not required to report on the exact same problems, and naturally can't use global analysis. The local
+ * inspection tool is not used in batch mode.
+ *
+ * For example a global inspection that reports a package could have a local inspection tool which highlights
+ * the package statement in a file.
+ * @return
+ */
+ @Nullable
+ public LocalInspectionTool getSharedLocalInspectionTool() {
+ return null;
}
public void initialize(@NotNull GlobalInspectionContext context) {
diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/DaemonCodeAnalyzerSettings.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/DaemonCodeAnalyzerSettings.java
index 4cc19cebef7b..0b3d945f85f3 100644
--- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/DaemonCodeAnalyzerSettings.java
+++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/DaemonCodeAnalyzerSettings.java
@@ -24,7 +24,7 @@ public class DaemonCodeAnalyzerSettings {
return ServiceManager.getService(DaemonCodeAnalyzerSettings.class);
}
- public boolean NEXT_ERROR_ACTION_GOES_TO_ERRORS_FIRST = false;
+ public boolean NEXT_ERROR_ACTION_GOES_TO_ERRORS_FIRST = true;
public int AUTOREPARSE_DELAY = 300;
public boolean SHOW_ADD_IMPORT_HINTS = true;
@NonNls public String NO_AUTO_IMPORT_PATTERN = "[a-z].?";
diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/SuppressionUtil.java b/platform/analysis-impl/src/com/intellij/codeInspection/SuppressionUtil.java
index b2f0c8ee2cc7..869d1f220b87 100644
--- a/platform/analysis-impl/src/com/intellij/codeInspection/SuppressionUtil.java
+++ b/platform/analysis-impl/src/com/intellij/codeInspection/SuppressionUtil.java
@@ -41,9 +41,7 @@ import java.util.regex.Pattern;
/**
* @author yole
*/
-public class SuppressionUtil {
- @NonNls public static final String SUPPRESS_INSPECTIONS_TAG_NAME = "noinspection";
-
+public class SuppressionUtil extends SuppressionUtilCore {
/**
* Common part of regexp for suppressing in line comments for different languages.
* Comment start prefix isn't included, e.g. add '//' for Java/C/JS or '#' for Ruby
diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionToolWrapper.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionToolWrapper.java
index 5fb8e9442308..8f6e87c3c495 100644
--- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionToolWrapper.java
+++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionToolWrapper.java
@@ -18,10 +18,12 @@ package com.intellij.codeInspection.ex;
import com.intellij.codeInspection.GlobalInspectionContext;
import com.intellij.codeInspection.GlobalInspectionTool;
import com.intellij.codeInspection.InspectionEP;
+import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.reference.RefGraphAnnotator;
import com.intellij.codeInspection.reference.RefManagerImpl;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
/**
* User: anna
@@ -72,4 +74,13 @@ public class GlobalInspectionToolWrapper extends InspectionToolWrapper<GlobalIns
public boolean worksInBatchModeOnly() {
return getTool().worksInBatchModeOnly();
}
+
+ @Nullable
+ public LocalInspectionToolWrapper getSharedLocalInspectionToolWrapper() {
+ final LocalInspectionTool sharedTool = getTool().getSharedLocalInspectionTool();
+ if (sharedTool == null) {
+ return null;
+ }
+ return new LocalInspectionToolWrapper(sharedTool);
+ }
}
diff --git a/platform/platform-impl/src/com/intellij/codeStyle/InconsistentLineSeparatorsInspection.java b/platform/analysis-impl/src/com/intellij/codeStyle/InconsistentLineSeparatorsInspection.java
index de31bc2d7d92..97e0261987e4 100644
--- a/platform/platform-impl/src/com/intellij/codeStyle/InconsistentLineSeparatorsInspection.java
+++ b/platform/analysis-impl/src/com/intellij/codeStyle/InconsistentLineSeparatorsInspection.java
@@ -19,6 +19,7 @@ import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemsHolder;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
@@ -46,10 +47,7 @@ public class InconsistentLineSeparatorsInspection extends LocalInspectionTool {
}
final Project project = holder.getProject();
- final String projectLineSeparator = CodeStyleFacade.getInstance(project).getLineSeparator();
- if (projectLineSeparator == null) {
- return;
- }
+ final String projectLineSeparator = FileDocumentManager.getInstance().getLineSeparator(null, project);
final VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile == null || !AbstractConvertLineSeparatorsAction.shouldProcess(virtualFile, project)) {
@@ -88,10 +86,7 @@ public class InconsistentLineSeparatorsInspection extends LocalInspectionTool {
return;
}
- final String lineSeparator = CodeStyleFacade.getInstance(project).getLineSeparator();
- if (lineSeparator == null) {
- return;
- }
+ final String lineSeparator = FileDocumentManager.getInstance().getLineSeparator(null, project);
final VirtualFile virtualFile = ((PsiFile)psiElement).getVirtualFile();
if (virtualFile != null) {
diff --git a/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java b/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java
index 582c728af173..69c2b0cdf326 100644
--- a/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java
+++ b/platform/analysis-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReference.java
@@ -198,7 +198,7 @@ public class FileReference implements PsiFileReference, FileReferenceOwner, PsiP
}
public String getFileNameToCreate() {
- return getCanonicalText();
+ return decode(getCanonicalText());
}
public
diff --git a/platform/bootstrap/src/com/intellij/idea/Main.java b/platform/bootstrap/src/com/intellij/idea/Main.java
index b095fabae055..c9a3f8e68004 100644
--- a/platform/bootstrap/src/com/intellij/idea/Main.java
+++ b/platform/bootstrap/src/com/intellij/idea/Main.java
@@ -40,13 +40,18 @@ public class Main {
private static final String AWT_HEADLESS = "java.awt.headless";
private static final String PLATFORM_PREFIX_PROPERTY = "idea.platform.prefix";
+ private static final String[] NO_ARGS = {};
private static boolean isHeadless;
private static boolean isCommandLine;
private Main() { }
- public static void main(final String[] args) {
+ public static void main(String[] args) {
+ if (args.length == 1 && "%f".equals(args[0])) {
+ args = NO_ARGS;
+ }
+
setFlags(args);
if (isHeadless()) {
diff --git a/platform/core-api/src/com/intellij/concurrency/Job.java b/platform/core-api/src/com/intellij/concurrency/Job.java
index 488ec8aa6947..f20917d2e703 100644
--- a/platform/core-api/src/com/intellij/concurrency/Job.java
+++ b/platform/core-api/src/com/intellij/concurrency/Job.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -19,10 +19,13 @@
*/
package com.intellij.concurrency;
+import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
public interface Job<T> {
// the lower the priority the more important the task is
@@ -46,6 +49,7 @@ public interface Job<T> {
boolean isDone();
+ void waitForCompletion(int millis) throws InterruptedException, ExecutionException, TimeoutException;
@NotNull
Job NULL_JOB = new Job() {
@@ -55,6 +59,11 @@ public interface Job<T> {
}
@Override
+ public void waitForCompletion(int millis) {
+
+ }
+
+ @Override
public void cancel() {
}
@@ -65,32 +74,32 @@ public interface Job<T> {
@Override
public void addTask(@NotNull Callable task) {
-
+ throw new IncorrectOperationException();
}
@Override
public void addTask(@NotNull Runnable task, Object result) {
-
+ throw new IncorrectOperationException();
}
@Override
public void addTask(@NotNull Runnable task) {
-
+ throw new IncorrectOperationException();
}
@Override
public List scheduleAndWaitForResults() throws Throwable {
- return null;
+ throw new IncorrectOperationException();
}
@Override
public boolean isCanceled() {
- return false;
+ return true;
}
@Override
public void schedule() {
-
+ throw new IncorrectOperationException();
}
};
diff --git a/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java b/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java
index 71a830a4c007..9734068a9dc0 100644
--- a/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java
+++ b/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java
@@ -27,6 +27,7 @@ import com.intellij.util.Function;
import com.intellij.util.PathUtil;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.Convertor;
import com.intellij.util.containers.DistinctRootsCollection;
import com.intellij.util.io.URLUtil;
import com.intellij.util.text.StringFactory;
@@ -550,4 +551,27 @@ public class VfsUtilCore {
return VfsUtilCore.isAncestor(ancestor, virtualFile, false);
}
}
+
+ public static void processFilesRecursively(@NotNull VirtualFile root,
+ @NotNull Processor<VirtualFile> processor,
+ @NotNull Convertor<VirtualFile, Boolean> directoryFilter) {
+ if (!processor.process(root)) return;
+
+ if (root.isDirectory() && directoryFilter.convert(root)) {
+ final LinkedList<VirtualFile[]> queue = new LinkedList<VirtualFile[]>();
+
+ queue.add(root.getChildren());
+
+ do {
+ final VirtualFile[] files = queue.removeFirst();
+
+ for (VirtualFile file : files) {
+ if (!processor.process(file)) return;
+ if (file.isDirectory() && directoryFilter.convert(file)) {
+ queue.add(file.getChildren());
+ }
+ }
+ } while (!queue.isEmpty());
+ }
+ }
}
diff --git a/platform/core-api/src/com/intellij/psi/util/PsiUtilCore.java b/platform/core-api/src/com/intellij/psi/util/PsiUtilCore.java
index 1948ff4d95ab..eaf72d5504f7 100644
--- a/platform/core-api/src/com/intellij/psi/util/PsiUtilCore.java
+++ b/platform/core-api/src/com/intellij/psi/util/PsiUtilCore.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2011 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.
@@ -483,4 +483,29 @@ public class PsiUtilCore {
}
return parent;
}
+
+ @NotNull
+ public static Language findLanguageFromElement(final PsiElement elt) {
+ if (elt.getFirstChild() == null) { //is leaf
+ final PsiElement parent = elt.getParent();
+ if (parent != null) {
+ return parent.getLanguage();
+ }
+ }
+
+ return elt.getLanguage();
+ }
+
+ @NotNull
+ public static Language getLanguageAtOffset (@NotNull PsiFile file, int offset) {
+ final PsiElement elt = file.findElementAt(offset);
+ if (elt == null) return file.getLanguage();
+ if (elt instanceof PsiWhiteSpace) {
+ final int decremented = elt.getTextRange().getStartOffset() - 1;
+ if (decremented >= 0) {
+ return getLanguageAtOffset(file, decremented);
+ }
+ }
+ return findLanguageFromElement(elt);
+ }
}
diff --git a/platform/core-impl/src/com/intellij/codeInspection/SuppressionUtilCore.java b/platform/core-impl/src/com/intellij/codeInspection/SuppressionUtilCore.java
new file mode 100644
index 000000000000..55e33a400594
--- /dev/null
+++ b/platform/core-impl/src/com/intellij/codeInspection/SuppressionUtilCore.java
@@ -0,0 +1,22 @@
+/*
+ * 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.codeInspection;
+
+import org.jetbrains.annotations.NonNls;
+
+public class SuppressionUtilCore {
+ @NonNls public static final String SUPPRESS_INSPECTIONS_TAG_NAME = "noinspection";
+}
diff --git a/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java b/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java
index f07fd284f13a..66062ee4766c 100644
--- a/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java
+++ b/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java
@@ -150,6 +150,18 @@ public class PluginManagerCore {
return true;
}
+ public static boolean enablePlugin(String id) {
+ if (!getDisabledPlugins().contains(id)) return false;
+ getDisabledPlugins().remove(id);
+ try {
+ saveDisabledPlugins(getDisabledPlugins(), false);
+ }
+ catch (IOException e) {
+ return false;
+ }
+ return true;
+ }
+
public static void saveDisabledPlugins(Collection<String> ids, boolean append) throws IOException {
File plugins = new File(PathManager.getConfigPath(), DISABLED_PLUGINS_FILENAME);
savePluginsList(ids, append, plugins);
diff --git a/platform/core-impl/src/com/intellij/openapi/progress/util/ProgressWrapper.java b/platform/core-impl/src/com/intellij/openapi/progress/util/ProgressWrapper.java
index f8520610ffda..a192ae0fd258 100644
--- a/platform/core-impl/src/com/intellij/openapi/progress/util/ProgressWrapper.java
+++ b/platform/core-impl/src/com/intellij/openapi/progress/util/ProgressWrapper.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -29,7 +29,7 @@ import org.jetbrains.annotations.Nullable;
public class ProgressWrapper extends AbstractProgressIndicatorBase {
private final ProgressIndicator myOriginal;
- private ProgressWrapper(@NotNull ProgressIndicator original) {
+ protected ProgressWrapper(@NotNull ProgressIndicator original) {
myOriginal = original;
}
diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java
index 62799195b045..b7fb408d6318 100644
--- a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java
+++ b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java
@@ -69,6 +69,7 @@ public class UISettings implements PersistentStateComponent<UISettings>, Exporta
public boolean WIDESCREEN_SUPPORT = false;
public boolean LEFT_HORIZONTAL_SPLIT = false;
public boolean RIGHT_HORIZONTAL_SPLIT = false;
+ public boolean SHOW_EDITOR_TOOLTIP = true;
public boolean SHOW_MEMORY_INDICATOR = false;
public boolean ALLOW_MERGE_BUTTONS = true;
public boolean SHOW_MAIN_TOOLBAR = false;
diff --git a/platform/platform-impl/src/com/intellij/codeStyle/AbstractConvertLineSeparatorsAction.java b/platform/editor-ui-ex/src/com/intellij/codeStyle/AbstractConvertLineSeparatorsAction.java
index d09b3a2643a9..8f54a068385a 100644
--- a/platform/platform-impl/src/com/intellij/codeStyle/AbstractConvertLineSeparatorsAction.java
+++ b/platform/editor-ui-ex/src/com/intellij/codeStyle/AbstractConvertLineSeparatorsAction.java
@@ -21,12 +21,12 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
-import com.intellij.openapi.fileTypes.FileTypeManager;
+import com.intellij.openapi.fileTypes.FileTypeRegistry;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.FileIndexFacade;
import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.LineSeparator;
import com.intellij.util.Processor;
@@ -40,14 +40,13 @@ import java.io.IOException;
* @author Nikolai Matveev
*/
public abstract class AbstractConvertLineSeparatorsAction extends AnAction {
-
- private static Logger LOG = Logger.getInstance("#com.intellij.codeStyle.AbstractConvertLineSeparatorsAction");
+ private static final Logger LOG = Logger.getInstance("#com.intellij.codeStyle.AbstractConvertLineSeparatorsAction");
@NotNull
private final String mySeparator;
protected AbstractConvertLineSeparatorsAction(@Nullable String text, @NotNull LineSeparator separator) {
- this(separator.toString() + " - " + text, separator.getSeparatorString());
+ this(separator + " - " + text, separator.getSeparatorString());
}
protected AbstractConvertLineSeparatorsAction(@Nullable String text, @NotNull String separator) {
@@ -98,9 +97,9 @@ public abstract class AbstractConvertLineSeparatorsAction extends AnAction {
projectVirtualDirectory = null;
}
- final FileTypeManager fileTypeManager = FileTypeManager.getInstance();
+ final FileTypeRegistry fileTypeManager = FileTypeRegistry.getInstance();
for (VirtualFile file : virtualFiles) {
- VfsUtil.processFilesRecursively(
+ VfsUtilCore.processFilesRecursively(
file,
new Processor<VirtualFile>() {
@Override
@@ -115,7 +114,7 @@ public abstract class AbstractConvertLineSeparatorsAction extends AnAction {
@Override
public Boolean convert(VirtualFile dir) {
return !dir.equals(projectVirtualDirectory)
- && !fileTypeManager.isFileIgnored(dir.getName()); // Exclude files like '.git'
+ && !fileTypeManager.isFileIgnored(dir); // Exclude files like '.git'
}
}
);
@@ -125,7 +124,7 @@ public abstract class AbstractConvertLineSeparatorsAction extends AnAction {
public static boolean shouldProcess(@NotNull VirtualFile file, @NotNull Project project) {
if (file.isDirectory()
|| !file.isWritable()
- || FileTypeManager.getInstance().isFileIgnored(file)
+ || FileTypeRegistry.getInstance().isFileIgnored(file)
|| file.getFileType().isBinary()
|| file.equals(project.getProjectFile())
|| file.equals(project.getWorkspaceFile()))
diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTask.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTask.java
index 4c93222793fc..2329fd38e67d 100644
--- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTask.java
+++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTask.java
@@ -38,6 +38,21 @@ public interface ExternalSystemTask {
void execute(@NotNull ExternalSystemTaskNotificationListener... listeners);
/**
+ * Cancels current task and updates given indicator's {@link ProgressIndicator#setText2(String) status} during that.
+ *
+ * @param indicator target progress indicator
+ * @param listeners callbacks to be notified on task execution update
+ */
+ void cancel(@NotNull ProgressIndicator indicator, @NotNull ExternalSystemTaskNotificationListener... listeners);
+
+ /**
+ * Cancels current task at the calling thread, i.e. the call to this method blocks.
+ *
+ * @param listeners callbacks to be notified about the task execution update
+ */
+ void cancel(@NotNull ExternalSystemTaskNotificationListener... listeners);
+
+ /**
* Forces current task to refresh {@link #getState() its state}.
*/
void refreshState();
diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskState.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskState.java
index 315a7a6fecf6..2df96affc604 100644
--- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskState.java
+++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskState.java
@@ -21,5 +21,5 @@ package com.intellij.openapi.externalSystem.model.task;
*/
public enum ExternalSystemTaskState {
- NOT_STARTED, IN_PROGRESS, FINISHED, FAILED
+ NOT_STARTED, IN_PROGRESS, FINISHED, FAILED, CANCELING, CANCELED
}
diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskType.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskType.java
index 490e8a5dfe76..81ce2f65a230 100644
--- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskType.java
+++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/ExternalSystemTaskType.java
@@ -1,7 +1,7 @@
package com.intellij.openapi.externalSystem.model.task;
/**
- * Enumerates interested types of tasks that may be enqueued to Gradle API.
+ * Enumerates interested types of tasks that may be enqueued to external systems API.
*
* @author Denis Zhdanov
* @since 11/10/11 9:07 AM
diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/task/ExternalSystemTaskManager.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/task/ExternalSystemTaskManager.java
index 4629e383795c..df27cdb7a382 100644
--- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/task/ExternalSystemTaskManager.java
+++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/task/ExternalSystemTaskManager.java
@@ -40,4 +40,8 @@ public interface ExternalSystemTaskManager<S extends ExternalSystemExecutionSett
@Nullable String debuggerSetup,
@NotNull ExternalSystemTaskNotificationListener listener)
throws ExternalSystemException;
+
+ void cancelTask(@NotNull ExternalSystemTaskId id,
+ @NotNull ExternalSystemTaskNotificationListener listener)
+ throws ExternalSystemException;
}
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/AbstractExternalSystemFacadeImpl.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/AbstractExternalSystemFacadeImpl.java
index 98deeacde3b5..5ff4b7228d96 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/AbstractExternalSystemFacadeImpl.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/AbstractExternalSystemFacadeImpl.java
@@ -187,7 +187,16 @@ public abstract class AbstractExternalSystemFacadeImpl<S extends ExternalSystemE
myProjectResolver.setNotificationListener(listener);
myTaskManager.setNotificationListener(listener);
}
-
+
+ @Override
+ public void cancelTask(@NotNull ExternalSystemTaskId id) throws RemoteException {
+ if(id.getType() == ExternalSystemTaskType.RESOLVE_PROJECT) {
+ myProjectResolver.cancelTask(id);
+ } else{
+ myTaskManager.cancelTask(id);
+ }
+ }
+
private static class SwallowingNotificationListener implements ExternalSystemTaskNotificationListener {
@NotNull private final RemoteExternalSystemProgressNotificationManager myManager;
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/RemoteExternalSystemFacade.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/RemoteExternalSystemFacade.java
index 10c2e42d87c5..5a095f740069 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/RemoteExternalSystemFacade.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/RemoteExternalSystemFacade.java
@@ -1,12 +1,12 @@
package com.intellij.openapi.externalSystem.service;
-import com.intellij.openapi.externalSystem.service.internal.ExternalSystemTaskAware;
+import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings;
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId;
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType;
-import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings;
-import com.intellij.openapi.externalSystem.service.remote.RemoteExternalSystemTaskManager;
+import com.intellij.openapi.externalSystem.service.internal.ExternalSystemTaskAware;
import com.intellij.openapi.externalSystem.service.remote.RemoteExternalSystemProgressNotificationManager;
import com.intellij.openapi.externalSystem.service.remote.RemoteExternalSystemProjectResolver;
+import com.intellij.openapi.externalSystem.service.remote.RemoteExternalSystemTaskManager;
import org.jetbrains.annotations.NotNull;
import java.rmi.Remote;
@@ -56,6 +56,10 @@ public interface RemoteExternalSystemFacade<S extends ExternalSystemExecutionSet
return false;
}
+ @Override
+ public void cancelTask(@NotNull ExternalSystemTaskId id) throws RemoteException {
+ }
+
@NotNull
@Override
public Map<ExternalSystemTaskType, Set<ExternalSystemTaskId>> getTasksInProgress() throws RemoteException {
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/RemoteExternalSystemFacadeImpl.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/RemoteExternalSystemFacadeImpl.java
index 16d181ea7bc3..625c83c2a0d9 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/RemoteExternalSystemFacadeImpl.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/RemoteExternalSystemFacadeImpl.java
@@ -18,6 +18,8 @@ package com.intellij.openapi.externalSystem.service;
import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings;
import com.intellij.openapi.externalSystem.service.project.ExternalSystemProjectResolver;
import com.intellij.openapi.externalSystem.task.ExternalSystemTaskManager;
+import com.intellij.openapi.externalSystem.util.ExternalSystemConstants;
+import com.intellij.openapi.util.registry.Registry;
import com.intellij.util.Alarm;
import org.jetbrains.annotations.NotNull;
@@ -82,6 +84,11 @@ public class RemoteExternalSystemFacadeImpl<S extends ExternalSystemExecutionSet
));
}
+ // running the code indicates remote communication mode with external system
+ Registry.get(
+ System.getProperty(ExternalSystemConstants.EXTERNAL_SYSTEM_ID_KEY) +
+ ExternalSystemConstants.USE_IN_PROCESS_COMMUNICATION_REGISTRY_KEY_SUFFIX).setValue(false);
+
RemoteExternalSystemFacadeImpl facade = new RemoteExternalSystemFacadeImpl(resolverClass, buildManagerClass);
facade.init();
start(facade);
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/AbstractExternalSystemTaskConfigurationType.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/AbstractExternalSystemTaskConfigurationType.java
index 5f050bb0b276..2d8377bbf2e5 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/AbstractExternalSystemTaskConfigurationType.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/AbstractExternalSystemTaskConfigurationType.java
@@ -129,7 +129,10 @@ public abstract class AbstractExternalSystemTaskConfigurationType implements Con
Map<String/* project dir path */, String/* project file path */> rootProjectPaths = ContainerUtilRt.newHashMap();
for (ExternalProjectSettings projectSettings : s.getLinkedProjectsSettings()) {
String path = projectSettings.getExternalProjectPath();
- rootProjectPaths.put(new File(path).getParentFile().getAbsolutePath(), path);
+ if(path == null) continue;
+ final File rootProjectPathFile = new File(path).getParentFile();
+ if(rootProjectPathFile == null) continue;
+ rootProjectPaths.put(rootProjectPathFile.getAbsolutePath(), path);
}
String rootProjectPath = null;
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java
index be7193b37bfb..a9bb3df568a5 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/execution/ExternalSystemRunConfiguration.java
@@ -4,7 +4,10 @@ import com.intellij.execution.DefaultExecutionResult;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.ExecutionResult;
import com.intellij.execution.Executor;
-import com.intellij.execution.configurations.*;
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.configurations.LocatableConfigurationBase;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.execution.configurations.RunProfileState;
import com.intellij.execution.executors.DefaultDebugExecutor;
import com.intellij.execution.filters.TextConsoleBuilderImpl;
import com.intellij.execution.process.ProcessHandler;
@@ -137,8 +140,6 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase {
public ExecutionResult execute(Executor executor, @NotNull ProgramRunner runner) throws ExecutionException {
ExternalSystemUtil.updateRecentTasks(new ExternalTaskExecutionInfo(mySettings.clone(), executor.getId()), myProject);
ConsoleView console = new TextConsoleBuilderImpl(myProject).getConsole();
- final MyProcessHandler processHandler = new MyProcessHandler();
- console.attachToProcess(processHandler);
final List<ExternalTaskPojo> tasks = ContainerUtilRt.newArrayList();
for (String taskName : mySettings.getTaskNames()) {
tasks.add(new ExternalTaskPojo(taskName, mySettings.getExternalProjectPath(), null));
@@ -156,6 +157,10 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase {
tasks,
mySettings.getVmOptions(),
debuggerSetup);
+
+ final MyProcessHandler processHandler = new MyProcessHandler(task);
+ console.attachToProcess(processHandler);
+
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
@@ -190,14 +195,37 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase {
return new DefaultExecutionResult(console, processHandler);
}
}
-
+
private static class MyProcessHandler extends ProcessHandler {
+ private final ExternalSystemExecuteTaskTask myTask;
+
+ public MyProcessHandler(ExternalSystemExecuteTaskTask task) {
+ myTask = task;
+ }
+
@Override
protected void destroyProcessImpl() {
}
@Override
protected void detachProcessImpl() {
+ myTask.cancel(new ExternalSystemTaskNotificationListenerAdapter() {
+
+ private boolean myResetGreeting = true;
+
+ @Override
+ public void onTaskOutput(@NotNull ExternalSystemTaskId id, @NotNull String text, boolean stdOut) {
+ if (myResetGreeting) {
+ notifyTextAvailable("\r", ProcessOutputTypes.SYSTEM);
+ myResetGreeting = false;
+ }
+ notifyTextAvailable(text, stdOut ? ProcessOutputTypes.STDOUT : ProcessOutputTypes.STDERR);
+ }
+
+ @Override
+ public void onEnd(@NotNull ExternalSystemTaskId id) {
+ }
+ });
notifyProcessDetached();
}
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/AbstractExternalSystemTask.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/AbstractExternalSystemTask.java
index e7367232bfce..562cf4d8e6bb 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/AbstractExternalSystemTask.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/AbstractExternalSystemTask.java
@@ -143,6 +143,50 @@ public abstract class AbstractExternalSystemTask implements ExternalSystemTask {
protected abstract void doExecute() throws Exception;
+ @Override
+ public void cancel(@NotNull final ProgressIndicator indicator, @NotNull ExternalSystemTaskNotificationListener... listeners) {
+ indicator.setIndeterminate(true);
+ ExternalSystemTaskNotificationListenerAdapter adapter = new ExternalSystemTaskNotificationListenerAdapter() {
+ @Override
+ public void onStatusChange(@NotNull ExternalSystemTaskNotificationEvent event) {
+ indicator.setText(wrapProgressText(event.getDescription()));
+ }
+ };
+ final ExternalSystemTaskNotificationListener[] ls;
+ if (listeners.length > 0) {
+ ls = ArrayUtil.append(listeners, adapter);
+ }
+ else {
+ ls = new ExternalSystemTaskNotificationListener[] { adapter };
+ }
+
+ cancel(ls);
+ }
+
+ @Override
+ public void cancel(@NotNull ExternalSystemTaskNotificationListener... listeners) {
+ ExternalSystemProgressNotificationManager progressManager = ServiceManager.getService(ExternalSystemProgressNotificationManager.class);
+ for (ExternalSystemTaskNotificationListener listener : listeners) {
+ progressManager.addNotificationListener(getId(), listener);
+ }
+ try {
+ doCancel();
+ }
+ catch (Throwable e) {
+ setState(ExternalSystemTaskState.FAILED);
+ myError.set(e);
+ LOG.warn(e);
+ }
+ finally {
+ for (ExternalSystemTaskNotificationListener listener : listeners) {
+ progressManager.removeNotificationListener(listener);
+ }
+ }
+ }
+
+ protected abstract void doCancel() throws Exception;
+
+
@NotNull
protected String wrapProgressText(@NotNull String text) {
return ExternalSystemBundle.message("progress.update.text", getExternalSystemId(), text);
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemExecuteTaskTask.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemExecuteTaskTask.java
index 50f882159eeb..8b5cb63beb04 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemExecuteTaskTask.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemExecuteTaskTask.java
@@ -106,4 +106,18 @@ public class ExternalSystemExecuteTaskTask extends AbstractExternalSystemTask {
setState(ExternalSystemTaskState.FINISHED);
}
}
+
+ @Override
+ protected void doCancel() throws Exception {
+ final ExternalSystemFacadeManager manager = ServiceManager.getService(ExternalSystemFacadeManager.class);
+ RemoteExternalSystemFacade facade = manager.getFacade(getIdeProject(), getExternalProjectPath(), getExternalSystemId());
+ RemoteExternalSystemTaskManager taskManager = facade.getTaskManager();
+ setState(ExternalSystemTaskState.CANCELING);
+ try {
+ taskManager.cancelTask(getId());
+ }
+ finally {
+ setState(ExternalSystemTaskState.CANCELED);
+ }
+ }
}
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemResolveProjectTask.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemResolveProjectTask.java
index 9f7f08da0bbb..fe0d5466dfa2 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemResolveProjectTask.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemResolveProjectTask.java
@@ -62,6 +62,20 @@ public class ExternalSystemResolveProjectTask extends AbstractExternalSystemTask
}
}
+ protected void doCancel() throws Exception {
+ final ExternalSystemFacadeManager manager = ServiceManager.getService(ExternalSystemFacadeManager.class);
+ Project ideProject = getIdeProject();
+ RemoteExternalSystemProjectResolver resolver = manager.getFacade(ideProject, myProjectPath, getExternalSystemId()).getResolver();
+
+ setState(ExternalSystemTaskState.CANCELING);
+ try {
+ resolver.cancelTask(getId());
+ }
+ finally {
+ setState(ExternalSystemTaskState.CANCELED);
+ }
+ }
+
@Nullable
public DataNode<ProjectData> getExternalProject() {
return myExternalProject.get();
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemTaskAware.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemTaskAware.java
index 73947b4f82d1..7ecc0c6028f9 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemTaskAware.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/internal/ExternalSystemTaskAware.java
@@ -27,6 +27,17 @@ public interface ExternalSystemTaskAware {
boolean isTaskInProgress(@NotNull ExternalSystemTaskId id) throws RemoteException;
/**
+ * Allows to cancel the target task by the current service.
+ *
+ *
+ * @param id target task's id
+ * @return <code>true</code> if a task was successfully canceled;
+ * <code>false</code> otherwise
+ * @throws RemoteException as required by RMI
+ */
+ void cancelTask(@NotNull ExternalSystemTaskId id) throws RemoteException;
+
+ /**
* Allows to ask current service for all tasks being executed at the moment.
*
* @return ids of all tasks being executed at the moment grouped by type
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ProjectStructureHelper.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ProjectStructureHelper.java
index 729d16d0d9fc..64d68884e0dc 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ProjectStructureHelper.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/ProjectStructureHelper.java
@@ -23,7 +23,7 @@ import org.jetbrains.annotations.Nullable;
*/
public class ProjectStructureHelper {
- @NotNull private final PlatformFacade myFacade;
+ @NotNull private final PlatformFacade myFacade;
@NotNull private final ExternalLibraryPathTypeMapper myLibraryPathTypeMapper;
public ProjectStructureHelper(@NotNull PlatformFacade facade, @NotNull ExternalLibraryPathTypeMapper mapper) {
@@ -56,10 +56,10 @@ public class ProjectStructureHelper {
* <p/>
* This methods serves as an utility which tries to find a library by it's given base name.
*
- * @param baseName base name of the target library
- * @param ideProject target ide project
- * @return target library for the given base name if there is one and only one library for it;
- * <code>null</code> otherwise (if there are no libraries or more than one library for the given base name)
+ * @param baseName base name of the target library
+ * @param ideProject target ide project
+ * @return target library for the given base name if there is one and only one library for it;
+ * <code>null</code> otherwise (if there are no libraries or more than one library for the given base name)
*/
@Nullable
public Library findIdeLibraryByBaseName(@NotNull String baseName, @NotNull Project ideProject) {
@@ -93,8 +93,7 @@ public class ProjectStructureHelper {
public Library findIdeLibrary(@NotNull String libraryName,
@NotNull OrderRootType jarType,
@NotNull String jarPath,
- @NotNull Project ideProject)
- {
+ @NotNull Project ideProject) {
Library library = findIdeLibrary(libraryName, ideProject);
if (library == null) {
return null;
@@ -110,8 +109,7 @@ public class ProjectStructureHelper {
@Nullable
public LibraryOrderEntry findIdeLibraryDependency(@NotNull final String moduleName,
@NotNull final String libraryName,
- @NotNull Project ideProject)
- {
+ @NotNull Project ideProject) {
final Module ideModule = findIdeModule(moduleName, ideProject);
if (ideModule == null) {
return null;
@@ -137,8 +135,7 @@ public class ProjectStructureHelper {
@Nullable
public ModuleLibraryOrderEntryImpl findIdeModuleLocalLibraryDependency(@NotNull final String moduleName,
@NotNull final String libraryName,
- @NotNull Project ideProject)
- {
+ @NotNull Project ideProject) {
final Module ideModule = findIdeModule(moduleName, ideProject);
if (ideModule == null) {
return null;
@@ -168,8 +165,7 @@ public class ProjectStructureHelper {
@SuppressWarnings("MethodMayBeStatic")
@Nullable
public LibraryOrderEntry findIdeLibraryDependency(@NotNull final String libraryName,
- @NotNull ModifiableRootModel model)
- {
+ @NotNull ModifiableRootModel model) {
for (OrderEntry entry : model.getOrderEntries()) {
if (entry instanceof LibraryOrderEntry) {
LibraryOrderEntry candidate = (LibraryOrderEntry)entry;
@@ -181,46 +177,14 @@ public class ProjectStructureHelper {
return null;
}
- @Nullable
- public ModuleOrderEntry findIdeModuleDependency(@NotNull final ModuleDependencyData gradleDependency, @NotNull Project ideProject) {
- return findIdeModuleDependency(gradleDependency.getOwnerModule().getName(), gradleDependency.getTarget().getName(), ideProject);
- }
-
- @Nullable
- public ModuleOrderEntry findIdeModuleDependency(@NotNull final String ownerModuleName,
- @NotNull final String dependencyModuleName,
- @NotNull Project ideProject)
- {
- final Module ideOwnerModule = findIdeModule(ownerModuleName, ideProject);
- if (ideOwnerModule == null) {
- return null;
- }
-
- RootPolicy<ModuleOrderEntry> visitor = new RootPolicy<ModuleOrderEntry>() {
- @Override
- public ModuleOrderEntry visitModuleOrderEntry(ModuleOrderEntry ideDependency, ModuleOrderEntry value) {
- if (dependencyModuleName.equals(ideDependency.getModuleName())) {
- return ideDependency;
- }
- return value;
- }
- };
- for (OrderEntry orderEntry : myFacade.getOrderEntries(ideOwnerModule)) {
- final ModuleOrderEntry result = orderEntry.accept(visitor, null);
- if (result != null) {
- return result;
- }
- }
- return null;
- }
-
@SuppressWarnings("MethodMayBeStatic")
@Nullable
public ModuleOrderEntry findIdeModuleDependency(@NotNull ModuleDependencyData dependency, @NotNull ModifiableRootModel model) {
for (OrderEntry entry : model.getOrderEntries()) {
if (entry instanceof ModuleOrderEntry) {
ModuleOrderEntry candidate = (ModuleOrderEntry)entry;
- if (dependency.getName().equals(candidate.getModuleName())) {
+ if (dependency.getName().equals(candidate.getModuleName()) &&
+ dependency.getScope().equals(candidate.getScope())) {
return candidate;
}
}
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/AbstractDependencyDataService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/AbstractDependencyDataService.java
index b21561c00068..3defa33fa403 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/AbstractDependencyDataService.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/AbstractDependencyDataService.java
@@ -126,7 +126,15 @@ public abstract class AbstractDependencyDataService<E extends AbstractDependency
// that's why we can't use target dependency object as is but need to get a reference to the current
// entry object from the model instead.
for (OrderEntry entry : moduleRootModel.getOrderEntries()) {
- if (entry.getPresentableName().equals(dependency.getPresentableName())) {
+ if (entry instanceof ExportableOrderEntry) {
+ ExportableOrderEntry orderEntry = (ExportableOrderEntry)entry;
+ if (orderEntry.getPresentableName().equals(dependency.getPresentableName()) &&
+ orderEntry.getScope().equals(dependency.getScope())) {
+ moduleRootModel.removeOrderEntry(entry);
+ break;
+ }
+ }
+ else if (entry.getPresentableName().equals(dependency.getPresentableName())) {
moduleRootModel.removeOrderEntry(entry);
break;
}
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ModuleDependencyDataService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ModuleDependencyDataService.java
index 34130a2ed289..be88a64df782 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ModuleDependencyDataService.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/ModuleDependencyDataService.java
@@ -28,10 +28,8 @@ import com.intellij.openapi.externalSystem.util.ExternalSystemConstants;
import com.intellij.openapi.externalSystem.util.Order;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.ModifiableRootModel;
-import com.intellij.openapi.roots.ModuleOrderEntry;
-import com.intellij.openapi.roots.ModuleRootManager;
-import com.intellij.openapi.roots.OrderEntry;
+import com.intellij.openapi.roots.*;
+import com.intellij.openapi.util.Pair;
import com.intellij.util.BooleanFunction;
import com.intellij.util.containers.ContainerUtilRt;
import org.jetbrains.annotations.NotNull;
@@ -94,11 +92,11 @@ public class ModuleDependencyDataService extends AbstractDependencyDataService<M
@Override
public void run() {
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
- Map<String /* dependency module name */, ModuleOrderEntry> toRemove = ContainerUtilRt.newHashMap();
+ Map<Pair<String /* dependency module name */, /* dependency module scope */DependencyScope> , ModuleOrderEntry> toRemove = ContainerUtilRt.newHashMap();
for (OrderEntry entry : moduleRootManager.getOrderEntries()) {
if (entry instanceof ModuleOrderEntry) {
ModuleOrderEntry e = (ModuleOrderEntry)entry;
- toRemove.put(e.getModuleName(), e);
+ toRemove.put(Pair.create(e.getModuleName(), e.getScope()), e);
}
}
@@ -106,7 +104,7 @@ public class ModuleDependencyDataService extends AbstractDependencyDataService<M
try {
for (DataNode<ModuleDependencyData> dependencyNode : toImport) {
final ModuleDependencyData dependencyData = dependencyNode.getData();
- toRemove.remove(dependencyData.getName());
+ toRemove.remove(Pair.create(dependencyData.getName(), dependencyData.getScope()));
final String moduleName = dependencyData.getName();
Module ideDependencyModule = myProjectStructureHelper.findIdeModule(moduleName, module.getProject());
if (ideDependencyModule == null) {
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemProjectResolver.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemProjectResolver.java
index 558fa5efed1c..2e5ce6469684 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemProjectResolver.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemProjectResolver.java
@@ -20,9 +20,9 @@ import com.intellij.openapi.externalSystem.model.ExternalSystemException;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings;
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId;
+import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener;
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType;
import com.intellij.openapi.externalSystem.service.RemoteExternalSystemService;
-import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -64,6 +64,10 @@ public interface RemoteExternalSystemProjectResolver<S extends ExternalSystemExe
return false;
}
+ @Override
+ public void cancelTask(@NotNull ExternalSystemTaskId id) throws RemoteException {
+ }
+
@NotNull
@Override
public Map<ExternalSystemTaskType, Set<ExternalSystemTaskId>> getTasksInProgress() throws RemoteException {
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemProjectResolverImpl.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemProjectResolverImpl.java
index ef892d295274..2bc337199d88 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemProjectResolverImpl.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemProjectResolverImpl.java
@@ -42,4 +42,11 @@ public class RemoteExternalSystemProjectResolverImpl<S extends ExternalSystemExe
}
});
}
+
+ @Nullable
+ @Override
+ public void cancelTask(@NotNull final ExternalSystemTaskId id)
+ throws ExternalSystemException, IllegalArgumentException, IllegalStateException {
+ // canceling of the project resolving does not support yet
+ }
}
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemTaskManager.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemTaskManager.java
index ff94b6aa6beb..6f9d4e3b596c 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemTaskManager.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemTaskManager.java
@@ -51,6 +51,11 @@ public interface RemoteExternalSystemTaskManager<S extends ExternalSystemExecuti
}
@Override
+ public void cancelTask(@NotNull ExternalSystemTaskId id) throws RemoteException, ExternalSystemException
+ {
+ }
+
+ @Override
public void setSettings(@NotNull ExternalSystemExecutionSettings settings) throws RemoteException {
}
@@ -76,4 +81,6 @@ public interface RemoteExternalSystemTaskManager<S extends ExternalSystemExecuti
@Nullable S settings,
@Nullable String vmOptions,
@Nullable String debuggerSetup) throws RemoteException, ExternalSystemException;
+
+ void cancelTask(@NotNull ExternalSystemTaskId id) throws RemoteException, ExternalSystemException;
}
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemTaskManagerImpl.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemTaskManagerImpl.java
index dec99ec0973e..4e5a45ee915e 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemTaskManagerImpl.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/RemoteExternalSystemTaskManagerImpl.java
@@ -15,10 +15,10 @@
*/
package com.intellij.openapi.externalSystem.service.remote;
-import com.intellij.openapi.externalSystem.task.ExternalSystemTaskManager;
import com.intellij.openapi.externalSystem.model.ExternalSystemException;
import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings;
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId;
+import com.intellij.openapi.externalSystem.task.ExternalSystemTaskManager;
import com.intellij.util.Producer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -57,4 +57,10 @@ public class RemoteExternalSystemTaskManagerImpl<S extends ExternalSystemExecuti
}
});
}
+
+ @Override
+ public void cancelTask(@NotNull final ExternalSystemTaskId id) throws RemoteException, ExternalSystemException
+ {
+ myDelegate.cancelTask(id, getNotificationListener());
+ }
}
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemFacadeWrapper.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemFacadeWrapper.java
index 81ddcdca9405..231bf0697ae7 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemFacadeWrapper.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemFacadeWrapper.java
@@ -1,12 +1,12 @@
package com.intellij.openapi.externalSystem.service.remote.wrapper;
+import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings;
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId;
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType;
import com.intellij.openapi.externalSystem.service.RemoteExternalSystemFacade;
-import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings;
-import com.intellij.openapi.externalSystem.service.remote.RemoteExternalSystemTaskManager;
import com.intellij.openapi.externalSystem.service.remote.RemoteExternalSystemProgressNotificationManager;
import com.intellij.openapi.externalSystem.service.remote.RemoteExternalSystemProjectResolver;
+import com.intellij.openapi.externalSystem.service.remote.RemoteExternalSystemTaskManager;
import org.jetbrains.annotations.NotNull;
import java.rmi.RemoteException;
@@ -72,4 +72,9 @@ public class ExternalSystemFacadeWrapper<S extends ExternalSystemExecutionSettin
public Map<ExternalSystemTaskType, Set<ExternalSystemTaskId>> getTasksInProgress() throws RemoteException {
return myDelegate.getTasksInProgress();
}
+
+ @Override
+ public void cancelTask(@NotNull ExternalSystemTaskId id) throws RemoteException {
+ myDelegate.cancelTask(id);
+ }
}
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemProjectResolverWrapper.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemProjectResolverWrapper.java
index d9bb08cd9ecb..47a7a138ac9a 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemProjectResolverWrapper.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemProjectResolverWrapper.java
@@ -3,11 +3,11 @@ package com.intellij.openapi.externalSystem.service.remote.wrapper;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.ExternalSystemException;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
-import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId;
import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings;
+import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId;
+import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener;
import com.intellij.openapi.externalSystem.service.remote.RemoteExternalSystemProgressNotificationManager;
import com.intellij.openapi.externalSystem.service.remote.RemoteExternalSystemProjectResolver;
-import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -52,4 +52,16 @@ public class ExternalSystemProjectResolverWrapper<S extends ExternalSystemExecut
myProgressManager.onEnd(id);
}
}
+
+ @Override
+ public void cancelTask(@NotNull ExternalSystemTaskId id)
+ throws ExternalSystemException, IllegalArgumentException, IllegalStateException, RemoteException {
+ myProgressManager.onQueued(id);
+ try {
+ getDelegate().cancelTask(id);
+ }
+ finally {
+ myProgressManager.onEnd(id);
+ }
+ }
}
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemTaskManagerWrapper.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemTaskManagerWrapper.java
index 0ff6b38889dc..7cb04bd38d3b 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemTaskManagerWrapper.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/remote/wrapper/ExternalSystemTaskManagerWrapper.java
@@ -60,4 +60,17 @@ public class ExternalSystemTaskManagerWrapper<S extends ExternalSystemExecutionS
myProgressManager.onEnd(id);
}
}
+
+ @Override
+ public void cancelTask(@NotNull ExternalSystemTaskId id) throws RemoteException, ExternalSystemException
+ {
+ myProgressManager.onQueued(id);
+ try {
+ getDelegate().cancelTask(id);
+ }
+ finally {
+ myProgressManager.onEnd(id);
+ }
+ }
}
+
diff --git a/platform/icons/src/actions/findWhite.png b/platform/icons/src/actions/findWhite.png
new file mode 100644
index 000000000000..528960e8803d
--- /dev/null
+++ b/platform/icons/src/actions/findWhite.png
Binary files differ
diff --git a/platform/icons/src/actions/findWhite@2x.png b/platform/icons/src/actions/findWhite@2x.png
new file mode 100644
index 000000000000..b1c125f24eff
--- /dev/null
+++ b/platform/icons/src/actions/findWhite@2x.png
Binary files differ
diff --git a/platform/icons/src/nodes/treeDownArrow.png b/platform/icons/src/nodes/treeDownArrow.png
new file mode 100644
index 000000000000..f10b84def7e2
--- /dev/null
+++ b/platform/icons/src/nodes/treeDownArrow.png
Binary files differ
diff --git a/platform/icons/src/nodes/treeDownArrow@2x.png b/platform/icons/src/nodes/treeDownArrow@2x.png
new file mode 100644
index 000000000000..fa2ad0b87102
--- /dev/null
+++ b/platform/icons/src/nodes/treeDownArrow@2x.png
Binary files differ
diff --git a/platform/icons/src/nodes/treeRightArrow.png b/platform/icons/src/nodes/treeRightArrow.png
new file mode 100644
index 000000000000..1bff9016044d
--- /dev/null
+++ b/platform/icons/src/nodes/treeRightArrow.png
Binary files differ
diff --git a/platform/icons/src/nodes/treeRightArrow@2x.png b/platform/icons/src/nodes/treeRightArrow@2x.png
new file mode 100644
index 000000000000..1b034a9c4444
--- /dev/null
+++ b/platform/icons/src/nodes/treeRightArrow@2x.png
Binary files differ
diff --git a/platform/indexing-api/src/com/intellij/util/indexing/IdFilter.java b/platform/indexing-api/src/com/intellij/util/indexing/IdFilter.java
index 799201064a6f..d402cbf8db72 100644
--- a/platform/indexing-api/src/com/intellij/util/indexing/IdFilter.java
+++ b/platform/indexing-api/src/com/intellij/util/indexing/IdFilter.java
@@ -38,9 +38,9 @@ public abstract class IdFilter {
ContentIterator iterator = new ContentIterator() {
@Override
public boolean processFile(VirtualFile fileOrDir) {
- idSet.set(
- ((VirtualFileWithId)fileOrDir).getId()
- );
+ int id = ((VirtualFileWithId)fileOrDir).getId();
+ if (id < 0) id = -id; // workaround for encountering invalid files, see EA-49915, EA-50599
+ idSet.set(id);
ProgressManager.checkCanceled();
return true;
}
diff --git a/platform/lang-api/src/com/intellij/codeInsight/TailType.java b/platform/lang-api/src/com/intellij/codeInsight/TailType.java
index 18b3bdee5e9a..881726046811 100644
--- a/platform/lang-api/src/com/intellij/codeInsight/TailType.java
+++ b/platform/lang-api/src/com/intellij/codeInsight/TailType.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -26,7 +26,7 @@ import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
-import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NotNull;
/**
@@ -99,7 +99,7 @@ public abstract class TailType {
protected static CommonCodeStyleSettings getLocalCodeStyleSettings(Editor editor, int tailOffset) {
final PsiFile psiFile = getFile(editor);
- Language language = PsiUtilBase.getLanguageAtOffset(psiFile, tailOffset);
+ Language language = PsiUtilCore.getLanguageAtOffset(psiFile, tailOffset);
final Project project = editor.getProject();
assert project != null;
diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionContributor.java b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionContributor.java
index f9e8f09831c7..56e474f74e6f 100644
--- a/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionContributor.java
+++ b/platform/lang-api/src/com/intellij/codeInsight/completion/CompletionContributor.java
@@ -28,7 +28,7 @@ import com.intellij.openapi.util.Pair;
import com.intellij.patterns.ElementPattern;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
-import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.Consumer;
import com.intellij.util.ProcessingContext;
import com.intellij.util.containers.MultiMap;
@@ -237,7 +237,7 @@ public abstract class CompletionContributor {
return ApplicationManager.getApplication().runReadAction(new Computable<List<CompletionContributor>>() {
@Override
public List<CompletionContributor> compute() {
- return forLanguage(PsiUtilBase.getLanguageAtOffset(parameters.getPosition().getContainingFile(), parameters.getOffset()));
+ return forLanguage(PsiUtilCore.getLanguageAtOffset(parameters.getPosition().getContainingFile(), parameters.getOffset()));
}
});
}
diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/InsertionContext.java b/platform/lang-api/src/com/intellij/codeInsight/completion/InsertionContext.java
index f75085af3ec2..cc394daf7645 100644
--- a/platform/lang-api/src/com/intellij/codeInsight/completion/InsertionContext.java
+++ b/platform/lang-api/src/com/intellij/codeInsight/completion/InsertionContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -24,7 +24,7 @@ import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
-import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -138,7 +138,7 @@ public class InsertionContext {
}
public CommonCodeStyleSettings getCodeStyleSettings() {
- Language lang = PsiUtilBase.getLanguageAtOffset(getFile(), getTailOffset());
+ Language lang = PsiUtilCore.getLanguageAtOffset(getFile(), getTailOffset());
return CodeStyleSettingsManager.getSettings(getProject()).getCommonSettings(lang);
}
}
diff --git a/platform/lang-api/src/com/intellij/codeInsight/completion/SkipAutopopupInStrings.java b/platform/lang-api/src/com/intellij/codeInsight/completion/SkipAutopopupInStrings.java
index 8f3714dbda93..437cef2f02f4 100644
--- a/platform/lang-api/src/com/intellij/codeInsight/completion/SkipAutopopupInStrings.java
+++ b/platform/lang-api/src/com/intellij/codeInsight/completion/SkipAutopopupInStrings.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2011 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.
@@ -22,7 +22,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiErrorElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
-import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.ThreeState;
import org.jetbrains.annotations.NotNull;
@@ -47,7 +47,7 @@ public class SkipAutopopupInStrings extends CompletionConfidence {
}
public static boolean isInStringLiteral(PsiElement element) {
- ParserDefinition definition = LanguageParserDefinitions.INSTANCE.forLanguage(PsiUtilBase.findLanguageFromElement(element));
+ ParserDefinition definition = LanguageParserDefinitions.INSTANCE.forLanguage(PsiUtilCore.findLanguageFromElement(element));
if (definition == null) {
return false;
}
diff --git a/platform/lang-api/src/com/intellij/formatting/FormattingDocumentModel.java b/platform/lang-api/src/com/intellij/formatting/FormattingDocumentModel.java
index 8e75e780760b..77397261c4ca 100644
--- a/platform/lang-api/src/com/intellij/formatting/FormattingDocumentModel.java
+++ b/platform/lang-api/src/com/intellij/formatting/FormattingDocumentModel.java
@@ -54,6 +54,7 @@ public interface FormattingDocumentModel {
*/
int getTextLength();
+ @NotNull
Document getDocument();
/**
diff --git a/platform/lang-api/src/com/intellij/framework/FrameworkGroupVersion.java b/platform/lang-api/src/com/intellij/framework/FrameworkGroupVersion.java
deleted file mode 100644
index 6ee7bd7e4529..000000000000
--- a/platform/lang-api/src/com/intellij/framework/FrameworkGroupVersion.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.intellij.framework;
-
-/**
- * @author nik
- */
-public interface FrameworkGroupVersion extends FrameworkVersion {
-}
diff --git a/platform/lang-api/src/com/intellij/framework/FrameworkVersion.java b/platform/lang-api/src/com/intellij/framework/FrameworkVersion.java
index 7f6a45f468d1..e5c37e62dd76 100644
--- a/platform/lang-api/src/com/intellij/framework/FrameworkVersion.java
+++ b/platform/lang-api/src/com/intellij/framework/FrameworkVersion.java
@@ -20,13 +20,10 @@ import org.jetbrains.annotations.NotNull;
/**
* @author nik
*/
-public interface FrameworkVersion {
+public interface FrameworkVersion extends PresentableVersion {
@NotNull
String getId();
@NotNull
- String getPresentableName();
-
- @NotNull
FrameworkAvailabilityCondition getAvailabilityCondition();
}
diff --git a/platform/lang-api/src/com/intellij/framework/PresentableVersion.java b/platform/lang-api/src/com/intellij/framework/PresentableVersion.java
new file mode 100644
index 000000000000..e9e7c854a85e
--- /dev/null
+++ b/platform/lang-api/src/com/intellij/framework/PresentableVersion.java
@@ -0,0 +1,32 @@
+/*
+ * 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.framework;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Dmitry Avdeev
+ * Date: 09.10.13
+ */
+public interface PresentableVersion {
+
+ /** Full version name as presented in combos, like JavaEE 6 */
+ @NotNull
+ String getPresentableName();
+
+ /** Just version number, like 2.2.1 */
+ String getVersionNumber();
+}
diff --git a/platform/lang-api/src/com/intellij/framework/library/FrameworkLibraryVersion.java b/platform/lang-api/src/com/intellij/framework/library/FrameworkLibraryVersion.java
index 75c419ef8232..2ccc6ef99748 100644
--- a/platform/lang-api/src/com/intellij/framework/library/FrameworkLibraryVersion.java
+++ b/platform/lang-api/src/com/intellij/framework/library/FrameworkLibraryVersion.java
@@ -15,6 +15,7 @@
*/
package com.intellij.framework.library;
+import com.intellij.framework.PresentableVersion;
import com.intellij.util.download.DownloadableFileSetDescription;
import org.jetbrains.annotations.NotNull;
@@ -23,7 +24,7 @@ import java.util.List;
/**
* @author nik
*/
-public interface FrameworkLibraryVersion extends DownloadableFileSetDescription {
+public interface FrameworkLibraryVersion extends DownloadableFileSetDescription, PresentableVersion {
@NotNull
String getDefaultLibraryName();
diff --git a/platform/lang-api/src/com/intellij/ide/util/frameworkSupport/FrameworkRole.java b/platform/lang-api/src/com/intellij/ide/util/frameworkSupport/FrameworkRole.java
new file mode 100644
index 000000000000..2331b27c9cae
--- /dev/null
+++ b/platform/lang-api/src/com/intellij/ide/util/frameworkSupport/FrameworkRole.java
@@ -0,0 +1,49 @@
+/*
+ * 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.ide.util.frameworkSupport;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Dmitry Avdeev
+ * Date: 04.10.13
+ */
+public class FrameworkRole {
+
+ public static FrameworkRole[] UNKNOWN = new FrameworkRole[0];
+
+ /** Groovy etc. */
+// public static FrameworkRole JVM_LANGUAGES = new FrameworkRole();
+
+ /** servlet-based frameworks like Struts, Tapestry etc. */
+ public static FrameworkRole JEE_FRAMEWORKS = new FrameworkRole("javaee");
+
+ private final String myId;
+
+ public FrameworkRole(@NotNull String id) {
+ myId = id;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof FrameworkRole && myId.equals(((FrameworkRole)obj).myId);
+ }
+
+ @Override
+ public String toString() {
+ return myId;
+ }
+}
diff --git a/platform/lang-api/src/com/intellij/ide/util/frameworkSupport/FrameworkSupportProvider.java b/platform/lang-api/src/com/intellij/ide/util/frameworkSupport/FrameworkSupportProvider.java
index 770a23cd81ac..59de4af358c9 100644
--- a/platform/lang-api/src/com/intellij/ide/util/frameworkSupport/FrameworkSupportProvider.java
+++ b/platform/lang-api/src/com/intellij/ide/util/frameworkSupport/FrameworkSupportProvider.java
@@ -78,6 +78,10 @@ public abstract class FrameworkSupportProvider {
return getGroupId() == null ? ArrayUtil.EMPTY_STRING_ARRAY : new String[] { getGroupId() };
}
+ public FrameworkRole[] getRoles() {
+ return getGroupId() == null ? FrameworkRole.UNKNOWN : new FrameworkRole[] { new FrameworkRole(getGroupId()) };
+ }
+
@Nullable
public Icon getIcon() {
return null;
diff --git a/platform/lang-api/src/com/intellij/ide/util/projectWizard/ModuleBuilder.java b/platform/lang-api/src/com/intellij/ide/util/projectWizard/ModuleBuilder.java
index ee33ac83ef48..349d3588c435 100644
--- a/platform/lang-api/src/com/intellij/ide/util/projectWizard/ModuleBuilder.java
+++ b/platform/lang-api/src/com/intellij/ide/util/projectWizard/ModuleBuilder.java
@@ -17,6 +17,7 @@ package com.intellij.ide.util.projectWizard;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.highlighter.ModuleFileType;
+import com.intellij.ide.util.frameworkSupport.FrameworkRole;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
@@ -381,6 +382,11 @@ public abstract class ModuleBuilder extends AbstractModuleBuilder {
myAvailableFrameworks = availableFrameworks;
}
+ @NotNull
+ public FrameworkRole getDefaultAcceptableRole() {
+ return getModuleType().getDefaultAcceptableRole();
+ }
+
public static abstract class ModuleConfigurationUpdater {
public abstract void update(@NotNull Module module, @NotNull ModifiableRootModel rootModel);
diff --git a/platform/lang-api/src/com/intellij/openapi/module/ModuleType.java b/platform/lang-api/src/com/intellij/openapi/module/ModuleType.java
index b436bfae7729..3e098021b82e 100644
--- a/platform/lang-api/src/com/intellij/openapi/module/ModuleType.java
+++ b/platform/lang-api/src/com/intellij/openapi/module/ModuleType.java
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.module;
+import com.intellij.ide.util.frameworkSupport.FrameworkRole;
import com.intellij.ide.util.projectWizard.ModuleBuilder;
import com.intellij.ide.util.projectWizard.ModuleWizardStep;
import com.intellij.ide.util.projectWizard.SettingsStep;
@@ -33,9 +34,11 @@ public abstract class ModuleType<T extends ModuleBuilder> {
@NotNull
private final String myId;
+ private final FrameworkRole myFrameworkRole;
protected ModuleType(@NotNull @NonNls String id) {
myId = id;
+ myFrameworkRole = new FrameworkRole(id);
}
@NotNull
@@ -107,4 +110,9 @@ public abstract class ModuleType<T extends ModuleBuilder> {
ModuleTypeManager instance = ModuleTypeManager.getInstance();
return instance == null && ApplicationManager.getApplication().isUnitTestMode() ? EMPTY : instance.findByID(module.getOptionValue(Module.ELEMENT_TYPE));
}
+
+ @NotNull
+ public FrameworkRole getDefaultAcceptableRole() {
+ return myFrameworkRole;
+ }
}
diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java
index b9fcf04069a6..2ba2f35e1b28 100644
--- a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java
+++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.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.
@@ -50,7 +50,8 @@ public class CommonCodeStyleSettings {
private ArrangementSettings myArrangementSettings;
private CodeStyleSettings myRootSettings;
private IndentOptions myIndentOptions;
- private FileType myFileType;
+ private final FileType myFileType;
+ private boolean myForceArrangeMenuAvailable;
@NonNls private static final String INDENT_OPTIONS_TAG = "indentOptions";
@@ -60,10 +61,7 @@ public class CommonCodeStyleSettings {
}
public CommonCodeStyleSettings(Language language) {
- myLanguage = language;
- if (language != null) {
- myFileType = language.getAssociatedFileType();
- }
+ this(language, language == null ? null : language.getAssociatedFileType());
}
void setRootSettings(@NotNull CodeStyleSettings rootSettings) {
@@ -131,11 +129,20 @@ public class CommonCodeStyleSettings {
myArrangementSettings = settings;
}
+ public void setForceArrangeMenuAvailable(boolean value) {
+ myForceArrangeMenuAvailable = value;
+ }
+
+ public boolean isForceArrangeMenuAvailable() {
+ return myForceArrangeMenuAvailable;
+ }
+
@SuppressWarnings("unchecked")
public CommonCodeStyleSettings clone(@NotNull CodeStyleSettings rootSettings) {
CommonCodeStyleSettings commonSettings = new CommonCodeStyleSettings(myLanguage, getFileType());
copyPublicFields(this, commonSettings);
commonSettings.setRootSettings(rootSettings);
+ commonSettings.myForceArrangeMenuAvailable = this.myForceArrangeMenuAvailable;
if (myIndentOptions != null) {
IndentOptions targetIndentOptions = commonSettings.initIndentOptions();
targetIndentOptions.copyFrom(myIndentOptions);
@@ -225,6 +232,7 @@ public class CommonCodeStyleSettings {
Set<String> supportedFields = getSupportedFields();
if (supportedFields != null) {
supportedFields.add("PARENT_SETTINGS_INSTALLED");
+ supportedFields.add("FORCE_REARRANGE_MODE");
}
DefaultJDOMExternalizer.writeExternal(this, element, new SupportedFieldsDiffFilter(this, supportedFields, defaultSettings));
if (myIndentOptions != null) {
@@ -916,6 +924,14 @@ public class CommonCodeStyleSettings {
//
public boolean PARENT_SETTINGS_INSTALLED = false;
+ //-------------------------Force rearrange settings---------------------------------------
+ public static int REARRANGE_ACCORDIND_TO_DIALOG = 0;
+ public static int REARRANGE_ALWAYS = 1;
+ public static int REARRANGE_NEVER = 2;
+
+ public int FORCE_REARRANGE_MODE = REARRANGE_ACCORDIND_TO_DIALOG;
+
+
//-------------------------Indent options-------------------------------------------------
public static class IndentOptions implements JDOMExternalizable, Cloneable {
public int INDENT_SIZE = 4;
diff --git a/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java b/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java
index f5b10ccf1b20..04c4b63b5084 100644
--- a/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java
+++ b/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java
@@ -73,31 +73,6 @@ public class PsiUtilBase extends PsiUtilCore {
throw new RuntimeException("Cannot find root for: "+root);
}
- @NotNull
- public static Language getLanguageAtOffset (@NotNull PsiFile file, int offset) {
- final PsiElement elt = file.findElementAt(offset);
- if (elt == null) return file.getLanguage();
- if (elt instanceof PsiWhiteSpace) {
- final int decremented = elt.getTextRange().getStartOffset() - 1;
- if (decremented >= 0) {
- return getLanguageAtOffset(file, decremented);
- }
- }
- return findLanguageFromElement(elt);
- }
-
- @NotNull
- public static Language findLanguageFromElement(final PsiElement elt) {
- if (elt.getFirstChild() == null) { //is leaf
- final PsiElement parent = elt.getParent();
- if (parent != null) {
- return parent.getLanguage();
- }
- }
-
- return elt.getLanguage();
- }
-
public static boolean isUnderPsiRoot(PsiFile root, PsiElement element) {
PsiFile containingFile = element.getContainingFile();
if (containingFile == root) return true;
diff --git a/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.form b/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.form
index 72d2e4e399f7..38d72c46c3cb 100644
--- a/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.form
+++ b/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.form
@@ -71,7 +71,7 @@
<border type="none" title="Default Indent Options"/>
<children/>
</grid>
- <grid id="f6e61" layout-manager="GridLayoutManager" row-count="4" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <grid id="f6e61" layout-manager="GridLayoutManager" row-count="2" 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="4" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
@@ -82,54 +82,78 @@
</clientProperties>
<border type="none" title-resource-bundle="messages/ApplicationBundle" title-key="settings.code.style.general.formatter.control"/>
<children>
- <component id="1afd0" class="com.intellij.ui.components.JBLabel">
+ <component id="3b152" class="javax.swing.JCheckBox" binding="myEnableFormatterTags">
<constraints>
- <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ <grid row="0" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
- <text resource-bundle="messages/ApplicationBundle" key="settings.code.style.general.formatter.off.tag"/>
+ <text resource-bundle="messages/ApplicationBundle" key="settings.code.style.general.enable.formatter.tags"/>
</properties>
</component>
- <component id="a4d" class="javax.swing.JTextField" binding="myFormatterOffTagField">
+ <grid id="3e0c8" binding="myMarkersPanel" layout-manager="GridLayoutManager" row-count="3" 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="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
- <preferred-size width="150" height="-1"/>
- </grid>
+ <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
- </component>
- <component id="66f0a" class="javax.swing.JTextField" binding="myFormatterOnTagField">
- <constraints>
- <grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
- <preferred-size width="150" height="-1"/>
+ <border type="none" title="Markers:"/>
+ <children>
+ <component id="1afd0" class="com.intellij.ui.components.JBLabel" binding="myFormatterOffLabel">
+ <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>
+ <labelFor value="a4d"/>
+ <text resource-bundle="messages/ApplicationBundle" key="settings.code.style.general.formatter.off.tag"/>
+ </properties>
+ </component>
+ <component id="96c9" class="com.intellij.ui.components.JBLabel" binding="myFormatterOnLabel">
+ <constraints>
+ <grid row="1" 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>
+ <labelFor value="66f0a"/>
+ <text resource-bundle="messages/ApplicationBundle" key="settings.code.style.general.formatter.on.tag"/>
+ </properties>
+ </component>
+ <component id="66f0a" class="javax.swing.JTextField" binding="myFormatterOnTagField">
+ <constraints>
+ <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
+ <preferred-size width="150" height="-1"/>
+ </grid>
+ </constraints>
+ <properties/>
+ </component>
+ <component id="a4d" class="javax.swing.JTextField" binding="myFormatterOffTagField">
+ <constraints>
+ <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
+ <preferred-size width="150" height="-1"/>
+ </grid>
+ </constraints>
+ <properties/>
+ </component>
+ <grid id="8023a" binding="myMarkerOptionsPanel" 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="2" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties/>
+ <border type="empty">
+ <font/>
+ </border>
+ <children>
+ <component id="f7481" class="javax.swing.JCheckBox" binding="myAcceptRegularExpressionsCheckBox">
+ <constraints>
+ <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <text resource-bundle="messages/ApplicationBundle" key="settings.code.style.general.formatter.marker.regexp"/>
+ </properties>
+ </component>
+ </children>
</grid>
- </constraints>
- <properties/>
- </component>
- <component id="96c9" class="com.intellij.ui.components.JBLabel">
- <constraints>
- <grid row="3" 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 resource-bundle="messages/ApplicationBundle" key="settings.code.style.general.formatter.on.tag"/>
- </properties>
- </component>
- <component id="f7481" class="javax.swing.JCheckBox" binding="myAcceptRegularExpressionsCheckBox">
- <constraints>
- <grid row="1" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
- </constraints>
- <properties>
- <text resource-bundle="messages/ApplicationBundle" key="settings.code.style.general.formatter.marker.regexp"/>
- </properties>
- </component>
- <component id="3b152" class="javax.swing.JCheckBox" binding="myEnableFormatterTags">
- <constraints>
- <grid row="0" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
- </constraints>
- <properties>
- <text resource-bundle="messages/ApplicationBundle" key="settings.code.style.general.enable.formatter.tags"/>
- </properties>
- </component>
+ </children>
+ </grid>
</children>
</grid>
</children>
diff --git a/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.java b/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.java
index c434c670823d..844b1ccbc1ba 100644
--- a/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.java
+++ b/platform/lang-impl/src/com/intellij/application/options/GeneralCodeStylePanel.java
@@ -39,7 +39,9 @@ import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.DisplayPriority;
import com.intellij.psi.codeStyle.FileTypeIndentOptionsProvider;
import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
+import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.awt.RelativePoint;
+import com.intellij.ui.components.JBLabel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -73,6 +75,10 @@ public class GeneralCodeStylePanel extends CodeStyleAbstractPanel {
private JTextField myFormatterOnTagField;
private JTextField myFormatterOffTagField;
private JCheckBox myAcceptRegularExpressionsCheckBox;
+ private JPanel myMarkersPanel;
+ private JBLabel myFormatterOffLabel;
+ private JBLabel myFormatterOnLabel;
+ private JPanel myMarkerOptionsPanel;
private final SmartIndentOptionsEditor myIndentOptionsEditor;
@@ -112,11 +118,14 @@ public class GeneralCodeStylePanel extends CodeStyleAbstractPanel {
@Override
public void actionPerformed(ActionEvent e) {
boolean tagsEnabled = myEnableFormatterTags.isSelected();
- myAcceptRegularExpressionsCheckBox.setEnabled(tagsEnabled);
- myFormatterOnTagField.setEnabled(tagsEnabled);
- myFormatterOffTagField.setEnabled(tagsEnabled);
+ setFormatterTagControlsEnabled(tagsEnabled);
}
});
+
+ myMarkersPanel.setBorder(IdeBorderFactory.createTitledBorder(
+ ApplicationBundle.message("settings.code.style.general.formatter.marker.title"), true));
+ myMarkerOptionsPanel.setBorder(
+ IdeBorderFactory.createTitledBorder(ApplicationBundle.message("settings.code.style.general.formatter.marker.options.title"), true));
}
@Nullable
@@ -258,14 +267,22 @@ public class GeneralCodeStylePanel extends CodeStyleAbstractPanel {
myIndentOptionsEditor.setEnabled(true);
myAcceptRegularExpressionsCheckBox.setSelected(settings.FORMATTER_TAGS_ACCEPT_REGEXP);
- myAcceptRegularExpressionsCheckBox.setEnabled(settings.FORMATTER_TAGS_ENABLED);
myEnableFormatterTags.setSelected(settings.FORMATTER_TAGS_ENABLED);
myFormatterOnTagField.setText(settings.FORMATTER_ON_TAG);
- myFormatterOnTagField.setEnabled(settings.FORMATTER_TAGS_ENABLED);
-
myFormatterOffTagField.setText(settings.FORMATTER_OFF_TAG);
- myFormatterOffTagField.setEnabled(settings.FORMATTER_TAGS_ENABLED);
+
+ setFormatterTagControlsEnabled(settings.FORMATTER_TAGS_ENABLED);
+ }
+
+ private void setFormatterTagControlsEnabled(boolean isEnabled) {
+ myFormatterOffTagField.setEnabled(isEnabled);
+ myFormatterOnTagField.setEnabled(isEnabled);
+ myMarkersPanel.setEnabled(isEnabled);
+ myAcceptRegularExpressionsCheckBox.setEnabled(isEnabled);
+ myFormatterOffLabel.setEnabled(isEnabled);
+ myFormatterOnLabel.setEnabled(isEnabled);
+ myMarkerOptionsPanel.setEnabled(isEnabled);
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java
index 969496745694..a6231d2f26fe 100644
--- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java
+++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java
@@ -17,6 +17,7 @@ package com.intellij.application.options.codeStyle.arrangement;
import com.intellij.application.options.CodeStyleAbstractPanel;
import com.intellij.application.options.codeStyle.arrangement.action.RemoveArrangementRuleAction;
+import com.intellij.application.options.codeStyle.arrangement.additional.ForceArrangementPanel;
import com.intellij.application.options.codeStyle.arrangement.color.ArrangementColorsProvider;
import com.intellij.application.options.codeStyle.arrangement.color.ArrangementColorsProviderImpl;
import com.intellij.application.options.codeStyle.arrangement.group.ArrangementGroupingRulesPanel;
@@ -45,6 +46,7 @@ import java.awt.*;
import java.util.ArrayList;
import java.util.List;
+
/**
* @author Denis Zhdanov
* @since 10/30/12 5:17 PM
@@ -57,6 +59,7 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel {
@NotNull private final ArrangementStandardSettingsAware mySettingsAware;
@NotNull private final ArrangementGroupingRulesPanel myGroupingRulesPanel;
@NotNull private final ArrangementMatchingRulesPanel myMatchingRulesPanel;
+ @Nullable private final ForceArrangementPanel myForceArrangementPanel;
public ArrangementSettingsPanel(@NotNull CodeStyleSettings settings, @NotNull Language language) {
super(settings);
@@ -80,7 +83,18 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel {
myMatchingRulesPanel = new ArrangementMatchingRulesPanel(settingsManager, colorsProvider);
myContent.add(myGroupingRulesPanel, new GridBag().coverLine().fillCellHorizontally().weightx(1));
- myContent.add(myMatchingRulesPanel, new GridBag().fillCell().weightx(1).weighty(1));
+ myContent.add(myMatchingRulesPanel, new GridBag().fillCell().weightx(1).weighty(1).coverLine());
+
+
+
+ if (settings.getCommonSettings(myLanguage).isForceArrangeMenuAvailable()) {
+ myForceArrangementPanel = new ForceArrangementPanel();
+ myForceArrangementPanel.setSelectedMode(settings.getCommonSettings(language).FORCE_REARRANGE_MODE);
+ myContent.add(myForceArrangementPanel.getPanel(), new GridBag().anchor(GridBagConstraints.WEST).coverLine().fillCellHorizontally());
+ }
+ else {
+ myForceArrangementPanel = null;
+ }
final List<CompositeArrangementSettingsToken> groupingTokens = settingsManager.getSupportedGroupingTokens();
myGroupingRulesPanel.setVisible(groupingTokens != null && !groupingTokens.isEmpty());
@@ -117,12 +131,16 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel {
public void apply(CodeStyleSettings settings) {
CommonCodeStyleSettings commonSettings = settings.getCommonSettings(myLanguage);
commonSettings.setArrangementSettings(new StdRulePriorityAwareSettings(myGroupingRulesPanel.getRules(), myMatchingRulesPanel.getRules()));
+ if (myForceArrangementPanel != null) {
+ commonSettings.FORCE_REARRANGE_MODE = myForceArrangementPanel.getRearrangeMode();
+ }
}
@Override
public boolean isModified(CodeStyleSettings settings) {
StdArrangementSettings s = new StdRulePriorityAwareSettings(myGroupingRulesPanel.getRules(), myMatchingRulesPanel.getRules());
- return !Comparing.equal(getSettings(settings), s);
+ return !Comparing.equal(getSettings(settings), s)
+ || myForceArrangementPanel != null && settings.getCommonSettings(myLanguage).FORCE_REARRANGE_MODE != myForceArrangementPanel.getRearrangeMode();
}
@Override
@@ -138,6 +156,9 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel {
myGroupingRulesPanel.setRules(ContainerUtilRt.newArrayList(groupings));
}
myMatchingRulesPanel.setRules(copy(s.getRules()));
+ if (myForceArrangementPanel != null) {
+ myForceArrangementPanel.setSelectedMode(settings.getCommonSettings(myLanguage).FORCE_REARRANGE_MODE);
+ }
}
}
diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/additional/ForceArrangementPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/additional/ForceArrangementPanel.java
new file mode 100644
index 000000000000..9524bb28417f
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/additional/ForceArrangementPanel.java
@@ -0,0 +1,103 @@
+/*
+ * 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.application.options.codeStyle.arrangement.additional;
+
+import com.intellij.openapi.application.ApplicationBundle;
+import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
+import com.intellij.ui.EnumComboBoxModel;
+import com.intellij.ui.OptionGroup;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class ForceArrangementPanel {
+
+ @NotNull private final JComboBox myForceRearrangeComboBox;
+ @NotNull private final JPanel myPanel;
+
+ public ForceArrangementPanel() {
+ myForceRearrangeComboBox = new JComboBox();
+ myForceRearrangeComboBox.setModel(new EnumComboBoxModel<SelectedMode>(SelectedMode.class));
+ myForceRearrangeComboBox.setMaximumSize(myForceRearrangeComboBox.getPreferredSize());
+ myPanel = createPanel();
+ }
+
+ public int getRearrangeMode() {
+ return getSelectedMode().rearrangeMode;
+ }
+
+ public void setSelectedMode(@NotNull SelectedMode mode) {
+ myForceRearrangeComboBox.setSelectedItem(mode);
+ }
+
+ public void setSelectedMode(int mode) {
+ SelectedMode toSetUp = SelectedMode.getByMode(mode);
+ assert(toSetUp != null);
+ setSelectedMode(toSetUp);
+ }
+
+ @NotNull
+ public JPanel getPanel() {
+ return myPanel;
+ }
+
+ @NotNull
+ private JPanel createPanel() {
+ OptionGroup group = new OptionGroup(ApplicationBundle.message("arrangement.settings.additional.title"));
+ JPanel textWithComboPanel = new JPanel();
+ textWithComboPanel.setLayout(new BoxLayout(textWithComboPanel, BoxLayout.LINE_AXIS));
+ textWithComboPanel.add(new JLabel(ApplicationBundle.message("arrangement.settings.additional.force.combobox.name")));
+ textWithComboPanel.add(Box.createRigidArea(new Dimension(5, 0)));
+ textWithComboPanel.add(myForceRearrangeComboBox);
+ group.add(textWithComboPanel);
+ return group.createPanel();
+ }
+
+ @NotNull
+ private SelectedMode getSelectedMode() {
+ return (SelectedMode)myForceRearrangeComboBox.getSelectedItem();
+ }
+
+ private enum SelectedMode {
+ FROM_DIALOG(ApplicationBundle.message("arrangement.settings.additional.force.rearrange.according.to.dialog"), CommonCodeStyleSettings.REARRANGE_ACCORDIND_TO_DIALOG),
+ ALWAYS(ApplicationBundle.message("arrangement.settings.additional.force.rearrange.always"), CommonCodeStyleSettings.REARRANGE_ALWAYS),
+ NEVER(ApplicationBundle.message("arrangement.settings.additional.force.rearrange.never"), CommonCodeStyleSettings.REARRANGE_NEVER);
+
+ public final int rearrangeMode;
+ @NotNull private final String myName;
+
+ SelectedMode(@NotNull String name, int mode) {
+ myName = name;
+ rearrangeMode = mode;
+ }
+
+ @Nullable
+ private static SelectedMode getByMode(int mode) {
+ for (SelectedMode currentMode: values()) {
+ if (currentMode.rearrangeMode == mode) return currentMode;
+ }
+ return null;
+ }
+
+ @Override
+ @NotNull
+ public String toString() {
+ return myName;
+ }
+ }
+}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.java
index 3914ce6e7e31..45862ed4e7ba 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/LayoutCodeDialog.java
@@ -26,6 +26,8 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
+import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
+import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.codeStyle.arrangement.Rearranger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -38,9 +40,10 @@ import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
public class LayoutCodeDialog extends DialogWrapper {
- private final PsiFile myFile;
+ @NotNull private final Project myProject;
+ @Nullable private final PsiFile myFile;
@Nullable private final PsiDirectory myDirectory;
- private final Boolean myTextSelected;
+ private final Boolean myTextSelected;
private JRadioButton myRbFile;
private JRadioButton myRbSelectedText;
@@ -52,6 +55,10 @@ public class LayoutCodeDialog extends DialogWrapper {
private JCheckBox myDoNotAskMeCheckBox;
private final String myHelpId;
+ @NotNull private String myRearrangeEntriesKeyForLanguage;
+ @Nullable private CommonCodeStyleSettings myCommonSettings;
+ private boolean myForceArrangeModeEnabled;
+
public LayoutCodeDialog(@NotNull Project project,
@NotNull String title,
@@ -61,9 +68,16 @@ public class LayoutCodeDialog extends DialogWrapper {
final String helpId) {
super(project, true);
myFile = file;
+ myProject = project;
myDirectory = directory;
myTextSelected = isTextSelected;
+ if (myFile != null) myCommonSettings = CodeStyleSettingsManager.getSettings(myProject).getCommonSettings(myFile.getLanguage());
+ myForceArrangeModeEnabled = myCommonSettings != null
+ && myCommonSettings.isForceArrangeMenuAvailable()
+ && myCommonSettings.FORCE_REARRANGE_MODE != CommonCodeStyleSettings.REARRANGE_ACCORDIND_TO_DIALOG;
+
+ myRearrangeEntriesKeyForLanguage = LayoutCodeConstants.REARRANGE_ENTRIES_KEY + (myFile == null ? "" : myFile.getLanguage().getDisplayName());
setOKButtonText(CodeInsightBundle.message("reformat.code.accept.button.text"));
setTitle(title);
init();
@@ -89,7 +103,9 @@ public class LayoutCodeDialog extends DialogWrapper {
myCbIncludeSubdirs.setSelected(true);
//Loading previous state
myCbOptimizeImports.setSelected(PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, false));
- myCbArrangeEntries.setSelected(PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.REARRANGE_ENTRIES_KEY, false));
+ myCbArrangeEntries.setSelected(myForceArrangeModeEnabled ? myCommonSettings.FORCE_REARRANGE_MODE == CommonCodeStyleSettings.REARRANGE_ALWAYS
+ : PropertiesComponent.getInstance(myProject).getBoolean(myRearrangeEntriesKeyForLanguage, false));
+
myCbOnlyVcsChangedRegions.setSelected(PropertiesComponent.getInstance().getBoolean(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, false));
ItemListener listener = new ItemListener() {
@@ -114,6 +130,7 @@ public class LayoutCodeDialog extends DialogWrapper {
);
myCbArrangeEntries.setEnabled(myFile != null
&& Rearranger.EXTENSION.forLanguage(myFile.getLanguage()) != null
+ && !myForceArrangeModeEnabled
);
myCbOnlyVcsChangedRegions.setEnabled(canTargetVcsRegions());
@@ -257,7 +274,7 @@ public class LayoutCodeDialog extends DialogWrapper {
super.doOKAction();
//Saving checkboxes state
PropertiesComponent.getInstance().setValue(LayoutCodeConstants.OPTIMIZE_IMPORTS_KEY, Boolean.toString(myCbOptimizeImports.isSelected()));
- PropertiesComponent.getInstance().setValue(LayoutCodeConstants.REARRANGE_ENTRIES_KEY, Boolean.toString(myCbArrangeEntries.isSelected()));
+ PropertiesComponent.getInstance(myProject).setValue(myRearrangeEntriesKeyForLanguage, Boolean.toString(myCbArrangeEntries.isSelected()));
PropertiesComponent.getInstance().setValue(LayoutCodeConstants.PROCESS_CHANGED_TEXT_KEY, Boolean.toString(myCbOnlyVcsChangedRegions.isSelected()));
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java
index 8f87b887fb8f..c5c5d6fe1737 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -43,9 +43,11 @@ import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.*;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
@@ -56,6 +58,7 @@ import com.intellij.psi.impl.source.PostprocessReformattingAspect;
import com.intellij.psi.impl.source.PsiFileImpl;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import com.intellij.reference.SoftReference;
import com.intellij.util.ThreeState;
import com.intellij.util.concurrency.Semaphore;
@@ -231,7 +234,7 @@ public class CodeCompletionHandlerBase {
}
if (elementAt == null) return true;
- Language language = PsiUtilBase.findLanguageFromElement(elementAt);
+ Language language = PsiUtilCore.findLanguageFromElement(elementAt);
for (CompletionConfidence confidence : CompletionConfidenceEP.forLanguage(language)) {
final ThreeState result = confidence.shouldSkipAutopopup(elementAt, psiFile, offset);
@@ -759,7 +762,7 @@ public class CodeCompletionHandlerBase {
private static PsiFile createFileCopy(PsiFile file) {
final VirtualFile virtualFile = file.getVirtualFile();
- if (file.isPhysical() && virtualFile != null && virtualFile.getFileSystem() == LocalFileSystem.getInstance()
+ if (file.isPhysical() && virtualFile != null && virtualFile.isInLocalFileSystem()
// must not cache injected file copy, since it does not reflect changes in host document
&& !InjectedLanguageManager.getInstance(file.getProject()).isInjectedFragment(file)) {
final SoftReference<Pair<PsiFile, Document>> reference = file.getUserData(FILE_COPY_KEY);
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java
index 91d89b2217a5..899a6017f6c7 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -56,7 +56,7 @@ import com.intellij.patterns.ElementPattern;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.psi.ReferenceRange;
-import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.LightweightHint;
import com.intellij.util.Alarm;
import com.intellij.util.ObjectUtils;
@@ -716,7 +716,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
return false;
}
- final Language language = PsiUtilBase.getLanguageAtOffset(parameters.getPosition().getContainingFile(), parameters.getOffset());
+ final Language language = PsiUtilCore.getLanguageAtOffset(parameters.getPosition().getContainingFile(), parameters.getOffset());
for (CompletionConfidence confidence : CompletionConfidenceEP.forLanguage(language)) {
final ThreeState result = confidence.shouldFocusLookup(parameters);
if (result != ThreeState.UNSURE) {
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java
index ea045464221e..ee3a195ae8fa 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java
@@ -143,7 +143,7 @@ public class CamelHumpMatcher extends PrefixMatcher {
int matchStart = ranges.get(0).getStartOffset();
int underscoreEnd = skipUnderscores(string);
if (matchStart > 0 && matchStart <= underscoreEnd) {
- return myMatcher.matchingDegree(string.substring(matchStart)) - 1;
+ return myCaseInsensitiveMatcher.matchingDegree(string.substring(matchStart)) - 1;
}
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonEditorPopup.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonEditorPopup.java
index d788f8537548..2566e2279aff 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonEditorPopup.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonEditorPopup.java
@@ -21,8 +21,11 @@ package com.intellij.codeInsight.daemon.impl;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings;
+import com.intellij.ide.IdeBundle;
+import com.intellij.ide.ui.UISettings;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.EditorBundle;
+import com.intellij.openapi.ui.JBCheckboxMenuItem;
import com.intellij.openapi.ui.JBMenuItem;
import com.intellij.openapi.ui.JBPopupMenu;
import com.intellij.psi.PsiFile;
@@ -86,6 +89,18 @@ public class DaemonEditorPopup extends PopupHandler {
component.showComponent(new RelativePoint(comp, new Point(point.x - dimension.width, point.y)));
}
});
+
+ final JBCheckboxMenuItem previewCheckbox = new JBCheckboxMenuItem(IdeBundle.message("checkbox.show.editor.preview.popup"), UISettings.getInstance().SHOW_EDITOR_TOOLTIP);
+ popupMenu.addSeparator();
+ popupMenu.add(previewCheckbox);
+ previewCheckbox.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ UISettings.getInstance().SHOW_EDITOR_TOOLTIP = previewCheckbox.isSelected();
+ UISettings.getInstance().fireUISettingsChanged();
+ }
+ });
+
PsiFile file = myPsiFile;
if (file != null && DaemonCodeAnalyzer.getInstance(myPsiFile.getProject()).isHighlightingAvailable(file)) {
popupMenu.show(comp, x, y);
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java
index 5de93879636a..aec61188112f 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java
@@ -703,6 +703,10 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass
if (toolWrapper instanceof LocalInspectionToolWrapper) {
wrapper = (LocalInspectionToolWrapper)toolWrapper;
}
+ else if (toolWrapper instanceof GlobalInspectionToolWrapper) {
+ final GlobalInspectionToolWrapper globalInspectionToolWrapper = (GlobalInspectionToolWrapper)toolWrapper;
+ wrapper = globalInspectionToolWrapper.getSharedLocalInspectionToolWrapper();
+ }
if (wrapper == null) continue;
if (myIgnoreSuppressed) {
if (wrapper.isApplicable(language) && SuppressionUtil.inspectionResultSuppressed(myFile, wrapper.getTool())) {
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java
index f9488aad2794..22e3b55f58a0 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -19,7 +19,6 @@ package com.intellij.codeInsight.daemon.impl;
import com.intellij.codeHighlighting.HighlightingPass;
import com.intellij.codeHighlighting.TextEditorHighlightingPass;
import com.intellij.concurrency.Job;
-import com.intellij.concurrency.JobImpl;
import com.intellij.concurrency.JobLauncher;
import com.intellij.injected.editor.EditorWindow;
import com.intellij.openapi.Disposable;
@@ -47,7 +46,6 @@ import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.TestOnly;
import java.util.*;
import java.util.concurrent.*;
@@ -79,17 +77,17 @@ public abstract class PassExecutorService implements Disposable {
submittedPass.cancel();
}
if (waitForTermination) {
- for (Job<Void> job : mySubmittedPasses.values()) {
- try {
- if (job instanceof JobImpl) {
- JobImpl ji = (JobImpl)job;
- if (!job.isDone()) ji.waitForTermination();
- }
- }
- catch (Throwable throwable) {
- LOG.error(throwable);
+ try {
+ while (!waitFor(50)) {
+ int i = 0;
}
}
+ catch (ProcessCanceledException ignored) {
+
+ }
+ catch (Throwable throwable) {
+ LOG.error(throwable);
+ }
}
mySubmittedPasses.clear();
}
@@ -360,7 +358,9 @@ public abstract class PassExecutorService implements Disposable {
catch (ProcessCanceledException e) {
log(myUpdateProgress, myPass, "Canceled ");
- myUpdateProgress.cancel(e); //in case when some smart asses throw PCE just for fun
+ if (!myUpdateProgress.isCanceled()) {
+ myUpdateProgress.cancel(e); //in case when some smart asses throw PCE just for fun
+ }
}
catch (RuntimeException e) {
myUpdateProgress.cancel(e);
@@ -518,20 +518,23 @@ public abstract class PassExecutorService implements Disposable {
return indicator.getUserData(THROWABLE_KEY);
}
- @TestOnly
- public void waitFor(int millis) throws Exception {
+ // return true if terminated
+ public boolean waitFor(int millis) throws Throwable {
ApplicationManager.getApplication().assertIsDispatchThread();
try {
for (Job<Void> job : mySubmittedPasses.values()) {
- if (!job.isDone()) {
- for (FutureTask task : ((JobImpl)job).getTasks()) {
- task.get(millis, TimeUnit.MILLISECONDS);
- }
- }
+ job.waitForCompletion(millis);
}
+ return true;
}
catch (TimeoutException ignored) {
-
+ return false;
+ }
+ catch (InterruptedException e) {
+ return true;
+ }
+ catch (ExecutionException e) {
+ throw e.getCause();
}
}
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/AutoHardWrapHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/AutoHardWrapHandler.java
index 341c1447409e..4c24ff5ce156 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/AutoHardWrapHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/AutoHardWrapHandler.java
@@ -108,8 +108,9 @@ public class AutoHardWrapHandler {
int line = document.getLineNumber(caretOffset);
int startOffset = document.getLineStartOffset(line);
int endOffset = document.getLineEndOffset(line);
- final String endOfString = document.getText().substring(caretOffset, endOffset);
- final boolean endsWithSpaces = StringUtil.isEmptyOrSpaces(endOfString);
+
+ final CharSequence endOfString = document.getCharsSequence().subSequence(caretOffset, endOffset);
+ final boolean endsWithSpaces = StringUtil.isEmptyOrSpaces(String.valueOf(endOfString));
// Check if right margin is exceeded.
int margin = editor.getSettings().getRightMargin(project);
if (margin <= 0) {
@@ -185,14 +186,16 @@ public class AutoHardWrapHandler {
caretOffsetDiff[0] += event.getNewLength() - event.getOldLength();
}
- if (event.getNewLength() <= event.getOldLength() && endsWithSpaces) {
- // There is a possible case that document fragment is removed because of auto-formatting.
- // We don't want to process such events in case of current string ends with spaces.
+ if (autoFormatted(event)) {
return;
}
wrapIntroducedSymbolsNumber[0] += event.getNewLength() - event.getOldLength();
}
+ private boolean autoFormatted(DocumentEvent event) {
+ return event.getNewLength() <= event.getOldLength() && endsWithSpaces;
+ }
+
@Override
public void documentChanged(DocumentEvent event) {
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CodeDocumentationUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CodeDocumentationUtil.java
index 85a84021e5a0..bcb6196c9434 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CodeDocumentationUtil.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CodeDocumentationUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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,7 +23,7 @@ import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
-import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -96,7 +96,7 @@ public class CodeDocumentationUtil {
*/
@NotNull
public static CommentContext tryParseCommentContext(@NotNull PsiFile file, @NotNull CharSequence chars, int offset, int lineStartOffset) {
- Commenter langCommenter = LanguageCommenters.INSTANCE.forLanguage(PsiUtilBase.getLanguageAtOffset(file, offset));
+ Commenter langCommenter = LanguageCommenters.INSTANCE.forLanguage(PsiUtilCore.getLanguageAtOffset(file, offset));
final boolean isInsideCommentLikeCode = langCommenter instanceof CodeDocumentationAwareCommenter;
if (!isInsideCommentLikeCode) {
return new CommentContext();
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java
index c12a0dde63e9..58a0c772da8a 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/FixDocCommentAction.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.
@@ -33,7 +33,7 @@ import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
-import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -79,7 +79,7 @@ public class FixDocCommentAction extends EditorAction {
return;
}
- Language language = PsiUtilBase.getLanguageAtOffset(file, offset);
+ Language language = PsiUtilCore.getLanguageAtOffset(file, offset);
final CodeDocumentationProvider docProvider;
final DocumentationProvider langDocumentationProvider = LanguageDocumentation.INSTANCE.forLanguage(language);
if (langDocumentationProvider instanceof CompositeDocumentationProvider) {
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/SelectWordUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/SelectWordUtil.java
index 642069f0d918..c6e5851857ba 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/SelectWordUtil.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/SelectWordUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -39,7 +39,6 @@ import java.util.List;
* @author Mike
*/
public class SelectWordUtil {
-
private static ExtendWordSelectionHandler[] SELECTIONERS = new ExtendWordSelectionHandler[]{
};
@@ -66,38 +65,53 @@ public class SelectWordUtil {
return SELECTIONERS;
}
+ private static final CharCondition JAVA_IDENTIFIER_PART_CONDITION = new CharCondition() {
+ @Override
+ public boolean value(char ch) {
+ return Character.isJavaIdentifierPart(ch);
+ }
+ };
+
public static void addWordSelection(boolean camel, CharSequence editorText, int cursorOffset, @NotNull List<TextRange> ranges) {
- TextRange camelRange = camel ? getCamelSelectionRange(editorText, cursorOffset) : null;
+ addWordSelection(camel, editorText, cursorOffset, ranges, JAVA_IDENTIFIER_PART_CONDITION);
+ }
+
+ public static void addWordSelection(boolean camel,
+ CharSequence editorText,
+ int cursorOffset,
+ @NotNull List<TextRange> ranges,
+ CharCondition isWordPartCondition) {
+ TextRange camelRange = camel ? getCamelSelectionRange(editorText, cursorOffset, isWordPartCondition) : null;
if (camelRange != null) {
ranges.add(camelRange);
}
- TextRange range = getWordSelectionRange(editorText, cursorOffset);
+ TextRange range = getWordSelectionRange(editorText, cursorOffset, isWordPartCondition);
if (range != null && !range.equals(camelRange)) {
ranges.add(range);
}
}
@Nullable
- private static TextRange getCamelSelectionRange(CharSequence editorText, int cursorOffset) {
+ private static TextRange getCamelSelectionRange(CharSequence editorText, int cursorOffset, CharCondition isWordPartCondition) {
if (cursorOffset < 0 || cursorOffset >= editorText.length()) {
return null;
}
- if (cursorOffset > 0 && !Character.isJavaIdentifierPart(editorText.charAt(cursorOffset)) &&
- Character.isJavaIdentifierPart(editorText.charAt(cursorOffset - 1))) {
+ if (cursorOffset > 0 && !isWordPartCondition.value(editorText.charAt(cursorOffset)) &&
+ isWordPartCondition.value(editorText.charAt(cursorOffset - 1))) {
cursorOffset--;
}
- if (Character.isJavaIdentifierPart(editorText.charAt(cursorOffset))) {
+ if (isWordPartCondition.value(editorText.charAt(cursorOffset))) {
int start = cursorOffset;
int end = cursorOffset + 1;
final int textLen = editorText.length();
- while (start > 0 && Character.isJavaIdentifierPart(editorText.charAt(start - 1)) && !EditorActionUtil.isHumpBound(editorText, start, true)) {
+ while (start > 0 && isWordPartCondition.value(editorText.charAt(start - 1)) && !EditorActionUtil.isHumpBound(editorText, start, true)) {
start--;
}
- while (end < textLen && Character.isJavaIdentifierPart(editorText.charAt(end)) && !EditorActionUtil.isHumpBound(editorText, end, false)) {
+ while (end < textLen && isWordPartCondition.value(editorText.charAt(end)) && !EditorActionUtil.isHumpBound(editorText, end, false)) {
end++;
}
@@ -110,24 +124,24 @@ public class SelectWordUtil {
}
@Nullable
- public static TextRange getWordSelectionRange(@NotNull CharSequence editorText, int cursorOffset) {
+ public static TextRange getWordSelectionRange(@NotNull CharSequence editorText, int cursorOffset, @NotNull CharCondition isWordPartCondition) {
int length = editorText.length();
if (length == 0) return null;
if (cursorOffset == length ||
- cursorOffset > 0 && !Character.isJavaIdentifierPart(editorText.charAt(cursorOffset)) &&
- Character.isJavaIdentifierPart(editorText.charAt(cursorOffset - 1))) {
+ cursorOffset > 0 && !isWordPartCondition.value(editorText.charAt(cursorOffset)) &&
+ isWordPartCondition.value(editorText.charAt(cursorOffset - 1))) {
cursorOffset--;
}
- if (Character.isJavaIdentifierPart(editorText.charAt(cursorOffset))) {
+ if (isWordPartCondition.value(editorText.charAt(cursorOffset))) {
int start = cursorOffset;
int end = cursorOffset;
- while (start > 0 && Character.isJavaIdentifierPart(editorText.charAt(start - 1))) {
+ while (start > 0 && isWordPartCondition.value(editorText.charAt(start - 1))) {
start--;
}
- while (end < length && Character.isJavaIdentifierPart(editorText.charAt(end))) {
+ while (end < length && isWordPartCondition.value(editorText.charAt(end))) {
end++;
}
@@ -229,7 +243,7 @@ public class SelectWordUtil {
result.add(new TextRange(lexer.getTokenStart(), lexer.getTokenEnd()));
}
else {
- TextRange word = getWordSelectionRange(editorText, cursorOffset);
+ TextRange word = getWordSelectionRange(editorText, cursorOffset, JAVA_IDENTIFIER_PART_CONDITION);
if (word != null) {
result.add(new TextRange(Math.max(word.getStartOffset(), lexer.getTokenStart()),
Math.min(word.getEndOffset(), lexer.getTokenEnd())));
@@ -240,4 +254,6 @@ public class SelectWordUtil {
lexer.advance();
}
}
+
+ public interface CharCondition { boolean value(char ch); }
}
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 ef79a906b9f4..b6c0f77f1a9f 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -45,6 +45,7 @@ import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.Indent;
import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.DocumentUtil;
import com.intellij.util.containers.IntArrayList;
import com.intellij.util.text.CharArrayUtil;
@@ -385,8 +386,8 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler {
final CharSequence charSequence = myDocument.getCharsSequence();
lineStartOffset = CharArrayUtil.shiftForward(charSequence, lineStartOffset, " \t");
lineEndOffset = CharArrayUtil.shiftBackward(charSequence, lineEndOffset < 0 ? 0 : lineEndOffset, " \t");
- final Language lineStartLanguage = PsiUtilBase.getLanguageAtOffset(myFile, lineStartOffset);
- final Language lineEndLanguage = PsiUtilBase.getLanguageAtOffset(myFile, lineEndOffset);
+ final Language lineStartLanguage = PsiUtilCore.getLanguageAtOffset(myFile, lineStartOffset);
+ final Language lineEndLanguage = PsiUtilCore.getLanguageAtOffset(myFile, lineEndOffset);
return CommentByBlockCommentHandler.getCommenter(myFile, myEditor, lineStartLanguage, lineEndLanguage);
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/DelegateMethodsHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/DelegateMethodsHandler.java
index 3f00e7919357..e21167186cd4 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/generation/DelegateMethodsHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/DelegateMethodsHandler.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.
@@ -25,7 +25,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
-import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NotNull;
public class DelegateMethodsHandler implements CodeInsightActionHandler{
@@ -36,7 +36,7 @@ public class DelegateMethodsHandler implements CodeInsightActionHandler{
return;
}
- Language language = PsiUtilBase.getLanguageAtOffset(file, editor.getCaretModel().getOffset());
+ Language language = PsiUtilCore.getLanguageAtOffset(file, editor.getCaretModel().getOffset());
final LanguageCodeInsightActionHandler codeInsightActionHandler = CodeInsightActions.DELEGATE_METHODS.forLanguage(language);
if (codeInsightActionHandler != null) {
codeInsightActionHandler.invoke(project, editor, file);
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/ImplementMethodsHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/ImplementMethodsHandler.java
index 25f0976cd949..3516cf3de745 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/generation/ImplementMethodsHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/ImplementMethodsHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -25,7 +25,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
-import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NotNull;
public class ImplementMethodsHandler implements CodeInsightActionHandler{
@@ -36,7 +36,7 @@ public class ImplementMethodsHandler implements CodeInsightActionHandler{
return;
}
- Language language = PsiUtilBase.getLanguageAtOffset(file, editor.getCaretModel().getOffset());
+ Language language = PsiUtilCore.getLanguageAtOffset(file, editor.getCaretModel().getOffset());
final LanguageCodeInsightActionHandler codeInsightActionHandler = CodeInsightActions.IMPLEMENT_METHOD.forLanguage(language);
if (codeInsightActionHandler != null) {
codeInsightActionHandler.invoke(project, editor, file);
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/OverrideMethodsHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/OverrideMethodsHandler.java
index ef1b513bed4f..18bb33d80691 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/generation/OverrideMethodsHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/OverrideMethodsHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -25,7 +25,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
-import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NotNull;
public class OverrideMethodsHandler implements CodeInsightActionHandler{
@@ -36,7 +36,7 @@ public class OverrideMethodsHandler implements CodeInsightActionHandler{
return;
}
- Language language = PsiUtilBase.getLanguageAtOffset(file, editor.getCaretModel().getOffset());
+ Language language = PsiUtilCore.getLanguageAtOffset(file, editor.getCaretModel().getOffset());
final LanguageCodeInsightActionHandler codeInsightActionHandler = CodeInsightActions.OVERRIDE_METHOD.forLanguage(language);
if (codeInsightActionHandler != null) {
codeInsightActionHandler.invoke(project, editor, file);
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/DelegateMethodsAction.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/DelegateMethodsAction.java
index bc5d831dcd47..73bde9118d8f 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/DelegateMethodsAction.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/DelegateMethodsAction.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.
@@ -26,7 +26,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
-import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NotNull;
public class DelegateMethodsAction extends BaseCodeInsightAction {
@@ -39,7 +39,7 @@ public class DelegateMethodsAction extends BaseCodeInsightAction {
@Override
protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull final PsiFile file) {
- Language language = PsiUtilBase.getLanguageAtOffset(file, editor.getCaretModel().getOffset());
+ Language language = PsiUtilCore.getLanguageAtOffset(file, editor.getCaretModel().getOffset());
final LanguageCodeInsightActionHandler codeInsightActionHandler = CodeInsightActions.DELEGATE_METHODS.forLanguage(language);
if (codeInsightActionHandler != null) {
return codeInsightActionHandler.isValidFor(editor, file);
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/ImplementMethodsAction.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/ImplementMethodsAction.java
index ed97b98f7868..27c2a4645a16 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/ImplementMethodsAction.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/ImplementMethodsAction.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.
@@ -26,7 +26,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.psi.PsiFile;
-import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NotNull;
public class ImplementMethodsAction extends BaseCodeInsightAction {
@@ -38,7 +38,7 @@ public class ImplementMethodsAction extends BaseCodeInsightAction {
@Override
protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull final PsiFile file) {
- final Language language = PsiUtilBase.getLanguageAtOffset(file, editor.getCaretModel().getOffset());
+ final Language language = PsiUtilCore.getLanguageAtOffset(file, editor.getCaretModel().getOffset());
final LanguageCodeInsightActionHandler codeInsightActionHandler = CodeInsightActions.IMPLEMENT_METHOD.forLanguage(language);
return codeInsightActionHandler != null && codeInsightActionHandler.isValidFor(editor, file);
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/OverrideMethodsAction.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/OverrideMethodsAction.java
index 9827f1272294..134bba4eb3ee 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/OverrideMethodsAction.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/OverrideMethodsAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2011 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.
@@ -26,7 +26,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.psi.PsiFile;
-import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NotNull;
public class OverrideMethodsAction extends BaseCodeInsightAction {
@@ -39,7 +39,7 @@ public class OverrideMethodsAction extends BaseCodeInsightAction {
@Override
protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull final PsiFile file) {
- Language language = PsiUtilBase.getLanguageAtOffset(file, editor.getCaretModel().getOffset());
+ Language language = PsiUtilCore.getLanguageAtOffset(file, editor.getCaretModel().getOffset());
final LanguageCodeInsightActionHandler codeInsightActionHandler = CodeInsightActions.OVERRIDE_METHOD.forLanguage(language);
if (codeInsightActionHandler != null) {
return codeInsightActionHandler.isValidFor(editor, file);
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java
index 651ffc8ee015..85f5c2233479 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java
@@ -55,6 +55,7 @@ import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.ColorUtil;
import com.intellij.util.Alarm;
import com.intellij.util.Processor;
@@ -493,7 +494,8 @@ public class BraceHighlightingHandler {
int start = lbraceStart;
if (!(myPsiFile instanceof PsiPlainTextFile) && myPsiFile.isValid()) {
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
- start = BraceMatchingUtil.getBraceMatcher(getFileTypeByOffset(lbraceStart), PsiUtilBase.getLanguageAtOffset(myPsiFile, lbraceStart)).getCodeConstructStart(myPsiFile, lbraceStart);
+ start = BraceMatchingUtil.getBraceMatcher(getFileTypeByOffset(lbraceStart), PsiUtilCore
+ .getLanguageAtOffset(myPsiFile, lbraceStart)).getCodeConstructStart(myPsiFile, lbraceStart);
}
TextRange range = new TextRange(start, lbraceEnd);
int line1 = myDocument.getLineNumber(range.getStartOffset());
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java
index 966c935b0698..a4d94da42c4c 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/ParameterInfoController.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -34,7 +34,7 @@ import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
-import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.LightweightHint;
import com.intellij.util.Alarm;
import com.intellij.util.ArrayUtil;
@@ -317,7 +317,7 @@ public class ParameterInfoController implements Disposable {
@Nullable
public static <E extends PsiElement> E findArgumentList(PsiFile file, int offset, int lbraceOffset){
if (file == null) return null;
- ParameterInfoHandler[] handlers = ShowParameterInfoHandler.getHandlers(file.getProject(), PsiUtilBase.getLanguageAtOffset(file, offset), file.getViewProvider().getBaseLanguage());
+ ParameterInfoHandler[] handlers = ShowParameterInfoHandler.getHandlers(file.getProject(), PsiUtilCore.getLanguageAtOffset(file, offset), file.getViewProvider().getBaseLanguage());
if (handlers != null) {
for(ParameterInfoHandler handler:handlers) {
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowParameterInfoAction.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowParameterInfoAction.java
index 439e6dc7b8c5..437603ff5bdb 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowParameterInfoAction.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowParameterInfoAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -24,7 +24,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
-import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NotNull;
public class ShowParameterInfoAction extends BaseCodeInsightAction implements DumbAware {
@@ -40,7 +40,7 @@ public class ShowParameterInfoAction extends BaseCodeInsightAction implements Du
@Override
protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull final PsiFile file) {
- final Language language = PsiUtilBase.getLanguageAtOffset(file, editor.getCaretModel().getOffset());
+ final Language language = PsiUtilCore.getLanguageAtOffset(file, editor.getCaretModel().getOffset());
return ShowParameterInfoHandler.getHandlers(project, language, file.getViewProvider().getBaseLanguage()) != null;
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.java
index 8af41a35df81..81312281355b 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.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.
@@ -147,6 +147,7 @@ public class QuickEditHandler extends DocumentAdapter implements Disposable {
public void update(AnActionEvent e) {
Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext());
e.getPresentation().setEnabled(
+ !myAction.isShowInBalloon() &&
editor != null && LookupManager.getActiveLookup(editor) == null &&
TemplateManager.getInstance(myProject).getActiveTemplate(editor) == null &&
(editorEscape == null || !editorEscape.isEnabled(editor, e.getDataContext())));
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoSuperAction.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoSuperAction.java
index ea26953e25ba..fc0e0cd73afc 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoSuperAction.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoSuperAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2011 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.
@@ -26,7 +26,7 @@ import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
-import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -45,7 +45,7 @@ public class GotoSuperAction extends BaseCodeInsightAction implements CodeInsigh
PsiDocumentManager.getInstance(project).commitAllDocuments();
int offset = editor.getCaretModel().getOffset();
- final Language language = PsiUtilBase.getLanguageAtOffset(file, offset);
+ final Language language = PsiUtilCore.getLanguageAtOffset(file, offset);
final CodeInsightActionHandler codeInsightActionHandler = CodeInsightActions.GOTO_SUPER.forLanguage(language);
if (codeInsightActionHandler != null) {
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/LiveTemplateBuilder.java b/platform/lang-impl/src/com/intellij/codeInsight/template/LiveTemplateBuilder.java
index b2756647a745..592b6915cd36 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/LiveTemplateBuilder.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/LiveTemplateBuilder.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.
@@ -50,10 +50,6 @@ public class LiveTemplateBuilder {
return name.startsWith(END_PREFIX);
}
- public void insertVariableSegment(int offset, String name) {
- myVariableOccurences.add(new VarOccurence(name, offset));
- }
-
private static class VarOccurence {
String myName;
int myOffset;
@@ -262,7 +258,10 @@ public class LiveTemplateBuilder {
for (int i = 0; i < template.getSegmentsCount(); i++) {
String segmentName = template.getSegmentName(i);
int localOffset = template.getSegmentOffset(i);
- if (!TemplateImpl.INTERNAL_VARS_SET.contains(segmentName)) {
+ if (TemplateImpl.END.equals(segmentName)) {
+ end = offset + localOffset;
+ }
+ else {
if (predefinedVarValues != null && predefinedVarValues.containsKey(segmentName)) {
String value = predefinedVarValues.get(segmentName);
insertText(offset + localOffset, value, false);
@@ -274,9 +273,6 @@ public class LiveTemplateBuilder {
}
myVariableOccurences.add(new VarOccurence(segmentName, offset + localOffset));
}
- else if (TemplateImpl.END.equals(segmentName)) {
- end = offset + localOffset;
- }
}
int endOffset = end >= 0 ? end : offset + text.length();
if (endOffset > 0 &&
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateLookupElement.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateLookupElement.java
index 00e6c44d728d..e22a4114beed 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateLookupElement.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateLookupElement.java
@@ -65,7 +65,10 @@ public class LiveTemplateLookupElement extends LookupElement {
}
presentation.setTypeText(" [" + KeyEvent.getKeyText(shortcutChar) + "] ");
}
- presentation.setTailText(" (" + myTemplate.getDescription() + ")", true);
+ String description = myTemplate.getDescription();
+ if (description != null) {
+ presentation.setTailText(" (" + description + ")", true);
+ }
} else {
presentation.setTypeText(myTemplate.getDescription());
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java
index f1a94deefaab..0c1e6045fee6 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java
@@ -36,6 +36,7 @@ import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.PairProcessor;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NotNull;
@@ -570,7 +571,7 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo
// if we have, for example, a Ruby fragment in RHTML selected with its exact bounds, the file language and the base
// language will be ERb, so we won't match HTML templates for it. but they're actually valid
- Language languageAtOffset = PsiUtilBase.getLanguageAtOffset(file, offset);
+ Language languageAtOffset = PsiUtilCore.getLanguageAtOffset(file, offset);
if (languageAtOffset != file.getLanguage() && languageAtOffset != baseLanguage) {
PsiFile basePsi = file.getViewProvider().getPsi(languageAtOffset);
if (basePsi != null) {
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java
index 38bd35f6d96a..3f31d5c2d008 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java
@@ -51,7 +51,6 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.impl.source.codeStyle.CodeStyleManagerImpl;
-import com.intellij.psi.util.PsiUtilBase;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.refactoring.rename.inplace.InplaceRefactoring;
import com.intellij.util.IncorrectOperationException;
@@ -339,11 +338,11 @@ public class TemplateState implements Disposable {
mySegments.addSegment(segmentOffset, segmentOffset);
}
- LOG.assertTrue(myTemplateRange.isValid());
+ LOG.assertTrue(myTemplateRange.isValid(), myTemplateRange.toString());
calcResults(false);
- LOG.assertTrue(myTemplateRange.isValid());
+ LOG.assertTrue(myTemplateRange.isValid(), myTemplateRange.toString());
calcResults(false); //Fixed SCR #[vk500] : all variables should be recalced twice on start.
- LOG.assertTrue(myTemplateRange.isValid());
+ LOG.assertTrue(myTemplateRange.isValid(), myTemplateRange.toString());
doReformat(null);
int nextVariableNumber = getNextVariableNumber(-1);
diff --git a/platform/lang-impl/src/com/intellij/codeInspection/LossyEncodingInspection.java b/platform/lang-impl/src/com/intellij/codeInspection/LossyEncodingInspection.java
index 72336b57c591..7ec8be737e37 100644
--- a/platform/lang-impl/src/com/intellij/codeInspection/LossyEncodingInspection.java
+++ b/platform/lang-impl/src/com/intellij/codeInspection/LossyEncodingInspection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -22,7 +22,6 @@
*/
package com.intellij.codeInspection;
-import com.intellij.codeStyle.CodeStyleFacade;
import com.intellij.ide.DataManager;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.lang.properties.charset.Native2AsciiCharset;
@@ -41,11 +40,9 @@ import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.encoding.ChangeFileEncodingAction;
import com.intellij.openapi.vfs.encoding.EncodingUtil;
-import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.util.ArrayUtil;
@@ -99,9 +96,7 @@ public class LossyEncodingInspection extends LocalInspectionTool {
if (file.getViewProvider().getBaseLanguage() != file.getLanguage()) return null;
VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile == null) return null;
- if (virtualFile.getFileSystem() != LocalFileSystem.getInstance()
- // tests
- && virtualFile.getFileSystem() != TempFileSystem.getInstance()) return null;
+ if (!virtualFile.isInLocalFileSystem()) return null;
String text = file.getText();
Charset charset = LoadTextUtil.extractCharsetFromFileContent(file.getProject(), virtualFile, text);
@@ -157,7 +152,7 @@ public class LossyEncodingInspection extends LocalInspectionTool {
if (separator == null) {
separator = documentManager.isDocumentUnsaved(document) ?
FileDocumentManagerImpl.getLineSeparator(document, virtualFile) :
- CodeStyleFacade.getInstance(project).getLineSeparator();
+ FileDocumentManager.getInstance().getLineSeparator(null, project);
}
String toSave = StringUtil.convertLineSeparators(text, separator);
byte[] bom = virtualFile.getBOM();
diff --git a/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java b/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java
index d7d1ab894833..ac25e69af98b 100644
--- a/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java
+++ b/platform/lang-impl/src/com/intellij/execution/console/ConsoleHistoryController.java
@@ -19,9 +19,7 @@ import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.execution.process.ConsoleHistoryModel;
import com.intellij.lang.Language;
import com.intellij.openapi.Disposable;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.EmptyAction;
+import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.command.WriteCommandAction;
@@ -127,8 +125,16 @@ public class ConsoleHistoryController {
EmptyAction.setupAction(myHistoryPrev, "Console.History.Previous", null);
EmptyAction.setupAction(myBrowseHistory, "Console.History.Browse", null);
if (!myMultiline) {
- myHistoryNext.registerCustomShortcutSet(KeyEvent.VK_UP, 0, null);
- myHistoryPrev.registerCustomShortcutSet(KeyEvent.VK_DOWN, 0, null);
+ AnAction up = ActionManager.getInstance().getActionOrStub(IdeActions.ACTION_EDITOR_MOVE_CARET_UP);
+ AnAction down = ActionManager.getInstance().getActionOrStub(IdeActions.ACTION_EDITOR_MOVE_CARET_DOWN);
+ if (up != null && down != null) {
+ myHistoryNext.registerCustomShortcutSet(up.getShortcutSet(), null);
+ myHistoryPrev.registerCustomShortcutSet(down.getShortcutSet(), null);
+ }
+ else {
+ myHistoryNext.registerCustomShortcutSet(KeyEvent.VK_UP, 0, null);
+ myHistoryPrev.registerCustomShortcutSet(KeyEvent.VK_DOWN, 0, null);
+ }
}
myHistoryNext.registerCustomShortcutSet(myHistoryNext.getShortcutSet(), myConsole.getCurrentEditor().getComponent());
myHistoryPrev.registerCustomShortcutSet(myHistoryPrev.getShortcutSet(), myConsole.getCurrentEditor().getComponent());
diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java
index 8acd2da516ef..e39640d74694 100644
--- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java
+++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java
@@ -557,7 +557,8 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider {
}
if (preserveMarkup) {
duplicateHighlighters(markupModel, DocumentMarkupModel.forDocument(consoleEditor.getDocument(), myProject, true), offset, textRange);
- duplicateHighlighters(markupModel, consoleEditor.getMarkupModel(), offset, textRange);
+ // don't copy editor markup model, i.e. brace matcher, spell checker, etc.
+ // duplicateHighlighters(markupModel, consoleEditor.getMarkupModel(), offset, textRange);
}
if (!text.endsWith("\n")) {
appendToHistoryDocument(history, "\n");
diff --git a/platform/lang-impl/src/com/intellij/framework/library/impl/FrameworkLibraryVersionImpl.java b/platform/lang-impl/src/com/intellij/framework/library/impl/FrameworkLibraryVersionImpl.java
index 9a265a198544..5e8a897ade67 100644
--- a/platform/lang-impl/src/com/intellij/framework/library/impl/FrameworkLibraryVersionImpl.java
+++ b/platform/lang-impl/src/com/intellij/framework/library/impl/FrameworkLibraryVersionImpl.java
@@ -55,4 +55,15 @@ public class FrameworkLibraryVersionImpl extends DownloadableFileSetDescriptionI
String libName = StringUtil.isEmptyOrSpaces(myLibraryName) ? myLibraryCategory : myLibraryName;
return myVersionString.length() > 0 ? libName + "-" + myVersionString : myLibraryCategory;
}
+
+ @NotNull
+ @Override
+ public String getPresentableName() {
+ return getDefaultLibraryName();
+ }
+
+ @Override
+ public String getVersionNumber() {
+ return getVersionString();
+ }
}
diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java
index 91adb014bc16..da6216f32262 100644
--- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java
+++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.navigation.NavigationUtil;
import com.intellij.icons.AllIcons;
import com.intellij.ide.DataManager;
import com.intellij.ide.IdeEventQueue;
+import com.intellij.ide.IdeTooltipManager;
import com.intellij.ide.SearchTopHitProvider;
import com.intellij.ide.ui.LafManager;
import com.intellij.ide.ui.LafManagerListener;
@@ -38,6 +39,7 @@ import com.intellij.openapi.editor.actions.TextComponentEditorAction;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.fileEditor.impl.EditorHistoryManager;
import com.intellij.openapi.keymap.KeymapUtil;
+import com.intellij.openapi.keymap.MacKeymapUtil;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.options.ex.IdeConfigurablesGroup;
@@ -48,12 +50,11 @@ import com.intellij.openapi.progress.util.ProgressIndicatorBase;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.DumbServiceImpl;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.ComponentPopupBuilder;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.ui.popup.MouseChecker;
import com.intellij.openapi.util.*;
-import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFilePathWrapper;
@@ -73,7 +74,6 @@ import com.intellij.ui.components.JBList;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.OnOffButton;
import com.intellij.ui.popup.AbstractPopup;
-import com.intellij.ui.popup.PopupPositionManager;
import com.intellij.util.Alarm;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Consumer;
@@ -92,8 +92,7 @@ import java.lang.reflect.Field;
import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
-
-import static com.intellij.ui.popup.PopupPositionManager.Position.*;
+import java.util.concurrent.atomic.AtomicLong;
/**
* @author Konstantin Bulenkov
@@ -122,23 +121,14 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
private Alarm myAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, ApplicationManager.getApplication());
private Alarm myUpdateAlarm = new Alarm(ApplicationManager.getApplication());
- private JBList myList = new JBList(myListModel) {
- {
- setOpaque(false);
- }
- @Override
- protected void paintComponent(Graphics g) {
- //g.setColor(getTitlePanelBackground());
- //g.fillRect(0, 0, myLeftWidth - 1, getHeight());
- //g.setColor(getSeparatorColor());
- //g.drawLine(myLeftWidth-1, 0, myLeftWidth-1, getHeight());
- super.paintComponent(g);
- }
- };
+ private JBList myList = new JBList(myListModel);
private AnActionEvent myActionEvent;
private Component myContextComponent;
private CalcThread myCalcThread;
- private static AtomicBoolean ourShiftCanBeUsed = new AtomicBoolean(false);
+ private static AtomicBoolean ourPressed = new AtomicBoolean(false);
+ private static AtomicBoolean ourReleased = new AtomicBoolean(false);
+ private static AtomicBoolean ourOtherKeyWasPressed = new AtomicBoolean(false);
+ private static AtomicLong ourLastTimePressed = new AtomicLong(0);
private ArrayList<VirtualFile> myAlreadyAddedFiles = new ArrayList<VirtualFile>();
static {
@@ -146,50 +136,125 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
@Override
public boolean dispatch(AWTEvent event) {
if (event instanceof KeyEvent) {
- ourShiftCanBeUsed.set((((KeyEvent)event).getKeyCode() != KeyEvent.VK_SHIFT) || event.getID() != KeyEvent.KEY_PRESSED);
+ final KeyEvent keyEvent = (KeyEvent)event;
+ final int keyCode = keyEvent.getKeyCode();
+
+ if (keyCode == KeyEvent.VK_SHIFT) {
+ if (ourOtherKeyWasPressed.get() && System.currentTimeMillis() - ourLastTimePressed.get() < 300) {
+ ourPressed.set(false);
+ ourReleased.set(false);
+ return false;
+ }
+ ourOtherKeyWasPressed.set(false);
+ if (System.currentTimeMillis() - ourLastTimePressed.get() > 400) {
+ ourPressed.set(false);
+ ourReleased.set(false);
+ }
+ if (event.getID() == KeyEvent.KEY_PRESSED) {
+ if (!ourPressed.get()) {
+ ourPressed.set(true);
+ ourLastTimePressed.set(System.currentTimeMillis());
+ } else {
+ if (ourPressed.get() && ourReleased.get()) {
+ ourPressed.set(false);
+ ourReleased.set(false);
+ ourLastTimePressed.set(System.currentTimeMillis());
+ final ActionManager actionManager = ActionManager.getInstance();
+ final AnAction action = actionManager.getAction("SearchEverywhere");
+
+ final AnActionEvent anActionEvent = new AnActionEvent(keyEvent,
+ DataManager.getInstance().getDataContext(IdeFocusManager.findInstance().getFocusOwner()),
+ ActionPlaces.UNKNOWN,
+ action.getTemplatePresentation(),
+ actionManager,
+ 0);
+ action.actionPerformed(anActionEvent);
+ }
+ }
+ } else if (event.getID() == KeyEvent.KEY_RELEASED) {
+ if (ourPressed.get()) {
+ ourReleased.set(true);
+ }
+ }
+ return false;
+ } else {
+ ourLastTimePressed.set(System.currentTimeMillis());
+ ourOtherKeyWasPressed.set(true);
+ }
+ ourPressed.set(false);
+ ourReleased.set(false);
}
return false;
}
}, null);
}
- private Balloon myBalloon;
+ private JBPopup myBalloon;
private JLabel mySearchLabel;
private int myPopupActualWidth;
+ private Component myFocusOwner;
public SearchEverywhereAction() {
- myContentPanel = new JPanel(new BorderLayout());
+ myContentPanel = new JPanel(new BorderLayout()) {
+ @Override
+ protected void paintComponent(Graphics g) {
+ if (myBalloon != null && !myBalloon.isDisposed() && myActionEvent != null && myActionEvent.getInputEvent() == null) {
+ ((Graphics2D)g).setPaint(new GradientPaint(0,0, new JBColor(new Color(101, 136, 242), new Color(16, 91, 180)), 0, getHeight(),
+ new JBColor(new Color(44, 96, 238), new Color(16, 80, 147))));
+ g.fillRect(0,0,getWidth(), getHeight());
+ } else {
+ super.paintComponent(g);
+ }
+ }
+ };
myContentPanel.setOpaque(false);
+ myList.setOpaque(false);
mySearchLabel = new JBLabel(AllIcons.Actions.FindPlain) {
{
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
- setToolTipText("<html><body>Search Everywhere<br/>Press <b>"
- +
- KeymapUtil.getShortcutText(CustomShortcutSet.fromString("shift SPACE").getShortcuts()[0]) +
- "</b> to access<br/> - Classes<br/> - Files<br/> - Tool Windows<br/> - Actions<br/> - Settings</body></html>");
}
};
+ myContentPanel.add(mySearchLabel, BorderLayout.CENTER);
+ initTooltip();
mySearchLabel.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
- mySearchLabel.setIcon(AllIcons.Actions.FindPlain);
- myContentPanel.remove(mySearchLabel);
- field.getTextEditor().setColumns(SEARCH_FIELD_COLUMNS);
- myContentPanel.add(field, BorderLayout.CENTER);
- myContentPanel.revalidate();
- myContentPanel.repaint();
- IdeFocusManager.findInstanceByComponent(field.getTextEditor()).requestFocus(field.getTextEditor(), true);
+ if (myBalloon != null) {
+ myBalloon.cancel();
+ }
+ myFocusOwner = IdeFocusManager.findInstance().getFocusOwner();
+ mySearchLabel.setToolTipText(null);
+ IdeTooltipManager.getInstance().hideCurrentNow(false);
+ mySearchLabel.setIcon(AllIcons.Actions.FindWhite);
+ actionPerformed(null);
+// mySearchLabel.setIcon(AllIcons.Actions.FindPlain);
+// myContentPanel.remove(mySearchLabel);
+// field.getTextEditor().setColumns(SEARCH_FIELD_COLUMNS);
+// myContentPanel.add(field, BorderLayout.CENTER);
+// field.setOpaque(false);
+// myContentPanel.setOpaque(false);
+// JComponent parent = UIUtil.getParentOfType(Box.class, myContentPanel);
+// if (parent == null) {
+// parent = (JComponent)myContentPanel.getParent().getParent();
+// }
+// parent.revalidate();
+// parent.repaint();
+// IdeFocusManager.findInstanceByComponent(field.getTextEditor()).requestFocus(field.getTextEditor(), true);
}
@Override
public void mouseEntered(MouseEvent e) {
- mySearchLabel.setIcon(AllIcons.Actions.Find);
+ if (myBalloon == null || myBalloon.isDisposed()) {
+ mySearchLabel.setIcon(AllIcons.Actions.Find);
+ }
}
@Override
public void mouseExited(MouseEvent e) {
- mySearchLabel.setIcon(AllIcons.Actions.FindPlain);
+ if (myBalloon == null || myBalloon.isDisposed()) {
+ mySearchLabel.setIcon(AllIcons.Actions.FindPlain);
+ }
}
});
@@ -221,16 +286,13 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
}
- @Override
- public void update(AnActionEvent e) {
- final InputEvent event = e.getInputEvent();
- if (event instanceof KeyEvent && event.isShiftDown() && ((KeyEvent)event).getKeyCode() == KeyEvent.VK_SPACE) {
- e.getPresentation().setEnabledAndVisible(!ourShiftCanBeUsed.get() && Registry.is("search.everywhere.enabled"));
- } else {
- e.getPresentation().setEnabled(true);
- }
- }
+ private void initTooltip() {
+ mySearchLabel.setToolTipText("<html><body>Search Everywhere<br/>Press <b>" +
+ "Double " +
+ (SystemInfo.isMac ? MacKeymapUtil.SHIFT : "Shift") +
+ "</b> to access<br/> - Classes<br/> - Files<br/> - Tool Windows<br/> - Actions<br/> - Settings</body></html>");
+ }
private void createSearchField() {
field = new MySearchTextField();
@@ -239,6 +301,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
private void initSearchField(final SearchTextField search) {
final JTextField editor = search.getTextEditor();
+// editor.setOpaque(false);
+ editor.putClientProperty("JTextField.Search.noFocusRing", Boolean.TRUE);
onFocusLost(editor);
editor.getDocument().addDocumentListener(new DocumentAdapter() {
@Override
@@ -312,18 +376,22 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
- editor.setColumns(SystemInfo.isMac ? 5 : 8);
- field.getTextEditor().setForeground(UIUtil.getLabelDisabledForeground());
- field.setText(" " + KeymapUtil.getFirstKeyboardShortcutText(SearchEverywhereAction.this));
+// editor.setColumns(SystemInfo.isMac ? 5 : 8);
+// field.getTextEditor().setForeground(UIUtil.getLabelDisabledForeground());
+// field.setText(" " + KeymapUtil.getFirstKeyboardShortcutText(SearchEverywhereAction.this));
if (myCalcThread != null) {
myCalcThread.cancel();
myCalcThread = null;
}
myAlarm.cancelAllRequests();
clearModel();
- myContentPanel.remove(field);
- mySearchLabel.setIcon(AllIcons.Actions.FindPlain);
- myContentPanel.add(mySearchLabel);
+ if (myBalloon != null && !myBalloon.isDisposed() && myPopup != null && !myPopup.isDisposed()) {
+ myBalloon.cancel();
+ myPopup.cancel();
+ }
+// myContentPanel.remove(field);
+// mySearchLabel.setIcon(AllIcons.Actions.FindPlain);
+// myContentPanel.add(mySearchLabel, BorderLayout.CENTER);
//noinspection SSBasedInspection
SwingUtilities.invokeLater(new Runnable() {
@@ -431,43 +499,68 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
@Override
public void actionPerformed(AnActionEvent e) {
+ if (e == null && myFocusOwner != null) {
+ e = new AnActionEvent(null, DataManager.getInstance().getDataContext(myFocusComponent), ActionPlaces.UNKNOWN, getTemplatePresentation(), ActionManager.getInstance(), 0);
+ }
+ if (e == null) return;
myContextComponent = PlatformDataKeys.CONTEXT_COMPONENT.getData(e.getDataContext());
myActionEvent = e;
myPopupField = new MySearchTextField();
- myPopupField.setOpaque(true);
+ myPopupField.setOpaque(false);
initSearchField(myPopupField);
myPopupField.getTextEditor().setColumns(SEARCH_FIELD_COLUMNS);
- final JPanel panel = new JPanel(new BorderLayout());
+ final JPanel panel = new JPanel(new BorderLayout()) {
+ @Override
+ protected void paintComponent(Graphics g) {
+ ((Graphics2D)g).setPaint(new GradientPaint(0,0, new JBColor(new Color(0x6688f2), new Color(59, 81, 162)), 0, getHeight(),
+ new JBColor(new Color(0x2d60ee), new Color(53, 67, 134))));
+ g.fillRect(0,0, getWidth(), getHeight());
+ }
+ };
final JLabel title = new JLabel(" Search Everywhere:");
+ title.setForeground(new JBColor(Gray._255, Gray._160));
if (SystemInfo.isMac) {
title.setFont(title.getFont().deriveFont(Font.BOLD, title.getFont().getSize() - 1f));
} else {
title.setFont(title.getFont().deriveFont(Font.BOLD));
}
- panel.add(title, BorderLayout.NORTH);
+ panel.add(title, BorderLayout.WEST);
panel.add(myPopupField, BorderLayout.CENTER);
- panel.setBorder(IdeBorderFactory.createEmptyBorder(0, 5, 2, 5));
- myBalloon = JBPopupFactory.getInstance().createBalloonBuilder(panel)
- .setShowCallout(false)
- .setHideOnKeyOutside(false)
- .setHideOnAction(false)
- .setAnimationCycle(0)
- .setDialogMode(false)
- .setBorderColor(new JBColor(Gray._130, Gray._77))
- .setFillColor(new JBColor(Gray._242, new Color(60, 63, 65)))
- .createBalloon();
+ panel.setBorder(IdeBorderFactory.createEmptyBorder(3, 5, 4, 5));
+// final BalloonPopupBuilderImpl builder = (BalloonPopupBuilderImpl)JBPopupFactory.getInstance().createBalloonBuilder(panel);
+// myBalloon = builder
+// .setCustomPointlessBorder(new EmptyBorder(0,0,0,0))
+// .setShowCallout(false)
+// .setHideOnKeyOutside(false)
+// .setHideOnAction(false)
+// .setAnimationCycle(0)
+// .setBorderColor(new JBColor(Gray._130, Gray._77))
+// .setFillColor(new JBColor(new Color(0x2d60ee), new Color(60, 63, 65)))
+// .createBalloon();
+ final ComponentPopupBuilder builder = JBPopupFactory.getInstance().createComponentPopupBuilder(panel, myPopupField.getTextEditor());
+ myBalloon = builder
+ .setCancelOnClickOutside(true)
+ .setModalContext(false)
+ .createPopup();
+
final Window window = WindowManager.getInstance().suggestParentWindow(e.getProject());
Component parent = UIUtil.findUltimateParent(window);
+
final RelativePoint showPoint;
- if (parent != null) {
- showPoint = new RelativePoint(parent, new Point((parent.getSize().width - panel.getPreferredSize().width)/ 2, parent.getHeight()/3));
+ if (e.getInputEvent() == null) {
+ final Component button = mySearchLabel.getParent();
+ assert button != null;
+ showPoint = new RelativePoint(button, new Point(button.getWidth() - panel.getPreferredSize().width, button.getHeight()));
} else {
- showPoint = JBPopupFactory.getInstance().guessBestPopupLocation(e.getDataContext());
+ if (parent != null) {
+ showPoint = new RelativePoint(parent, new Point((parent.getSize().width - panel.getPreferredSize().width)/ 2, parent.getHeight()/3));
+ } else {
+ showPoint = JBPopupFactory.getInstance().guessBestPopupLocation(e.getDataContext());
+ }
}
- myBalloon.show(showPoint, Balloon.Position.below);
-
+ myBalloon.show(showPoint);
IdeFocusManager focusManager = IdeFocusManager.getInstance(e.getProject());
focusManager.requestFocus(myPopupField.getTextEditor(), true);
}
@@ -1067,14 +1160,29 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
myPopup = builder
.setRequestFocus(false)
.setCancelKeyEnabled(false)
+ .setCancelCallback(new Computable<Boolean>() {
+ @Override
+ public Boolean compute() {
+ return myBalloon == null || myBalloon.isDisposed() || !getField().getTextEditor().hasFocus();
+ }
+ })
+ .setCancelOnMouseOutCallback(new MouseChecker() {
+ @Override
+ public boolean check(MouseEvent event) {
+ final Component c = event.getComponent();
+ return myContentPanel != c && getField().getTextEditor() != c;
+ }
+ })
.createPopup();
Disposer.register(myPopup, new Disposable() {
@Override
public void dispose() {
callback.setDone();
if (myBalloon!= null) {
- myBalloon.hide();
+ myBalloon.cancel();
myBalloon = null;
+ initTooltip();
+ mySearchLabel.setIcon(AllIcons.Actions.FindPlain);
}
myFileModel = null;
myClassModel = null;
@@ -1085,11 +1193,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
myConfigurables.clear();
}
});
- if (getField() == field) {
- myPopup.showUnderneathOf(field);
- } else {
- myPopup.show(new RelativePoint(getField(), new Point(0, getField().getHeight() + 4)));
- }
+ myPopup.show(new RelativePoint(getField().getParent(), new Point(0, getField().getParent().getHeight())));
+
ActionManager.getInstance().addAnActionListener(new AnActionListener.Adapter() {
@Override
public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) {
@@ -1177,11 +1282,12 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
if (myPopup == null || !myPopup.isVisible()) {
return;
}
+ final Container parent = getField().getParent();
final Dimension size = myList.getPreferredSize();
- if (size.width < myPopupActualWidth) {
- size.width = myPopupActualWidth;
+ if (size.width < parent.getWidth()) {
+ size.width = parent.getWidth();
}
- Dimension sz = new Dimension(Math.max(getField().getWidth(), size.width), size.height);
+ Dimension sz = new Dimension(size.width, size.height);
if (sz.width > 800 || sz.height > 800) {
final int extra = new JBScrollPane().getVerticalScrollBar().getWidth();
sz = new Dimension(Math.min(800, Math.max(getField().getWidth(), size.width + extra)), Math.min(800, size.height + extra));
@@ -1194,11 +1300,11 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
sz.width++;
}
myPopup.setSize(sz);
- if (getField() == field) {
- final Point p = getField().getLocationOnScreen();
- p.y += getField().getHeight();
- if (getField().getWidth() < sz.width) {
- p.x -= sz.width - getField().getWidth();
+ if (myActionEvent != null && myActionEvent.getInputEvent() == null) {
+ final Point p = parent.getLocationOnScreen();
+ p.y += parent.getHeight();
+ if (parent.getWidth() < sz.width) {
+ p.x -= sz.width - parent.getWidth();
}
myPopup.setLocation(p);
} else {
@@ -1207,7 +1313,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
}
private void adjustPopup() {
- new PopupPositionManager.PositionAdjuster(getField().getTextEditor().getParent()).adjust(myPopup, BOTTOM, RIGHT, LEFT, TOP);
+// new PopupPositionManager.PositionAdjuster(getField().getParent()).adjust(myPopup, BOTTOM, RIGHT, LEFT, TOP);
}
private static boolean isToolWindowAction(Object o) {
@@ -1330,7 +1436,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
titleLabel.setForeground(UIUtil.getLabelDisabledForeground());
final Color bg = UIUtil.getListBackground();
SeparatorComponent separatorComponent =
- new SeparatorComponent(titleLabel.getPreferredSize().height / 2, new JBColor(bg.darker(), Gray._80), null);
+ new SeparatorComponent(titleLabel.getPreferredSize().height / 2, new JBColor(Gray._240, Gray._80), null);
JPanel result = new JPanel(new BorderLayout(5, 10));
result.add(titleLabel, BorderLayout.WEST);
diff --git a/platform/lang-impl/src/com/intellij/ide/actions/ViewStructureAction.java b/platform/lang-impl/src/com/intellij/ide/actions/ViewStructureAction.java
index 1a8218feee88..81355ac06f14 100644
--- a/platform/lang-impl/src/com/intellij/ide/actions/ViewStructureAction.java
+++ b/platform/lang-impl/src/com/intellij/ide/actions/ViewStructureAction.java
@@ -23,7 +23,10 @@ import com.intellij.ide.structureView.StructureViewModel;
import com.intellij.ide.util.FileStructureDialog;
import com.intellij.ide.util.FileStructurePopup;
import com.intellij.openapi.Disposable;
-import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.project.Project;
@@ -69,7 +72,7 @@ public class ViewStructureAction extends AnAction {
Navigatable navigatable = e.getData(CommonDataKeys.NAVIGATABLE);
if (Registry.is("file.structure.tree.mode")) {
- FileStructurePopup popup = createPopup(editor, project, navigatable, fileEditor);
+ FileStructurePopup popup = createPopup(project, fileEditor);
if (popup == null) return;
popup.setTitle(title);
@@ -93,35 +96,34 @@ public class ViewStructureAction extends AnAction {
}
@Nullable
- public static FileStructurePopup createPopup(@Nullable Editor editor, @NotNull Project project, @Nullable Navigatable navigatable, @NotNull FileEditor fileEditor) {
- final StructureViewBuilder structureViewBuilder = fileEditor.getStructureViewBuilder();
+ public static FileStructurePopup createPopup(@NotNull Project project, @NotNull FileEditor fileEditor) {
+ StructureViewBuilder structureViewBuilder = fileEditor.getStructureViewBuilder();
if (structureViewBuilder == null) return null;
StructureView structureView = structureViewBuilder.createStructureView(fileEditor, project);
- final StructureViewModel model = structureView.getTreeModel();
+ StructureViewModel model = structureView.getTreeModel();
if (model instanceof PlaceHolder) {
//noinspection unchecked
((PlaceHolder)model).setPlace(PLACE);
}
- return createStructureViewPopup(model, editor, project, navigatable, structureView);
+ return createStructureViewPopup(project, fileEditor, structureView);
}
public static boolean isInStructureViewPopup(@NotNull PlaceHolder<String> model) {
return PLACE.equals(model.getPlace());
}
- public static FileStructureDialog createStructureViewBasedDialog(final StructureViewModel structureViewModel,
- final Editor editor,
- final Project project,
- final Navigatable navigatable,
- final @NotNull Disposable alternativeDisposable) {
+ private static FileStructureDialog createStructureViewBasedDialog(StructureViewModel structureViewModel,
+ Editor editor,
+ Project project,
+ Navigatable navigatable,
+ @NotNull Disposable alternativeDisposable) {
return new FileStructureDialog(structureViewModel, editor, project, navigatable, alternativeDisposable, true);
}
- public static FileStructurePopup createStructureViewPopup(final StructureViewModel structureViewModel,
- final Editor editor,
- final Project project,
- final Navigatable navigatable,
- final @NotNull Disposable alternativeDisposable) {
- return new FileStructurePopup(structureViewModel, editor, project, alternativeDisposable, true);
+
+ private static FileStructurePopup createStructureViewPopup(Project project,
+ FileEditor fileEditor,
+ StructureView structureView) {
+ return new FileStructurePopup(project, fileEditor, structureView, true);
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java
index 4db5b6d88ac5..a5826879de90 100644
--- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java
+++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java
@@ -349,7 +349,7 @@ public class FileTemplateUtil{
}
}
- //Set escaped references to dummy values to remove leading "\" (if not already explicitely set)
+ //Set escaped references to dummy values to remove leading "\" (if not already explicitly set)
String[] dummyRefs = calculateAttributes(template.getText(), propsMap, true);
for (String dummyRef : dummyRefs) {
propsMap.put(dummyRef, "");
@@ -384,7 +384,7 @@ public class FileTemplateUtil{
}
});
}
- }, template.isTemplateOfType(StdFileTypes.JAVA)
+ }, template.isTemplateOfType(StdFileTypes.JAVA) && !"package-info".equals(template.getName())
? IdeBundle.message("command.create.class.from.template")
: IdeBundle.message("command.create.file.from.template"), null);
if(commandException[0] != null){
diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateConfigurable.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateConfigurable.java
index 7963b7386b93..944cbc28a5f7 100644
--- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateConfigurable.java
+++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateConfigurable.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -173,7 +173,7 @@ public class FileTemplateConfigurable implements Configurable, Configurable.NoSc
myMainPanel = new JPanel(new GridBagLayout());
myNameField = new JTextField();
myExtensionField = new JTextField();
- mySplitter = new Splitter(true, 0.66f);
+ mySplitter = new Splitter(true, 0.4f);
myTemplateEditor = createEditor();
diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateManagerImpl.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateManagerImpl.java
index 3c8716435c48..835299105ca8 100644
--- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateManagerImpl.java
+++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateManagerImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -68,6 +68,8 @@ public class FileTemplateManagerImpl extends FileTemplateManager implements JDOM
private final FTManager myCodeTemplatesManager;
private final FTManager myJ2eeTemplatesManager;
private final FTManager[] myAllManagers;
+ private final URL myDefaultTemplateDescription;
+ private final URL myDefaultIncludeDescription;
public static FileTemplateManagerImpl getInstanceImpl() {
return (FileTemplateManagerImpl)ServiceManager.getService(FileTemplateManager.class);
@@ -84,6 +86,8 @@ public class FileTemplateManagerImpl extends FileTemplateManager implements JDOM
myCodeTemplatesManager = myTemplateSettings.getCodeTemplatesManager();
myJ2eeTemplatesManager = myTemplateSettings.getJ2eeTemplatesManager();
myAllManagers = myTemplateSettings.getAllManagers();
+ myDefaultTemplateDescription = myTemplateSettings.getDefaultTemplateDescription();
+ myDefaultIncludeDescription = myTemplateSettings.getDefaultIncludeDescription();
if (ApplicationManager.getApplication().isUnitTestMode()) {
for (String tname : Arrays.asList("Class", "AnnotationType", "Enum", "Interface")) {
@@ -473,11 +477,11 @@ public class FileTemplateManagerImpl extends FileTemplateManager implements JDOM
}
public URL getDefaultTemplateDescription() {
- return null; // todo
+ return myDefaultTemplateDescription;
}
public URL getDefaultIncludeDescription() {
- return null; // todo
+ return myDefaultIncludeDescription;
}
private Date myTestDate;
diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateTab.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateTab.java
index 67492fd345fc..e820ac7ac89c 100644
--- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateTab.java
+++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateTab.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.
@@ -17,6 +17,7 @@
package com.intellij.ide.fileTemplates.impl;
import com.intellij.ide.fileTemplates.FileTemplate;
+import com.intellij.ui.JBColor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -31,7 +32,7 @@ import java.util.List;
abstract class FileTemplateTab {
protected final List<FileTemplateBase> myTemplates = new ArrayList<FileTemplateBase>();
private final String myTitle;
- protected static final Color MODIFIED_FOREGROUND = new Color(0, 0, 210);
+ protected static final Color MODIFIED_FOREGROUND = JBColor.BLUE;
protected FileTemplateTab(String title) {
myTitle = title;
diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplatesLoader.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplatesLoader.java
index 59c1ae95f391..2f9d057fee9c 100644
--- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplatesLoader.java
+++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplatesLoader.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 @@ public class FileTemplatesLoader {
private static final String TEMPLATES_DIR = "fileTemplates";
private static final String DEFAULT_TEMPLATES_ROOT = TEMPLATES_DIR;
public static final String DESCRIPTION_FILE_EXTENSION = "html";
- static final String DESCRIPTION_EXTENSION_SUFFIX = "." + DESCRIPTION_FILE_EXTENSION;
+ private static final String DESCRIPTION_EXTENSION_SUFFIX = "." + DESCRIPTION_FILE_EXTENSION;
//static final String DESCRIPTION_FILE_NAME = "default." + DESCRIPTION_FILE_EXTENSION;
private final FTManager myDefaultTemplatesManager;
@@ -63,6 +63,9 @@ public class FileTemplatesLoader {
private static final String ROOT_DIR = ".";
private final FileTypeManagerEx myTypeManager;
+ private URL myDefaultTemplateDescription;
+ private URL myDefaultIncludeDescription;
+
public FileTemplatesLoader(@NotNull FileTypeManagerEx typeManager) {
myTypeManager = typeManager;
myDefaultTemplatesManager = new FTManager(FileTemplateManager.DEFAULT_TEMPLATES_CATEGORY, ROOT_DIR);
@@ -116,6 +119,14 @@ public class FileTemplatesLoader {
return myJ2eeTemplatesManager;
}
+ public URL getDefaultTemplateDescription() {
+ return myDefaultTemplateDescription;
+ }
+
+ public URL getDefaultIncludeDescription() {
+ return myDefaultIncludeDescription;
+ }
+
private void loadDefaultTemplates() {
final Set<URL> processedUrls = new HashSet<URL>();
for (PluginDescriptor plugin : PluginManager.getPlugins()) {
@@ -151,7 +162,13 @@ public class FileTemplatesLoader {
}
final Set<String> descriptionPaths = new HashSet<String>();
for (String path : children) {
- if (path.endsWith(DESCRIPTION_EXTENSION_SUFFIX)) {
+ if (path.equals("default.html")) {
+ myDefaultTemplateDescription = UrlClassLoader.internProtocol(new URL(root.toExternalForm() + "/" + path));
+ }
+ else if (path.equals("includes/default.html")) {
+ myDefaultIncludeDescription = UrlClassLoader.internProtocol(new URL(root.toExternalForm() + "/" + path));
+ }
+ else if (path.endsWith(DESCRIPTION_EXTENSION_SUFFIX)) {
descriptionPaths.add(path);
}
}
@@ -176,7 +193,7 @@ public class FileTemplatesLoader {
private void loadCustomizedContent(FTManager manager) {
final File configRoot = manager.getConfigRoot(false);
- File[] configFiles = configRoot.listFiles();
+ final File[] configFiles = configRoot.listFiles();
if (configFiles == null) {
return;
}
diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java
index 90dfe7e5a81f..34c23d723574 100644
--- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java
+++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPSIPane.java
@@ -85,7 +85,7 @@ public abstract class AbstractProjectViewPSIPane extends AbstractProjectViewPane
@Override
public void uiSettingsChanged(UISettings source) {
- myTree.setRowHeight(-1);
+// myTree.setRowHeight(-1);
myTree.setFont(UIUtil.getTreeFont());
myTree.invalidate();
myTree.repaint();
diff --git a/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java b/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java
index 27a4f6bf085c..0c6d351e3f11 100644
--- a/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java
+++ b/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/StructureViewComponent.java
@@ -26,10 +26,7 @@ import com.intellij.ide.structureView.impl.StructureViewState;
import com.intellij.ide.structureView.impl.common.PsiTreeElementBase;
import com.intellij.ide.ui.customization.CustomizationUtil;
import com.intellij.ide.util.FileStructurePopup;
-import com.intellij.ide.util.treeView.AbstractTreeNode;
-import com.intellij.ide.util.treeView.AbstractTreeStructure;
-import com.intellij.ide.util.treeView.NodeDescriptorProvidingKey;
-import com.intellij.ide.util.treeView.NodeRenderer;
+import com.intellij.ide.util.treeView.*;
import com.intellij.ide.util.treeView.smartTree.*;
import com.intellij.ide.util.treeView.smartTree.TreeModel;
import com.intellij.openapi.Disposable;
@@ -51,14 +48,16 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.source.tree.CompositeElement;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.*;
-import com.intellij.ui.treeStructure.Tree;
import com.intellij.ui.treeStructure.actions.CollapseAllAction;
import com.intellij.ui.treeStructure.actions.ExpandAllAction;
+import com.intellij.ui.treeStructure.filtered.FilteringTreeStructure;
import com.intellij.util.Alarm;
import com.intellij.util.ArrayUtil;
import com.intellij.util.EditSourceOnDoubleClickHandler;
import com.intellij.util.OpenSourceUtil;
+import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Convertor;
+import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NonNls;
@@ -79,7 +78,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.structureView.newStructureView.StructureViewComponent");
@NonNls private static final String ourHelpID = "viewingStructure.fileStructureView";
- private StructureTreeBuilder myAbstractTreeBuilder;
+ private AbstractTreeBuilder myAbstractTreeBuilder;
private FileEditor myFileEditor;
private final TreeModelWrapper myTreeModelWrapper;
@@ -97,7 +96,6 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
private final Project myProject;
private final StructureViewModel myTreeModel;
private static int ourSettingsModificationCount;
- private Tree myTree;
public StructureViewComponent(FileEditor editor, StructureViewModel structureViewModel, Project project) {
this(editor, structureViewModel, project, true);
@@ -139,12 +137,12 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
};
final DefaultTreeModel model = new DefaultTreeModel(new DefaultMutableTreeNode(treeStructure.getRootElement()));
- myTree = new JBTreeWithHintProvider(model);
- myTree.setRootVisible(showRootNode);
- myTree.setShowsRootHandles(true);
+ JTree tree = new JBTreeWithHintProvider(model);
+ tree.setRootVisible(showRootNode);
+ tree.setShowsRootHandles(true);
- myAbstractTreeBuilder = new StructureTreeBuilder(project, myTree,
- (DefaultTreeModel)myTree.getModel(),treeStructure,myTreeModelWrapper) {
+ myAbstractTreeBuilder = new StructureTreeBuilder(project, tree,
+ (DefaultTreeModel)tree.getModel(),treeStructure,myTreeModelWrapper) {
@Override
protected boolean validateNode(Object child) {
return isValid(child);
@@ -244,41 +242,37 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
private static Object[] convertPathsToValues(TreePath[] selectionPaths) {
- if (selectionPaths != null) {
- List<Object> result = new ArrayList<Object>();
-
- for (TreePath selectionPath : selectionPaths) {
- final Object userObject = ((DefaultMutableTreeNode)selectionPath.getLastPathComponent()).getUserObject();
- if (userObject instanceof AbstractTreeNode) {
- Object value = ((AbstractTreeNode)userObject).getValue();
- if (value instanceof StructureViewTreeElement) {
- value = ((StructureViewTreeElement)value).getValue();
- }
- result.add(value);
- }
- }
- return ArrayUtil.toObjectArray(result);
- }
- else {
- return null;
+ if (selectionPaths == null) return null;
+ List<Object> result = new ArrayList<Object>();
+ for (TreePath selectionPath : selectionPaths) {
+ ContainerUtil.addIfNotNull(result, getNodeTreeValue((DefaultMutableTreeNode)selectionPath.getLastPathComponent()));
}
+ return ArrayUtil.toObjectArray(result);
}
@Nullable
private static Object[] convertPathsToTreeElements(TreePath[] selectionPaths) {
- if (selectionPaths != null) {
- Object[] result = new Object[selectionPaths.length];
-
- for (int i = 0; i < selectionPaths.length; i++) {
- Object userObject = ((DefaultMutableTreeNode)selectionPaths[i].getLastPathComponent()).getUserObject();
- if (!(userObject instanceof AbstractTreeNode)) return null;
- result[i] = ((AbstractTreeNode)userObject).getValue();
- }
- return result;
+ if (selectionPaths == null) return null;
+ List<Object> result = new ArrayList<Object>();
+ for (TreePath selectionPath : selectionPaths) {
+ ContainerUtil.addIfNotNull(result, getNodeValue((DefaultMutableTreeNode)selectionPath.getLastPathComponent()));
}
- else {
- return null;
+ return ArrayUtil.toObjectArray(result);
+ }
+
+ @Nullable
+ private static Object getNodeValue(DefaultMutableTreeNode mutableTreeNode) {
+ Object userObject = mutableTreeNode.getUserObject();
+ if (userObject instanceof FilteringTreeStructure.FilteringNode) {
+ userObject = ((FilteringTreeStructure.FilteringNode)userObject).getDelegate();
}
+ return userObject instanceof AbstractTreeNode ? ((AbstractTreeNode)userObject).getValue() : null;
+ }
+
+ @Nullable
+ private static Object getNodeTreeValue(DefaultMutableTreeNode mutableTreeNode) {
+ Object value = getNodeValue(mutableTreeNode);
+ return value instanceof StructureViewTreeElement ? ((StructureViewTreeElement)value).getValue() : null;
}
private void addTreeMouseListeners() {
@@ -596,28 +590,25 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
new Runnable() {
@Override
public void run() {
- if (myAbstractTreeBuilder == null) {
- return;
- }
- try {
- selectViewableElement();
- }
- catch (IndexNotReadyException ignore) {
- }
+ if (myAbstractTreeBuilder == null) return;
+ if (UIUtil.isFocusAncestor(StructureViewComponent.this)) return;
+ scrollToSelectedElementInner();
}
- }, 1000
- );
+ }, 1000);
}
- private void selectViewableElement() {
- PsiDocumentManager.getInstance(myProject).commitAllDocuments();
- final Object currentEditorElement = myTreeModel.getCurrentEditorElement();
- if (currentEditorElement != null) {
- select(currentEditorElement, false);
+ private void scrollToSelectedElementInner() {
+ try {
+ PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+ final Object currentEditorElement = myTreeModel.getCurrentEditorElement();
+ if (currentEditorElement != null) {
+ select(currentEditorElement, false);
+ }
+ }
+ catch (IndexNotReadyException ignore) {
}
}
-
@Override
public void dispose() {
LOG.assertTrue(EventQueue.isDispatchThread(), Thread.currentThread().getName());
@@ -634,10 +625,8 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
@Override
public void centerSelectedRow() {
TreePath path = getTree().getSelectionPath();
- if (path == null)
- {
- return;
- }
+ if (path == null) return;
+
myAutoScrollToSourceHandler.setShouldAutoScroll(false);
TreeUtil.showRowCentered(getTree(), getTree().getRowForPath(path), false);
myAutoScrollToSourceHandler.setShouldAutoScroll(true);
@@ -667,10 +656,18 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
return myAbstractTreeBuilder.getTreeStructure();
}
- public Tree getTree() {
- return myTree;
+ public JTree getTree() {
+ return myAbstractTreeBuilder.getTree();
}
+ public AbstractTreeBuilder getTreeBuilder() {
+ return myAbstractTreeBuilder;
+ }
+
+ //public void setTreeBuilder(AbstractTreeBuilder treeBuilder) {
+ // myAbstractTreeBuilder = treeBuilder;
+ //}
+
private final class MyAutoScrollToSourceHandler extends AutoScrollToSourceHandler {
private boolean myShouldAutoScroll = true;
@@ -742,7 +739,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
getSettings().AUTOSCROLL_FROM_SOURCE = state;
final FileEditor[] selectedEditors = FileEditorManager.getInstance(myProject).getSelectedEditors();
if (selectedEditors.length > 0 && state) {
- scrollToSelectedElement();
+ scrollToSelectedElementInner();
}
}
}
@@ -753,10 +750,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
TreePath path = getSelectedUniquePath();
if (path == null) return null;
DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
- Object userObject = node.getUserObject();
- if (!(userObject instanceof AbstractTreeNode)) return null;
- AbstractTreeNode descriptor = (AbstractTreeNode)userObject;
- Object element = descriptor.getValue();
+ Object element = getNodeValue(node);
if (element instanceof StructureViewTreeElement) {
element = ((StructureViewTreeElement)element).getValue();
}
@@ -831,7 +825,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
public void doUpdate() {
assert ApplicationManager.getApplication().isUnitTestMode();
- myAbstractTreeBuilder.addRootToUpdate();
+ myAbstractTreeBuilder.queueUpdate(true);
}
//todo [kirillk] dirty hack for discovering invalid psi elements, to delegate it to a proper place after 8.1
@@ -994,7 +988,7 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
@Override
public Dimension getCurrentSize() {
- return myTree.getSize();
+ return getTree().getSize();
}
@Override
@@ -1012,11 +1006,12 @@ public class StructureViewComponent extends SimpleToolWindowPanel implements Tre
}
private void _setRefSize(Dimension size) {
- myTree.setPreferredSize(size);
- myTree.setMinimumSize(size);
- myTree.setMaximumSize(size);
+ JTree tree = getTree();
+ tree.setPreferredSize(size);
+ tree.setMinimumSize(size);
+ tree.setMaximumSize(size);
- myTree.revalidate();
- myTree.repaint();
+ tree.revalidate();
+ tree.repaint();
}
}
diff --git a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java
index ef31e14c0550..d3186cf4d17e 100644
--- a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java
+++ b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java
@@ -20,8 +20,8 @@ import com.intellij.ide.DataManager;
import com.intellij.ide.DefaultTreeExpander;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.TreeExpander;
+import com.intellij.ide.structureView.ModelListener;
import com.intellij.ide.structureView.StructureView;
-import com.intellij.ide.structureView.StructureViewBuilder;
import com.intellij.ide.structureView.StructureViewModel;
import com.intellij.ide.structureView.StructureViewTreeElement;
import com.intellij.ide.structureView.impl.StructureViewComposite;
@@ -40,9 +40,8 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.fileEditor.FileEditor;
-import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.Project;
@@ -51,12 +50,10 @@ import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiManager;
import com.intellij.ui.*;
import com.intellij.ui.popup.AbstractPopup;
import com.intellij.ui.popup.PopupUpdateProcessor;
@@ -96,7 +93,6 @@ import java.util.List;
*/
public class FileStructurePopup implements Disposable {
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.FileStructurePopup");
- private final Editor myEditor;
private final Project myProject;
private final StructureViewModel myTreeModel;
private final StructureViewModel myBaseTreeModel;
@@ -121,53 +117,49 @@ public class FileStructurePopup implements Disposable {
private boolean myInitialNodeIsLeaf;
private final List<Pair<String, JCheckBox>> myTriggeredCheckboxes = new ArrayList<Pair<String, JCheckBox>>();
private final TreeExpander myTreeExpander;
- private StructureView myStructureView;
+ @NotNull private final FileEditor myFileEditor;
+ private final StructureView myStructureViewDelegate;
- public FileStructurePopup(StructureViewModel structureViewModel,
- @Nullable Editor editor,
- Project project,
- @NotNull final Disposable auxDisposable,
+ public FileStructurePopup(@NotNull Project project,
+ @NotNull FileEditor fileEditor,
+ @NotNull StructureView structureView,
final boolean applySortAndFilter) {
myProject = project;
- myEditor = editor;
+ myFileEditor = fileEditor;
+ myStructureViewDelegate = structureView;
//Stop code analyzer to speedup EDT
DaemonCodeAnalyzer.getInstance(myProject).disableUpdateByTimer(this);
IdeFocusManager.getInstance(myProject).typeAheadUntil(myTreeHasBuilt);
+ Disposer.register(this, myStructureViewDelegate);
//long l = System.currentTimeMillis();
- if (editor instanceof EditorImpl) {
- VirtualFile file = ((EditorImpl)editor).getVirtualFile();
- FileEditor fileEditor = FileEditorManager.getInstance(myProject).getSelectedEditor(file);
- if (fileEditor != null) {
- StructureViewBuilder builder = fileEditor.getStructureViewBuilder();
- myPsiFile = PsiManager.getInstance(project).findFile(file);
- if (builder != null && myPsiFile != null) {
- myStructureView = builder.createStructureView(fileEditor, project);
- Disposer.register(this, myStructureView);
- }
- }
+ if (myFileEditor instanceof TextEditor) {
+ Editor e = ((TextEditor)myFileEditor).getEditor();
+ myPsiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(e.getDocument());
}
+
//System.out.println(System.currentTimeMillis() - l);
- if (myStructureView instanceof StructureViewComposite) {
- StructureViewComposite.StructureViewDescriptor[] views = ((StructureViewComposite)myStructureView).getStructureViews();
+ if (myStructureViewDelegate instanceof StructureViewComposite) {
+ StructureViewComposite.StructureViewDescriptor[] views = ((StructureViewComposite)myStructureViewDelegate).getStructureViews();
myBaseTreeModel = new StructureViewCompositeModel(myPsiFile, views);
Disposer.register(this, (Disposable)myBaseTreeModel);
- } else {
- myBaseTreeModel = structureViewModel;
}
- Disposer.register(this, auxDisposable);
+ else {
+ myBaseTreeModel = myStructureViewDelegate.getTreeModel();
+ }
+
if (applySortAndFilter) {
myTreeActionsOwner = new TreeStructureActionsOwner(myBaseTreeModel);
myTreeModel = new TreeModelWrapper(myBaseTreeModel, myTreeActionsOwner);
}
else {
myTreeActionsOwner = null;
- myTreeModel = structureViewModel;
+ myTreeModel = myStructureViewDelegate.getTreeModel();
}
- myTreeStructure = new SmartTreeStructure(project, myTreeModel){
+ myTreeStructure = new SmartTreeStructure(project, myTreeModel) {
@Override
public void rebuildTree() {
if (ApplicationManager.getApplication().isUnitTestMode() || !myPopup.isDisposed()) {
@@ -200,9 +192,10 @@ public class FileStructurePopup implements Disposable {
@NotNull SimpleTextAttributes attributes,
boolean isMainText,
boolean selected) {
- if (!isMainText ) {
+ if (!isMainText) {
super.doAppend(fragment, attributes, isMainText, selected);
- } else {
+ }
+ else {
SpeedSearchUtil.appendFragmentsForSpeedSearch(myTree, fragment, attributes, selected, this);
}
}
@@ -247,10 +240,23 @@ public class FileStructurePopup implements Disposable {
};
myTreeExpander = new DefaultTreeExpander(myTree);
+ final ModelListener modelListener = new ModelListener() {
+ @Override
+ public void onModelChanged() {
+ myAbstractTreeBuilder.queueUpdate();
+ }
+ };
+ myTreeModel.addModelListener(modelListener);
+ Disposer.register(this, new Disposable() {
+ @Override
+ public void dispose() {
+ myTreeModel.removeModelListener(modelListener);
+ }
+ });
//myAbstractTreeBuilder.getUi().setPassthroughMode(true);
myAbstractTreeBuilder.getUi().getUpdater().setDelay(1);
- myInitialPsiElement = getCurrentElement(getPsiFile(myProject));
+ myInitialPsiElement = getCurrentElement(myPsiFile);
//myAbstractTreeBuilder.setCanYieldUpdate(true);
Disposer.register(this, myAbstractTreeBuilder);
TreeUtil.installActions(myTree);
@@ -304,9 +310,10 @@ public class FileStructurePopup implements Disposable {
});
myTree.getEmptyText().setText("Loading...");
final Point location = DimensionService.getInstance().getLocation(getDimensionServiceKey(), myProject);
- if (location != null && myEditor != null) {
- myPopup.showInScreenCoordinates(myEditor.getContentComponent(), location);
- } else {
+ if (location != null) {
+ myPopup.showInScreenCoordinates(myFileEditor.getComponent(), location);
+ }
+ else {
myPopup.showCenteredInCurrentWindow(myProject);
}
@@ -436,7 +443,7 @@ public class FileStructurePopup implements Disposable {
Set<PsiElement> parents = getAllParents(element);
FilteringTreeStructure.FilteringNode node = (FilteringTreeStructure.FilteringNode)myAbstractTreeBuilder.getRootElement();
- if (element != null && node != null && myStructureView instanceof StructureViewComposite) {
+ if (element != null && node != null && myStructureViewDelegate instanceof StructureViewComposite) {
parents.remove(element.getContainingFile());
final List<FilteringTreeStructure.FilteringNode> fileNodes = node.children();
@@ -446,7 +453,8 @@ public class FileStructurePopup implements Disposable {
return found;
}
}
- } else {
+ }
+ else {
final FilteringTreeStructure.FilteringNode found = findNode(parents, node);
if (found == null) {
TreeUtil.ensureSelection(myTree);
@@ -506,11 +514,6 @@ public class FileStructurePopup implements Disposable {
return null;
}
- @Nullable
- protected PsiFile getPsiFile(final Project project) {
- return myEditor == null ? null : PsiDocumentManager.getInstance(project).getPsiFile(myEditor.getDocument());
- }
-
@Override
public void dispose() {
@@ -523,8 +526,6 @@ public class FileStructurePopup implements Disposable {
@Nullable
public PsiElement getCurrentElement(@Nullable final PsiFile psiFile) {
- if (psiFile == null) return null;
-
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
Object elementAtCursor = myTreeModel.getCurrentEditorElement();
@@ -532,8 +533,8 @@ public class FileStructurePopup implements Disposable {
return (PsiElement)elementAtCursor;
}
- if (myEditor != null) {
- return psiFile.getViewProvider().findElementAt(myEditor.getCaretModel().getOffset());
+ if (psiFile != null && myFileEditor instanceof TextEditor) {
+ return psiFile.getViewProvider().findElementAt(((TextEditor)myFileEditor).getEditor().getCaretModel().getOffset());
}
return null;
@@ -543,7 +544,7 @@ public class FileStructurePopup implements Disposable {
List<FileStructureFilter> fileStructureFilters = new ArrayList<FileStructureFilter>();
List<FileStructureNodeProvider> fileStructureNodeProviders = new ArrayList<FileStructureNodeProvider>();
if (myTreeActionsOwner != null) {
- for(Filter filter: myBaseTreeModel.getFilters()) {
+ for (Filter filter : myBaseTreeModel.getFilters()) {
if (filter instanceof FileStructureFilter) {
final FileStructureFilter fsFilter = (FileStructureFilter)filter;
myTreeActionsOwner.setActionIncluded(fsFilter, true);
@@ -580,7 +581,8 @@ public class FileStructurePopup implements Disposable {
public void actionPerformed(AnActionEvent e) {
if (mySpeedSearch != null && mySpeedSearch.isPopupActive()) {
mySpeedSearch.hidePopup();
- } else {
+ }
+ else {
myPopup.cancel();
}
}
@@ -596,7 +598,7 @@ public class FileStructurePopup implements Disposable {
}
}.installOn(myTree);
- for(FileStructureFilter filter: fileStructureFilters) {
+ for (FileStructureFilter filter : fileStructureFilters) {
addCheckbox(comboPanel, filter);
}
@@ -612,14 +614,27 @@ public class FileStructurePopup implements Disposable {
DataManager.registerDataProvider(panel, new DataProvider() {
@Override
public Object getData(@NonNls String dataId) {
- if (PlatformDataKeys.PROJECT.is(dataId)) {
+ if (CommonDataKeys.PROJECT.is(dataId)) {
return myProject;
}
+ if (PlatformDataKeys.FILE_EDITOR.is(dataId)) {
+ return myFileEditor;
+ }
if (CommonDataKeys.PSI_ELEMENT.is(dataId)) {
- final Object node = ContainerUtil.getFirstItem(myAbstractTreeBuilder.getSelectedElements());
+ Object node = ContainerUtil.getFirstItem(myAbstractTreeBuilder.getSelectedElements());
if (!(node instanceof FilteringTreeStructure.FilteringNode)) return null;
return getPsi((FilteringTreeStructure.FilteringNode)node);
}
+ if (LangDataKeys.PSI_ELEMENT_ARRAY.is(dataId)) {
+ Set<Object> nodes = myAbstractTreeBuilder.getSelectedElements();
+ if (nodes.isEmpty()) return PsiElement.EMPTY_ARRAY;
+ ArrayList<PsiElement> result = new ArrayList<PsiElement>();
+ for (Object o : nodes) {
+ if (!(o instanceof FilteringTreeStructure.FilteringNode)) continue;
+ ContainerUtil.addIfNotNull(result, getPsi((FilteringTreeStructure.FilteringNode)o));
+ }
+ return ContainerUtil.toArray(result, PsiElement.ARRAY_FACTORY);
+ }
if (LangDataKeys.POSITION_ADJUSTER_POPUP.is(dataId)) {
return myPopup;
}
@@ -722,8 +737,7 @@ public class FileStructurePopup implements Disposable {
if (text == null) return;
Shortcut[] shortcuts = action instanceof FileStructureFilter ?
- ((FileStructureFilter)action).getShortcut() : ((FileStructureNodeProvider)action).getShortcut();
-
+ ((FileStructureFilter)action).getShortcut() : ((FileStructureNodeProvider)action).getShortcut();
final JCheckBox chkFilter = new JCheckBox();
@@ -770,7 +784,8 @@ public class FileStructurePopup implements Disposable {
};
if (ApplicationManager.getApplication().isUnitTestMode()) {
runnable.run();
- } else {
+ }
+ else {
ApplicationManager.getApplication().invokeLater(runnable);
}
}
@@ -911,10 +926,10 @@ public class FileStructurePopup implements Disposable {
myVisibleParents.add(o);
}
return true;
- } else {
+ }
+ else {
return false;
}
-
}
return true;
}
@@ -926,7 +941,6 @@ public class FileStructurePopup implements Disposable {
}
return mySpeedSearch.matchingFragments(text) != null;
}
-
}
@Nullable
@@ -934,7 +948,7 @@ public class FileStructurePopup implements Disposable {
if (ApplicationManager.getApplication().isUnitTestMode()) return myTestSearchFilter;
return mySpeedSearch != null && !StringUtil.isEmpty(mySpeedSearch.getEnteredPrefix())
- ? mySpeedSearch.getEnteredPrefix() : null;
+ ? mySpeedSearch.getEnteredPrefix() : null;
}
public class MyTreeSpeedSearch extends TreeSpeedSearch {
@@ -997,7 +1011,8 @@ public class FileStructurePopup implements Disposable {
max = size;
cur.clear();
cur.add(p);
- } else if (size == max) {
+ }
+ else if (size == max) {
cur.add(p);
}
}
@@ -1013,7 +1028,6 @@ public class FileStructurePopup implements Disposable {
});
return cur.isEmpty() ? null : cur.get(0).node;
}
-
}
class FileStructureTree extends JBTreeWithHintProvider implements AlwaysExpandedTree {
@@ -1038,7 +1052,8 @@ public class FileStructurePopup implements Disposable {
newValueIsSet = false;
}
fast = newValueIsSet;
- } else {
+ }
+ else {
fast = false;
}
diff --git a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorPsiDataProvider.java b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorPsiDataProvider.java
index be2b52ec1706..1f911936637a 100644
--- a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorPsiDataProvider.java
+++ b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/TextEditorPsiDataProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -29,7 +29,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
-import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.psi.util.PsiUtilCore;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -132,7 +132,7 @@ public class TextEditorPsiDataProvider implements EditorDataProvider {
return getLanguageAtOffset(psiFile, mostProbablyCorrectLanguageOffset, selectionModel.getSelectionEnd());
}
- return PsiUtilBase.getLanguageAtOffset(psiFile, mostProbablyCorrectLanguageOffset);
+ return PsiUtilCore.getLanguageAtOffset(psiFile, mostProbablyCorrectLanguageOffset);
}
private static Language getLanguageAtOffset(PsiFile psiFile, int mostProbablyCorrectLanguageOffset, int end) {
@@ -144,7 +144,7 @@ public class TextEditorPsiDataProvider implements EditorDataProvider {
return getLanguageAtOffset(psiFile, incremented, end);
}
}
- return PsiUtilBase.findLanguageFromElement(elt);
+ return PsiUtilCore.findLanguageFromElement(elt);
}
@Nullable
diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/CommonContentEntriesEditor.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/CommonContentEntriesEditor.java
index 669d08e6796a..b7583d05ffdb 100644
--- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/CommonContentEntriesEditor.java
+++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/CommonContentEntriesEditor.java
@@ -163,6 +163,7 @@ public class CommonContentEntriesEditor extends ModuleElementsEditor {
entriesPanel.add(new ToolbarPanel(myScrollPane, group), BorderLayout.CENTER);
final Splitter splitter = new Splitter(false);
+ splitter.setProportion(0.4f);
splitter.setHonorComponentsMinimumSize(true);
mainPanel.add(splitter, BorderLayout.CENTER);
diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/JavaTestSourceRootEditHandler.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/JavaTestSourceRootEditHandler.java
index f62f3a4ae202..2cdcbc42de55 100644
--- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/JavaTestSourceRootEditHandler.java
+++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/JavaTestSourceRootEditHandler.java
@@ -18,6 +18,7 @@ package com.intellij.openapi.roots.ui.configuration;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.CustomShortcutSet;
import com.intellij.openapi.project.ProjectBundle;
+import com.intellij.ui.JBColor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.java.JavaSourceRootType;
@@ -31,7 +32,7 @@ import java.awt.event.KeyEvent;
* @author nik
*/
public class JavaTestSourceRootEditHandler extends JavaSourceRootEditHandlerBase {
- private static final Color TESTS_COLOR = new Color(0x008C2E);
+ private static final Color TESTS_COLOR = new JBColor(new Color(0x008C2E), new Color(73, 140, 101));
public JavaTestSourceRootEditHandler() {
super(JavaSourceRootType.TEST_SOURCE);
diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/DocumentBasedFormattingModel.java b/platform/lang-impl/src/com/intellij/psi/formatter/DocumentBasedFormattingModel.java
index 73acc4f69780..403324cf3171 100644
--- a/platform/lang-impl/src/com/intellij/psi/formatter/DocumentBasedFormattingModel.java
+++ b/platform/lang-impl/src/com/intellij/psi/formatter/DocumentBasedFormattingModel.java
@@ -39,14 +39,14 @@ import org.jetbrains.annotations.Nullable;
public class DocumentBasedFormattingModel implements FormattingModel {
private final Block myRootBlock;
private final FormattingDocumentModel myDocumentModel;
- private final Document myDocument;
+ @NotNull private final Document myDocument;
private final Project myProject;
private final CodeStyleSettings mySettings;
private final FileType myFileType;
private final PsiFile myFile;
public DocumentBasedFormattingModel(final Block rootBlock,
- final Document document,
+ @NotNull final Document document,
final Project project,
final CodeStyleSettings settings,
final FileType fileType,
@@ -221,6 +221,7 @@ public class DocumentBasedFormattingModel implements FormattingModel {
return mySettings.getIndentOptions(myFileType);
}
+ @NotNull
public Document getDocument() {
return myDocument;
}
diff --git a/platform/lang-impl/src/com/intellij/psi/formatter/FormattingDocumentModelImpl.java b/platform/lang-impl/src/com/intellij/psi/formatter/FormattingDocumentModelImpl.java
index 2bab927fbba9..77507a6c6abd 100644
--- a/platform/lang-impl/src/com/intellij/psi/formatter/FormattingDocumentModelImpl.java
+++ b/platform/lang-impl/src/com/intellij/psi/formatter/FormattingDocumentModelImpl.java
@@ -38,13 +38,13 @@ public class FormattingDocumentModelImpl implements FormattingDocumentModel {
private final WhiteSpaceFormattingStrategy myWhiteSpaceStrategy;
//private final CharBuffer myBuffer = CharBuffer.allocate(1);
- private final Document myDocument;
+ @NotNull private final Document myDocument;
private final PsiFile myFile;
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.formatter.FormattingDocumentModelImpl");
private final CodeStyleSettings mySettings;
- public FormattingDocumentModelImpl(final Document document, PsiFile file) {
+ public FormattingDocumentModelImpl(@NotNull final Document document, PsiFile file) {
myDocument = document;
myFile = file;
if (file != null) {
@@ -117,6 +117,7 @@ public class FormattingDocumentModelImpl implements FormattingDocumentModel {
return myDocument.getTextLength();
}
+ @NotNull
@Override
public Document getDocument() {
return myDocument;
diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java
index 8ebc3aadbe07..a8bdbae7ea2f 100644
--- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java
+++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java
@@ -175,6 +175,7 @@ public class CodeFormatterFacade {
if (builder != null) {
if (file.getTextLength() > 0) {
+ LOG.assertTrue(document != null);
try {
final PsiElement startElement = file.findElementAt(textRanges.get(0).getTextRange().getStartOffset());
final PsiElement endElement = file.findElementAt(textRanges.get(textRanges.size() - 1).getTextRange().getEndOffset() - 1);
diff --git a/platform/lang-impl/src/com/intellij/refactoring/extractMethod/SimpleDuplicatesFinder.java b/platform/lang-impl/src/com/intellij/refactoring/extractMethod/SimpleDuplicatesFinder.java
index 6c067e5ee0a6..7197eb646f17 100644
--- a/platform/lang-impl/src/com/intellij/refactoring/extractMethod/SimpleDuplicatesFinder.java
+++ b/platform/lang-impl/src/com/intellij/refactoring/extractMethod/SimpleDuplicatesFinder.java
@@ -127,7 +127,10 @@ public class SimpleDuplicatesFinder {
if (pattern == null || candidate == null) return pattern == candidate;
final PsiElement[] children1 = PsiEquivalenceUtil.getFilteredChildren(pattern, null, true);
final PsiElement[] children2 = PsiEquivalenceUtil.getFilteredChildren(candidate, null, true);
- if (pattern.getUserData(PARAMETER) != null && pattern.getParent().getClass() == candidate.getParent().getClass()) {
+ final PsiElement patternParent = pattern.getParent();
+ final PsiElement candidateParent = candidate.getParent();
+ if (patternParent == null || candidateParent == null) return false;
+ if (pattern.getUserData(PARAMETER) != null && patternParent.getClass() == candidateParent.getClass()) {
match.changeParameter(pattern.getText(), candidate.getText());
return true;
}
@@ -140,7 +143,7 @@ public class SimpleDuplicatesFinder {
}
if (children1.length == 0) {
- if (pattern.getUserData(PARAMETER) != null && pattern.getParent().getClass() == candidate.getParent().getClass()) {
+ if (pattern.getUserData(PARAMETER) != null && patternParent.getClass() == candidateParent.getClass()) {
match.changeParameter(pattern.getText(), candidate.getText());
return true;
}
diff --git a/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesHandler.java b/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesHandler.java
index a7812f880484..66505d903dbf 100644
--- a/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesHandler.java
+++ b/platform/lang-impl/src/com/intellij/refactoring/move/moveFilesOrDirectories/MoveFilesOrDirectoriesHandler.java
@@ -75,7 +75,7 @@ public class MoveFilesOrDirectoriesHandler extends MoveHandlerDelegate {
@Override
public void doMove(final Project project, final PsiElement[] elements, final PsiElement targetContainer, @Nullable final MoveCallback callback) {
if (!LOG.assertTrue(targetContainer == null || targetContainer instanceof PsiDirectory || targetContainer instanceof PsiDirectoryContainer,
- "container: " + targetContainer + "; elements: " + Arrays.toString(elements))) {
+ "container: " + targetContainer + "; elements: " + Arrays.toString(elements) + "; working handler: " + toString())) {
return;
}
MoveFilesOrDirectoriesUtil.doMove(project, adjustForMove(project, elements, targetContainer), new PsiElement[] {targetContainer}, callback);
diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java
index 1ff57760a628..33f23494b341 100644
--- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java
+++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java
@@ -61,6 +61,7 @@ import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.*;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
+import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.ProjectScope;
@@ -530,6 +531,18 @@ public abstract class InplaceRefactoring {
final PsiReference reference = (myEditorFile != null ?
myEditorFile : myElementToRename.getContainingFile())
.findReferenceAt(myEditor.getCaretModel().getOffset());
+ if (reference instanceof PsiMultiReference) {
+ final PsiReference[] references = ((PsiMultiReference)reference).getReferences();
+ for (PsiReference ref : references) {
+ addReferenceIfNeeded(refs, ref);
+ }
+ }
+ else {
+ addReferenceIfNeeded(refs, reference);
+ }
+ }
+
+ private void addReferenceIfNeeded(@NotNull final Collection<PsiReference> refs, @Nullable final PsiReference reference) {
if (reference != null && reference.isReferenceTo(myElementToRename) && !refs.contains(reference)) {
refs.add(reference);
}
diff --git a/platform/lang-impl/src/com/intellij/ui/tabs/FileColorConfigurationEditDialog.java b/platform/lang-impl/src/com/intellij/ui/tabs/FileColorConfigurationEditDialog.java
index c099253fb247..24d886cfb548 100644
--- a/platform/lang-impl/src/com/intellij/ui/tabs/FileColorConfigurationEditDialog.java
+++ b/platform/lang-impl/src/com/intellij/ui/tabs/FileColorConfigurationEditDialog.java
@@ -54,7 +54,7 @@ public class FileColorConfigurationEditDialog extends DialogWrapper {
public FileColorConfigurationEditDialog(@NotNull final FileColorManager manager, @Nullable final FileColorConfiguration configuration) {
super(true);
- setTitle(configuration == null ? "Add color label" : "Edit color label");
+ setTitle(configuration == null ? "Add Color Label" : "Edit Color Label");
setResizable(false);
myManager = manager;
diff --git a/platform/lang-impl/src/com/intellij/util/ui/classpath/SimpleClasspathElementFactory.java b/platform/lang-impl/src/com/intellij/util/ui/classpath/SimpleClasspathElementFactory.java
index 9f45e024501a..28e4fa85011e 100644
--- a/platform/lang-impl/src/com/intellij/util/ui/classpath/SimpleClasspathElementFactory.java
+++ b/platform/lang-impl/src/com/intellij/util/ui/classpath/SimpleClasspathElementFactory.java
@@ -7,11 +7,13 @@ import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileManager;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -68,4 +70,20 @@ public class SimpleClasspathElementFactory {
}
return list;
}
+
+ public static List<VirtualFile> convertToFiles(Collection<SimpleClasspathElement> cpeList)
+ {
+ VirtualFileManager fileManager = VirtualFileManager.getInstance();
+ List<VirtualFile> files = new ArrayList<VirtualFile>();
+ for (SimpleClasspathElement cpe : cpeList) {
+ for (String fileUrl : cpe.getClassesRootUrls()) {
+ VirtualFile file = fileManager.findFileByUrl(fileUrl);
+ if (file != null) {
+ files.add(file);
+ }
+ }
+ }
+ return files;
+ }
+
}
diff --git a/platform/platform-api/src/com/intellij/openapi/application/ApplicationInfo.java b/platform/platform-api/src/com/intellij/openapi/application/ApplicationInfo.java
index 6fb51704318c..4661dbda9e72 100644
--- a/platform/platform-api/src/com/intellij/openapi/application/ApplicationInfo.java
+++ b/platform/platform-api/src/com/intellij/openapi/application/ApplicationInfo.java
@@ -32,6 +32,7 @@ public abstract class ApplicationInfo {
}
public abstract BuildNumber getBuild();
+ public abstract String getApiVersion();
public abstract String getMajorVersion();
public abstract String getMinorVersion();
diff --git a/platform/platform-api/src/com/intellij/openapi/ui/MessageType.java b/platform/platform-api/src/com/intellij/openapi/ui/MessageType.java
index f3343a27f605..a9d4ca3f20d7 100644
--- a/platform/platform-api/src/com/intellij/openapi/ui/MessageType.java
+++ b/platform/platform-api/src/com/intellij/openapi/ui/MessageType.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.
@@ -25,11 +25,11 @@ import java.awt.*;
public class MessageType {
public static final MessageType ERROR = new MessageType(UIUtil.getBalloonErrorIcon(),
- new JBColor(new Color(255, 204, 204, 230), new Color(0x70383a)));
+ new JBColor(new Color(255, 204, 204, 230), new Color(112, 71, 69)));
public static final MessageType INFO = new MessageType(UIUtil.getBalloonInformationIcon(),
- new JBColor(new Color(186, 238, 186, 230), new Color(0x356936)));
+ new JBColor(new Color(186, 238, 186, 230), new Color(73, 117, 73)));
public static final MessageType WARNING = new MessageType(UIUtil.getBalloonWarningIcon(),
- new JBColor(new Color(249, 247, 142, 230), new Color(0x5C5C42)));
+ new JBColor(new Color(249, 247, 142, 230), new Color(128, 125, 75)));
private final Icon myDefaultIcon;
private final Color myPopupBackground;
diff --git a/platform/platform-api/src/com/intellij/openapi/vfs/VfsUtil.java b/platform/platform-api/src/com/intellij/openapi/vfs/VfsUtil.java
index 7bc02081df30..d9f435594bbb 100644
--- a/platform/platform-api/src/com/intellij/openapi/vfs/VfsUtil.java
+++ b/platform/platform-api/src/com/intellij/openapi/vfs/VfsUtil.java
@@ -567,28 +567,6 @@ public class VfsUtil extends VfsUtilCore {
});
}
- public static void processFilesRecursively(@NotNull VirtualFile root, @NotNull Processor<VirtualFile> processor,
- @NotNull Convertor<VirtualFile, Boolean> directoryFilter) {
- if (!processor.process(root)) return;
-
- if (root.isDirectory() && directoryFilter.convert(root)) {
- final LinkedList<VirtualFile[]> queue = new LinkedList<VirtualFile[]>();
-
- queue.add(root.getChildren());
-
- do {
- final VirtualFile[] files = queue.removeFirst();
-
- for (VirtualFile file : files) {
- if (!processor.process(file)) return;
- if (file.isDirectory() && directoryFilter.convert(file)) {
- queue.add(file.getChildren());
- }
- }
- } while (!queue.isEmpty());
- }
- }
-
@Nullable
public static <T> T processInputStream(@NotNull final VirtualFile file, @NotNull Function<InputStream, T> function) {
InputStream stream = null;
@@ -598,7 +576,8 @@ public class VfsUtil extends VfsUtilCore {
}
catch (IOException e) {
LOG.error(e);
- } finally {
+ }
+ finally {
try {
if (stream != null) {
stream.close();
diff --git a/platform/platform-api/src/com/intellij/ui/CheckedTreeNode.java b/platform/platform-api/src/com/intellij/ui/CheckedTreeNode.java
index 69b4aaa7e14e..a7cfb7162fa9 100644
--- a/platform/platform-api/src/com/intellij/ui/CheckedTreeNode.java
+++ b/platform/platform-api/src/com/intellij/ui/CheckedTreeNode.java
@@ -26,6 +26,10 @@ import javax.swing.tree.DefaultMutableTreeNode;
public class CheckedTreeNode extends DefaultMutableTreeNode {
protected boolean isChecked = true;
private boolean isEnabled = true;
+
+ public CheckedTreeNode() {
+ }
+
public CheckedTreeNode(Object userObject) {
super(userObject);
}
diff --git a/platform/platform-api/src/com/intellij/ui/SearchTextField.java b/platform/platform-api/src/com/intellij/ui/SearchTextField.java
index ad153fe7a479..8603393f1e9b 100644
--- a/platform/platform-api/src/com/intellij/ui/SearchTextField.java
+++ b/platform/platform-api/src/com/intellij/ui/SearchTextField.java
@@ -110,7 +110,7 @@ public class SearchTextField extends JPanel {
}
});
- if (hasNativeLeopardSearchControl() || UIUtil.isUnderDarcula()) {
+ if (hasNativeLeopardSearchControl() || UIUtil.isUnderDarcula() || UIUtil.isUnderIntelliJLaF()) {
myTextField.putClientProperty("JTextField.variant", "search");
}
if (hasNativeLeopardSearchControl()) {
@@ -204,7 +204,7 @@ public class SearchTextField extends JPanel {
}
private static boolean hasNativeLeopardSearchControl() {
- return (SystemInfo.isMacOSLeopard && UIUtil.isUnderAquaLookAndFeel()) || UIUtil.isUnderDarcula();
+ return (SystemInfo.isMacOSLeopard && UIUtil.isUnderAquaLookAndFeel()) || UIUtil.isUnderDarcula() || UIUtil.isUnderIntelliJLaF();
}
private static boolean hasIconsOutsideOfTextField() {
diff --git a/platform/platform-api/src/com/intellij/ui/components/OnOffButton.java b/platform/platform-api/src/com/intellij/ui/components/OnOffButton.java
index c09a66991aad..7ee0ab9207eb 100644
--- a/platform/platform-api/src/com/intellij/ui/components/OnOffButton.java
+++ b/platform/platform-api/src/com/intellij/ui/components/OnOffButton.java
@@ -16,6 +16,7 @@
package com.intellij.ui.components;
import com.intellij.ui.Gray;
+import com.intellij.ui.JBColor;
import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.UIUtil;
@@ -78,7 +79,7 @@ public class OnOffButton extends JToggleButton {
int w = fm.stringWidth(text);
int h = fm.getHeight();
h += 2*4;
- w += 3 * h / 2 + 4;
+ w += 3 * h / 2;
return new Dimension(w, h);
}
@Override
@@ -94,11 +95,11 @@ public class OnOffButton extends JToggleButton {
GraphicsUtil.setupAAPainting(g);
g.translate(1,1);
if (button.isSelected()) {
- g.setColor(new Color(13, 41, 62));
+ g.setColor(new JBColor(new Color(57, 113, 238), new Color(13, 41, 62)));
g.fillRoundRect(0, 0, w, h, h, h);
g.setColor(UIUtil.getBorderColor());
g.drawRoundRect(0, 0, w, h, h, h);
- g.setColor(Gray._128);
+ g.setColor(new JBColor(Gray._220, Gray._128));
g.fillOval(w - h + 1, 1, h - 1, h - 1);
g.setColor(UIUtil.getListForeground(true));
g.drawString(button.getOnText(), h/2, h - 4);
diff --git a/platform/platform-api/src/com/intellij/util/MixinEP.java b/platform/platform-api/src/com/intellij/util/MixinEP.java
index 6a8032641d3c..406ec2865807 100644
--- a/platform/platform-api/src/com/intellij/util/MixinEP.java
+++ b/platform/platform-api/src/com/intellij/util/MixinEP.java
@@ -15,6 +15,7 @@
*/
package com.intellij.util;
+import com.intellij.diagnostic.PluginException;
import com.intellij.openapi.extensions.AbstractExtensionPointBean;
import com.intellij.openapi.util.LazyInstance;
import com.intellij.openapi.util.NotNullLazyValue;
@@ -36,6 +37,13 @@ public class MixinEP<T> extends AbstractExtensionPointBean {
private final NotNullLazyValue<Class> myKey = new NotNullLazyValue<Class>() {
@NotNull
protected Class compute() {
+ if (key == null) {
+ String error = "No key specified for mixin with implementation class " + implementationClass;
+ if (myPluginDescriptor != null) {
+ throw new PluginException(error, myPluginDescriptor.getPluginId());
+ }
+ throw new IllegalArgumentException(error);
+ }
try {
return findClass(key);
}
diff --git a/platform/platform-impl/src/com/intellij/concurrency/ApplierCompleter.java b/platform/platform-impl/src/com/intellij/concurrency/ApplierCompleter.java
new file mode 100644
index 000000000000..1644e54df8b1
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/concurrency/ApplierCompleter.java
@@ -0,0 +1,231 @@
+/*
+ * 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.concurrency;
+
+import com.intellij.openapi.application.ex.ApplicationManagerEx;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.util.Processor;
+import jsr166e.CountedCompleter;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Executes processor on array elements in range from lo (inclusive) to hi (exclusive).
+ * To do this it starts executing processor on first array items and, if it takes too much time, splits the work and forks the right half.
+ * The series of splits lead to linked list of forked sub tasks, each of which is a CountedCompleter of its own,
+ * having this task as its parent.
+ * After the first pass on the array, this task attempts to steal work from the recently forked off sub tasks,
+ * by traversing the linked subtasks list, unforking each subtask and calling execAndForkSubTasks() on each recursively.
+ * After that, the task completes itself.
+ * The process of completing traverses task parent hierarchy, decrementing each pending count until it either
+ * decrements not-zero pending count and stops or
+ * reaches the top, in which case it invokes {@link jsr166e.ForkJoinTask#quietlyComplete()} which causes the top level task to wake up and join successfully.
+ * The exceptions from the sub tasks bubble up to the top and saved in {@link #throwable}.
+ */
+public class ApplierCompleter extends CountedCompleter<Void> {
+ private final boolean runInReadAction;
+ private final ProgressIndicator progressIndicator;
+ @NotNull
+ private final List array;
+ @NotNull
+ private final Processor processor;
+ private final int lo;
+ private final int hi;
+ private final ApplierCompleter next; // keeps track of right-hand-side tasks
+ volatile Throwable throwable;
+
+ // if not null, the read action has failed and this list contains unfinished subtasks
+ private List<ApplierCompleter> failedSubTasks;
+
+ //private final List<ApplierCompleter> children = new ArrayList<ApplierCompleter>();
+
+ ApplierCompleter(ApplierCompleter parent,
+ boolean runInReadAction,
+ @NotNull ProgressIndicator progressIndicator,
+ @NotNull List array,
+ @NotNull Processor processor,
+ int lo,
+ int hi,
+ ApplierCompleter next) {
+ super(parent);
+ this.runInReadAction = runInReadAction;
+ this.progressIndicator = progressIndicator;
+ this.array = array;
+ this.processor = processor;
+ this.lo = lo;
+ this.hi = hi;
+ this.next = next;
+ }
+
+ @Override
+ public void compute() {
+ compute(new Runnable() {
+ @Override
+ public void run() {
+ execAndForkSubTasks();
+ }
+ });
+ }
+
+ private void compute(@NotNull final Runnable process) {
+ Runnable toRun = runInReadAction ? new Runnable() {
+ @Override
+ public void run() {
+ if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(process)) {
+ failedSubTasks = new ArrayList<ApplierCompleter>();
+ failedSubTasks.add(ApplierCompleter.this);
+ doComplete(throwable);
+ }
+ }
+ } : process;
+ ProgressIndicator existing = ProgressManager.getInstance().getProgressIndicator();
+ if (existing == progressIndicator) {
+ toRun.run();
+ }
+ else {
+ ProgressManager.getInstance().executeProcessUnderProgress(toRun, progressIndicator);
+ }
+ }
+
+ static class ComputationAbortedException extends RuntimeException {}
+ // executes tasks one by one and forks right halves if it takes too much time
+ // returns the linked list of forked halves - they all need to be joined; null means all tasks have been executed, nothing was forked
+ @Nullable
+ private ApplierCompleter execAndForkSubTasks() {
+ int hi = this.hi;
+ long start = System.currentTimeMillis();
+ ApplierCompleter right = null;
+ Throwable throwable = null;
+ try {
+ for (int i = lo; i < hi; ++i) {
+ progressIndicator.checkCanceled();
+ if (!processor.process(array.get(i))) throw new ComputationAbortedException();
+ long finish = System.currentTimeMillis();
+ long elapsed = finish - start;
+ if (elapsed > 10 && hi - i >= 2 && getSurplusQueuedTaskCount() <= JobSchedulerImpl.CORES_COUNT) {
+ int mid = i + hi >>> 1;
+ right = new ApplierCompleter(this, runInReadAction, progressIndicator, array, processor, mid, hi, right);
+ //children.add(right);
+ addToPendingCount(1);
+ right.fork();
+ hi = mid;
+ start = finish;
+ }
+ }
+
+ // traverse the list looking for a task available for stealing
+ if (right != null) {
+ right.tryToExecAllList();
+ }
+ }
+ catch (Throwable e) {
+ cancelProgress();
+ throwable = e;
+ }
+ finally {
+ doComplete(throwable == null ? this.throwable : throwable);
+ }
+ return right;
+ }
+
+ private void doComplete(Throwable throwable) {
+ ApplierCompleter a = this;
+ ApplierCompleter child = a;
+ while (true) {
+ if (throwable != null) {
+ a.throwable = throwable;
+ }
+ if (a.getPendingCount() == 0) {
+ if (throwable == null) {
+ a.onCompletion(child);
+ }
+ else {
+ a.throwable = throwable;
+ // currently avoid using onExceptionalCompletion since it leaks exceptions via jsr166e.ForkJoinTask.exceptionTable
+ a.onCompletion(child);
+ //a.onExceptionalCompletion(throwable, child);
+ }
+ child = a;
+ a = (ApplierCompleter)a.getCompleter();
+ if (a == null) {
+ if (throwable == null) {
+ child.quietlyComplete();
+ }
+ else {
+ child.throwable = throwable;
+ // currently avoid using completeExceptionally since it leaks exceptions via jsr166e.ForkJoinTask.exceptionTable
+ child.quietlyComplete();
+ //child.completeExceptionally(throwable);
+ }
+ break;
+ }
+ }
+ else if (a.decrementPendingCountUnlessZero() != 0) {
+ break;
+ }
+ }
+ }
+
+ private void cancelProgress() {
+ if (!progressIndicator.isCanceled()) {
+ progressIndicator.cancel();
+ }
+ }
+
+ // tries to unfork, execute and re-link subtasks
+ private void tryToExecAllList() {
+ ApplierCompleter right = this;
+ while (right != null) {
+ if (right.tryUnfork()) {
+ right.execAndForkSubTasks();
+ }
+ right = right.next;
+ }
+ }
+
+ boolean completeTaskWhichFailToAcquireReadAction() {
+ if (failedSubTasks == null) {
+ return true;
+ }
+ final boolean[] result = {true};
+ // these tasks could not be executed in the other thread; do them here
+ for (final ApplierCompleter task : failedSubTasks) {
+ task.failedSubTasks = null;
+ task.compute(new Runnable() {
+ @Override
+ public void run() {
+ for (int i = task.lo; i < task.hi; ++i) {
+ if (!task.processor.process(task.array.get(i))) {
+ result[0] = false;
+ break;
+ }
+ }
+ }
+ });
+ assert task.failedSubTasks == null;
+ }
+ return result[0];
+ }
+
+ @Override
+ public String toString() {
+ return System.identityHashCode(this) + " ("+lo+"-"+hi+")";
+ }
+}
diff --git a/platform/platform-impl/src/com/intellij/concurrency/JobImpl.java b/platform/platform-impl/src/com/intellij/concurrency/JobImpl.java
deleted file mode 100644
index 9a7541c11187..000000000000
--- a/platform/platform-impl/src/com/intellij/concurrency/JobImpl.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright 2000-2009 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.
- */
-
-/*
- * @author max
- */
-package com.intellij.concurrency;
-
-import com.intellij.openapi.application.Application;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.util.Consumer;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.AtomicInteger;
-
-public class JobImpl<T> implements Job<T> {
- private static volatile long ourJobsCounter = 0;
- private final long myJobIndex = ourJobsCounter++;
- private final int myPriority;
- private final List<PrioritizedFutureTask<T>> myFutures = new ArrayList<PrioritizedFutureTask<T>>();
- private volatile boolean canceled = false;
- private final AtomicInteger runningTasks = new AtomicInteger();
- private volatile boolean scheduled;
- private final boolean myFailFastOnAcquireReadAction;
-
- JobImpl(int priority, boolean failFastOnAcquireReadAction) {
- myPriority = priority;
- myFailFastOnAcquireReadAction = failFastOnAcquireReadAction;
- }
-
- @Override
- public String getTitle() {
- return null;
- }
-
- @Override
- public void addTask(@NotNull Callable<T> task) {
- addTask(task, null);
- }
-
- @Override
- public void addTask(@NotNull Runnable task, T result) {
- addTask(Executors.callable(task, result));
- }
-
- @Override
- public void addTask(@NotNull Runnable task) {
- addTask(Executors.callable(task, (T)null));
- }
-
- public void addTask(@NotNull Callable<T> callable, final Consumer<Future> onDoneCallback) {
- checkNotScheduled();
-
- PrioritizedFutureTask<T> future =
- new PrioritizedFutureTask<T>(callable, this, myJobIndex, JobSchedulerImpl.currentTaskIndex(), myPriority, myFailFastOnAcquireReadAction){
- @Override
- protected void done() {
- super.done();
- if (onDoneCallback != null) {
- onDoneCallback.consume(this);
- }
- //TODO[cdr]: consider clearing thread locals: ReflectionUtil.resetThreadlocals();
- }
- };
- synchronized (myFutures) {
- myFutures.add(future);
- }
- runningTasks.incrementAndGet();
- }
-
-
- @Override
- public List<T> scheduleAndWaitForResults() throws Throwable {
- checkCanSchedule();
- final Application application = ApplicationManager.getApplication();
- boolean callerHasReadAccess = application != null && application.isReadAccessAllowed();
- scheduleAndWaitForResults(callerHasReadAccess);
- return null;
- }
-
- public void scheduleAndWaitForResults(boolean runInReadAction) throws Throwable {
- // Don't bother scheduling if we only have one processor or only one task
- boolean reallySchedule;
- PrioritizedFutureTask[] tasks = getTasks();
- synchronized (myFutures) {
- reallySchedule = JobSchedulerImpl.CORES_COUNT >= 2 && myFutures.size() >= 2;
- }
- scheduled = true;
-
- if (!reallySchedule) {
- for (PrioritizedFutureTask future : tasks) {
- future.run();
- }
- return;
- }
-
- submitTasks(tasks, runInReadAction, false);
-
- // in case of imbalanced tasks one huge task can stuck running and we would fall to waitForTermination instead of doing useful work
- //// http://gafter.blogspot.com/2006/11/thread-pool-puzzler.html
- //for (PrioritizedFutureTask task : tasks) {
- // task.run();
- //}
- //
- while (!isDone()) {
- Runnable task = JobSchedulerImpl.stealTask();
- if (task == null) break;
-
- task.run();
- }
-
- waitForTermination();
- }
-
- public void waitForTermination() throws Throwable {
- Throwable ex = null;
- PrioritizedFutureTask[] tasks = getTasks();
- for (PrioritizedFutureTask f : tasks) {
- try {
- // this loop is for workaround of mysterious bug
- // when sometimes future hangs inside parkAndCheckForInterrupt() during unbounded get()
- while(true) {
- try {
- f.get(10, TimeUnit.MILLISECONDS);
- break;
- }
- catch (TimeoutException e) {
- if (f.isDone()) {
- f.get(); // does awaitTermination(), and there is no chance to hang
- break;
- }
- }
- }
- }
- catch (CancellationException ignore) {
- // already cancelled
- cancel();
- }
- catch (ExecutionException e) {
- cancel();
-
- Throwable cause = e.getCause();
- if (cause != null) {
- ex = cause;
- }
- }
- }
-
- if (ex != null) {
- throw ex;
- }
- }
-
- @Override
- public void cancel() {
- checkScheduled();
- if (canceled) return;
- canceled = true;
-
- PrioritizedFutureTask[] tasks = getTasks();
- for (PrioritizedFutureTask future : tasks) {
- future.cancel(false);
- }
- runningTasks.set(0);
- }
-
- @Override
- public boolean isCanceled() {
- checkScheduled();
- return canceled;
- }
-
- @Override
- public void schedule() {
- checkCanSchedule();
- scheduled = true;
-
- PrioritizedFutureTask[] tasks = getTasks();
-
- submitTasks(tasks, false, true);
- }
-
- @NotNull
- public PrioritizedFutureTask[] getTasks() {
- PrioritizedFutureTask[] tasks;
- synchronized (myFutures) {
- tasks = myFutures.toArray(new PrioritizedFutureTask[myFutures.size()]);
- }
- return tasks;
- }
-
- @Override
- public boolean isDone() {
- checkScheduled();
-
- return runningTasks.get() <= 0;
- }
-
- private void checkCanSchedule() {
- checkNotScheduled();
- synchronized (myFutures) {
- if (myFutures.isEmpty()) {
- throw new IllegalStateException("No tasks added. You can't schedule a job which has no tasks");
- }
- }
- }
-
- private void checkNotScheduled() {
- if (scheduled) {
- throw new IllegalStateException("Already running. You can't call this method for a job which is already scheduled");
- }
- }
-
- private void checkScheduled() {
- if (!scheduled) {
- throw new IllegalStateException("Cannot call this method for not yet started job");
- }
- }
-
- private static void submitTasks(@NotNull PrioritizedFutureTask[] tasks, boolean runInReadAction, boolean reportExceptions) {
- for (final PrioritizedFutureTask future : tasks) {
- JobSchedulerImpl.submitTask(future, runInReadAction, reportExceptions);
- }
- }
-
- void taskDone() {
- runningTasks.decrementAndGet();
- }
-}
diff --git a/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java b/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java
index ee5379e4b794..f47962e2eb72 100644
--- a/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java
+++ b/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java
@@ -19,67 +19,90 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
-import com.intellij.openapi.progress.util.ProgressWrapper;
+import com.intellij.openapi.progress.util.ProgressIndicatorBase;
import com.intellij.util.Consumer;
+import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Processor;
+import jsr166e.ForkJoinPool;
+import jsr166e.ForkJoinTask;
+import jsr166e.ForkJoinWorkerThread;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Future;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
/**
* @author cdr
*/
public class JobLauncherImpl extends JobLauncher {
- private static <T> boolean invokeConcurrentlyForAll(@NotNull final List<? extends T> things,
- boolean runInReadAction,
- boolean failFastOnAcquireReadAction,
- @NotNull final Processor<T> thingProcessor,
- final ProgressWrapper wrapper) throws ProcessCanceledException {
- final JobImpl<String> job = new JobImpl<String>(Job.DEFAULT_PRIORITY, failFastOnAcquireReadAction);
-
- final int chunkSize = Math.max(1, things.size() / Math.max(1, JobSchedulerImpl.CORES_COUNT / 2));
- for (int i = 0; i < things.size(); i += chunkSize) {
- // this job chunk is i..i+chunkSize-1
- final int finalI = i;
- job.addTask(new Runnable() {
+ private static final AtomicLong bits = new AtomicLong();
+ private static final ForkJoinPool.ForkJoinWorkerThreadFactory FACTORY = new ForkJoinPool.ForkJoinWorkerThreadFactory() {
+ @Override
+ public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
+ final int n = addThread();
+ ForkJoinWorkerThread thread = new ForkJoinWorkerThread(pool) {
@Override
- public void run() {
- ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() {
- @Override
- public void run() {
- try {
- for (int k = finalI; k < finalI + chunkSize && k < things.size(); k++) {
- T thing = things.get(k);
- if (!thingProcessor.process(thing)) {
- job.cancel();
- break;
- }
- }
- }
- catch (ProcessCanceledException e) {
- job.cancel();
- throw e;
- }
-
- }
- }, wrapper);
+ protected void onTermination(Throwable exception) {
+ finishThread(n);
+ super.onTermination(exception);
}
- });
+ };
+ thread.setName("JobScheduler FJ pool "+ n +"/"+ JobSchedulerImpl.CORES_COUNT);
+ return thread;
+ }
+
+ private int addThread() {
+ boolean set;
+ int n;
+ do {
+ long l = bits.longValue();
+ long next = (l + 1) | l;
+ n = Long.numberOfTrailingZeros(l + 1);
+ set = bits.compareAndSet(l, next);
+ } while (!set);
+ return n;
+ }
+ private void finishThread(int n) {
+ boolean set;
+ do {
+ long l = bits.get();
+ long next = l & ~(1L << n);
+ set = bits.compareAndSet(l, next);
+ } while (!set);
}
+ };
+
+ private static final ForkJoinPool pool = new ForkJoinPool(JobSchedulerImpl.CORES_COUNT, FACTORY, null, false);
+
+ private static <T> boolean invokeConcurrentlyForAll(@NotNull final List<T> things,
+ boolean runInReadAction,
+ @NotNull final Processor<? super T> thingProcessor,
+ @NotNull ProgressIndicator wrapper) throws ProcessCanceledException {
+ ApplierCompleter applier = new ApplierCompleter(null, runInReadAction, wrapper, things, thingProcessor, 0, things.size(), null);
try {
- job.scheduleAndWaitForResults(runInReadAction);
+ pool.invoke(applier);
+ if (applier.throwable != null) throw applier.throwable;
+ }
+ catch (ApplierCompleter.ComputationAbortedException e) {
+ return false;
}
catch (RuntimeException e) {
- job.cancel();
+ assert wrapper.isCanceled();
throw e;
}
- catch (Throwable throwable) {
- job.cancel();
- throw new ProcessCanceledException(throwable);
+ catch (Error e) {
+ assert wrapper.isCanceled();
+ throw e;
+ }
+ catch (Throwable e) {
+ assert wrapper.isCanceled();
+ throw new RuntimeException(e);
}
- return !job.isCanceled();
+ assert applier.isDone();
+ return applier.completeTaskWhichFailToAcquireReadAction();
}
@Override
@@ -92,22 +115,34 @@ public class JobLauncherImpl extends JobLauncher {
}
@Override
- public <T> boolean invokeConcurrentlyUnderProgress(@NotNull List<? extends T> things,
+ public <T> boolean invokeConcurrentlyUnderProgress(@NotNull final List<? extends T> things,
ProgressIndicator progress,
boolean runInReadAction,
boolean failFastOnAcquireReadAction,
- @NotNull Processor<T> thingProcessor) {
- if (things.isEmpty()) {
- return true;
- }
- if (things.size() == 1) {
- T t = things.get(0);
- return thingProcessor.process(t);
+ @NotNull final Processor<T> thingProcessor) throws ProcessCanceledException {
+ if (things.isEmpty()) return true;
+ // supply our own indicator even if we haven't given one - to support cancellation
+ final ProgressIndicator wrapper = progress == null ? new ProgressIndicatorBase() : new SensitiveProgressWrapper(progress);
+
+ if (things.size() <= 1 || JobSchedulerImpl.CORES_COUNT <= 2) {
+ final AtomicBoolean result = new AtomicBoolean(true);
+ ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() {
+ @Override
+ public void run() {
+ //noinspection ForLoopReplaceableByForEach
+ for (int i = 0; i < things.size(); i++) {
+ T thing = things.get(i);
+ if (!thingProcessor.process(thing)) {
+ result.set(false);
+ break;
+ }
+ }
+ }
+ }, wrapper);
+ return result.get();
}
- // can be already wrapped
- final ProgressWrapper wrapper = progress instanceof ProgressWrapper ? (ProgressWrapper)progress : ProgressWrapper.wrap(progress);
- return invokeConcurrentlyForAll(things, runInReadAction, failFastOnAcquireReadAction, thingProcessor, wrapper);
+ return invokeConcurrentlyForAll(things, runInReadAction, thingProcessor, wrapper);
}
// This implementation is not really async
@@ -130,22 +165,92 @@ public class JobLauncherImpl extends JobLauncher {
@NotNull
@Override
- public Job<Void> submitToJobThread(int priority, @NotNull final Runnable action, Consumer<Future> onDoneCallback) {
- final JobImpl<Void> job = new JobImpl<Void>(priority, false);
- Callable<Void> callable = new Callable<Void>() {
- @Override
- public Void call() throws Exception {
- try {
- action.run();
- }
- catch (ProcessCanceledException ignored) {
- // since it's the only task in the job, nothing to cancel
+ public Job<Void> submitToJobThread(int priority, @NotNull final Runnable action, final Consumer<Future> onDoneCallback) {
+ VoidForkJoinTask task = new VoidForkJoinTask(action, onDoneCallback);
+ pool.submit(task);
+ return task;
+ }
+
+ private static class VoidForkJoinTask extends ForkJoinTask<Void> implements Job<Void> {
+ private final Runnable myAction;
+ private final Consumer<Future> myOnDoneCallback;
+
+ public VoidForkJoinTask(@NotNull Runnable action, @Nullable Consumer<Future> onDoneCallback) {
+ myAction = action;
+ myOnDoneCallback = onDoneCallback;
+ }
+
+ @Override
+ public Void getRawResult() {
+ return null;
+ }
+
+ @Override
+ protected void setRawResult(Void value) {
+
+ }
+
+ @Override
+ protected boolean exec() {
+ try {
+ myAction.run();
+ complete(null); // complete manually before calling callback
+ }
+ catch (Throwable throwable) {
+ completeExceptionally(throwable);
+ }
+ finally {
+ if (myOnDoneCallback != null) {
+ myOnDoneCallback.consume(this);
}
- return null;
}
- };
- job.addTask(callable, onDoneCallback);
- job.schedule();
- return job;
+ return true;
+ }
+
+ //////////////// Job
+ @Override
+ public String getTitle() {
+ throw new IncorrectOperationException();
+ }
+
+ @Override
+ public boolean isCanceled() {
+ return isCancelled();
+ }
+
+ @Override
+ public void addTask(@NotNull Callable<Void> task) {
+ throw new IncorrectOperationException();
+ }
+
+ @Override
+ public void addTask(@NotNull Runnable task, Void result) {
+ throw new IncorrectOperationException();
+ }
+
+ @Override
+ public void addTask(@NotNull Runnable task) {
+ throw new IncorrectOperationException();
+ }
+
+ @Override
+ public List<Void> scheduleAndWaitForResults() throws Throwable {
+ throw new IncorrectOperationException();
+ }
+
+ @Override
+ public void cancel() {
+ cancel(true);
+ }
+
+ @Override
+ public void schedule() {
+ throw new IncorrectOperationException();
+ }
+
+ @Override
+ public void waitForCompletion(int millis) throws InterruptedException, ExecutionException, TimeoutException {
+ get(millis, TimeUnit.MILLISECONDS);
+ }
}
}
diff --git a/platform/platform-impl/src/com/intellij/concurrency/JobSchedulerImpl.java b/platform/platform-impl/src/com/intellij/concurrency/JobSchedulerImpl.java
index 366615108899..7b252e9c16d0 100644
--- a/platform/platform-impl/src/com/intellij/concurrency/JobSchedulerImpl.java
+++ b/platform/platform-impl/src/com/intellij/concurrency/JobSchedulerImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -19,66 +19,6 @@
*/
package com.intellij.concurrency;
-import com.intellij.openapi.Disposable;
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.concurrent.PriorityBlockingQueue;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-@NonNls
-public class JobSchedulerImpl extends JobScheduler implements Disposable {
- public static final int CORES_COUNT = /*1;//*/ Runtime.getRuntime().availableProcessors();
-
- private static final ThreadFactory WORKERS_FACTORY = new ThreadFactory() {
- private int threadSeq;
-
- @NotNull
- @Override
- public synchronized Thread newThread(@NotNull final Runnable r) {
- @NonNls String name = "JobScheduler pool " + threadSeq + "/" + CORES_COUNT;
- final Thread thread = new Thread(r, name);
- thread.setPriority(Thread.NORM_PRIORITY);
- threadSeq++;
- return thread;
- }
- };
-
- private static final PriorityBlockingQueue<Runnable> ourQueue = new PriorityBlockingQueue<Runnable>();
- private static final MyExecutor ourExecutor = new MyExecutor();
-
- static int currentTaskIndex() {
- return ourQueue.size();
- }
-
- @Override
- public void dispose() {
- ((ThreadPoolExecutor)getScheduler()).getQueue().clear();
- }
-
- static Runnable stealTask() {
- return ourQueue.poll();
- }
-
- static void submitTask(@NotNull PrioritizedFutureTask future, boolean runInReadAction, boolean reportExceptions) {
- future.beforeRun(runInReadAction, reportExceptions);
- ourExecutor.executeTask(future);
- }
-
- private static class MyExecutor extends ThreadPoolExecutor {
- private MyExecutor() {
- super(CORES_COUNT, Integer.MAX_VALUE, 60 * 10, TimeUnit.SECONDS, ourQueue, WORKERS_FACTORY);
- }
-
- private void executeTask(@NotNull PrioritizedFutureTask task) {
- super.execute(task);
- }
-
- @Override
- public void execute(@NotNull Runnable command) {
- throw new IllegalStateException("Use executeTask() to submit PrioritizedFutureTasks only");
- }
- }
+public abstract class JobSchedulerImpl {
+ public static final int CORES_COUNT = Runtime.getRuntime().availableProcessors();
}
diff --git a/platform/platform-impl/src/com/intellij/concurrency/PrioritizedFutureTask.java b/platform/platform-impl/src/com/intellij/concurrency/PrioritizedFutureTask.java
deleted file mode 100644
index 799750ed5339..000000000000
--- a/platform/platform-impl/src/com/intellij/concurrency/PrioritizedFutureTask.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2000-2009 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.
- */
-
-/*
- * @author max
- */
-package com.intellij.concurrency;
-
-import com.intellij.openapi.application.ex.ApplicationManagerEx;
-import com.intellij.openapi.application.impl.ApplicationImpl;
-import com.intellij.openapi.diagnostic.Logger;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.FutureTask;
-
-class PrioritizedFutureTask<T> extends FutureTask<T> implements Comparable<PrioritizedFutureTask> {
- private static final Logger LOG = Logger.getInstance("#com.intellij.concurrency.PrioritizedFutureTask");
- private final JobImpl<T> myJob;
- private final long myJobIndex;
- private final int myTaskIndex;
- private final int myPriority;
- private final boolean myFailFastOnAcquireReadAction;
- private volatile boolean myRunInReadAction;
- private volatile boolean myReportExceptions;
-
- PrioritizedFutureTask(final Callable<T> callable,
- JobImpl<T> job,
- long jobIndex,
- int taskIndex,
- int priority,
- boolean failFastOnAcquireReadAction) {
- super(callable);
- myJob = job;
- myJobIndex = jobIndex;
- myTaskIndex = taskIndex;
- myPriority = priority;
- myFailFastOnAcquireReadAction = failFastOnAcquireReadAction;
- }
-
- public void beforeRun(boolean runInReadAction, boolean reportExceptions) {
- myRunInReadAction = runInReadAction;
- myReportExceptions = reportExceptions;
- }
-
- @Override
- public void run() {
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- try {
- if (myJob.isCanceled()) {
- //set(null);
- cancel(false); //todo cancel or set?
- }
- else {
- PrioritizedFutureTask.super.run();
- }
- }
- finally {
- try {
- if (myReportExceptions) {
- // let exceptions during execution manifest themselves
- PrioritizedFutureTask.super.get();
- }
- }
- catch (CancellationException ignored) {
- }
- catch (InterruptedException e) {
- LOG.error(e);
- }
- catch (ExecutionException e) {
- LOG.error(e);
- }
- finally {
- myJob.taskDone();
- }
- }
- }
- };
- if (myRunInReadAction) {
- // have to start "real" read action so that we cannot start write action until we are finished here
- if (myFailFastOnAcquireReadAction) {
- if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(runnable)) {
- myJob.cancel();
- }
- }
- else {
- // cannot run readaction here because of possible deadlock when writeaction in the queue
- boolean old = ApplicationImpl.setExceptionalThreadWithReadAccessFlag(true);
- try {
- runnable.run();
- }
- finally {
- ApplicationImpl.setExceptionalThreadWithReadAccessFlag(old);
- }
- }
- }
- else {
- runnable.run();
- }
- }
-
- @Override
- public int compareTo(@NotNull final PrioritizedFutureTask o) {
- int priorityDelta = myPriority - o.myPriority;
- if (priorityDelta != 0) return priorityDelta;
- if (myJobIndex != o.myJobIndex) return myJobIndex < o.myJobIndex ? -1 : 1;
- return myTaskIndex - o.myTaskIndex;
- }
-}
diff --git a/platform/platform-impl/src/com/intellij/concurrency/SensitiveProgressWrapper.java b/platform/platform-impl/src/com/intellij/concurrency/SensitiveProgressWrapper.java
new file mode 100644
index 000000000000..e471f68a58c8
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/concurrency/SensitiveProgressWrapper.java
@@ -0,0 +1,34 @@
+/*
+ * 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.concurrency;
+
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.util.ProgressWrapper;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Progress indicator wrapper which reacts to its own cancellation in addition to the cancellation of its wrappee.
+ */
+public class SensitiveProgressWrapper extends ProgressWrapper {
+ public SensitiveProgressWrapper(@NotNull ProgressIndicator indicator) {
+ super(indicator);
+ }
+
+ @Override
+ public boolean isCanceled() {
+ return super.isCanceled() || getOriginalProgressIndicator().isCanceled();
+ }
+}
diff --git a/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java b/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java
index f960c7005076..3ba6638a4b8d 100644
--- a/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java
+++ b/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java
@@ -286,6 +286,10 @@ public class IdeTooltipManager implements ApplicationComponent, AWTEventListener
effectivePoint.y = toCenterY ? bounds.height / 2 : effectivePoint.y;
}
+ if (myCurrentComponent == tooltip.getComponent() && myCurrentTipUi != null) {
+ myCurrentTipUi.show(new RelativePoint(tooltip.getComponent(), effectivePoint), tooltip.getPreferredPosition());
+ return;
+ }
if (myCurrentComponent == tooltip.getComponent() && effectivePoint.equals(new Point(myX, myY))) {
return;
diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java
index b8c36473dcf3..671ae6fd2ceb 100644
--- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java
+++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java
@@ -521,6 +521,12 @@ public abstract class PluginManagerMain implements Disposable {
public static void notifyPluginsWereInstalled(@Nullable String pluginName) {
+ notifyPluginsWereUpdated(pluginName != null
+ ? "Plugin \'" + pluginName + "\' was successfully installed"
+ : "Plugins were installed");
+ }
+
+ public static void notifyPluginsWereUpdated(final String title) {
final ApplicationEx app = ApplicationManagerEx.getApplicationEx();
final boolean restartCapable = app.isRestartCapable();
String message =
@@ -530,9 +536,7 @@ public abstract class PluginManagerMain implements Disposable {
message += restartCapable ? "\"restart\">Restart now" : "\"shutdown\">Shutdown";
message += "</a>";
new NotificationGroup("Plugins Lifecycle Group", NotificationDisplayType.STICKY_BALLOON, true)
- .createNotification(pluginName != null
- ? "Plugin \'" + pluginName + "\' was successfully installed"
- : "Plugins were installed",
+ .createNotification(title,
XmlStringUtil.wrapInHtml(message), NotificationType.INFORMATION,
new NotificationListener() {
@Override
diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryHelper.java b/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryHelper.java
index 1b98915733cb..9959cef30030 100644
--- a/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryHelper.java
+++ b/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryHelper.java
@@ -45,7 +45,7 @@ public class RepositoryHelper {
public static List<IdeaPluginDescriptor> loadPluginsFromRepository(@Nullable ProgressIndicator indicator) throws Exception {
ApplicationInfoEx appInfo = ApplicationInfoImpl.getShadowInstance();
- String url = appInfo.getPluginsListUrl() + "?build=" + appInfo.getBuild().asString();
+ String url = appInfo.getPluginsListUrl() + "?build=" + appInfo.getApiVersion();
if (indicator != null) {
indicator.setText2(IdeBundle.message("progress.connecting.to.plugin.manager", appInfo.getPluginManagerUrl()));
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/AppearanceConfigurable.java b/platform/platform-impl/src/com/intellij/ide/ui/AppearanceConfigurable.java
index 92e7a60972f4..69944b4febe3 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/AppearanceConfigurable.java
+++ b/platform/platform-impl/src/com/intellij/ide/ui/AppearanceConfigurable.java
@@ -170,6 +170,9 @@ public class AppearanceConfigurable extends BaseConfigurable implements Searchab
update |= settings.RIGHT_HORIZONTAL_SPLIT != myComponent.myRightLayoutCheckBox.isSelected();
settings.RIGHT_HORIZONTAL_SPLIT = myComponent.myRightLayoutCheckBox.isSelected();
+ update |= settings.SHOW_EDITOR_TOOLTIP != myComponent.myEditorTooltipCheckBox.isSelected();
+ settings.SHOW_EDITOR_TOOLTIP = myComponent.myEditorTooltipCheckBox.isSelected();
+
update |= settings.DISABLE_MNEMONICS_IN_CONTROLS != myComponent.myDisableMnemonicInControlsCheckBox.isSelected();
settings.DISABLE_MNEMONICS_IN_CONTROLS = myComponent.myDisableMnemonicInControlsCheckBox.isSelected();
@@ -274,6 +277,7 @@ public class AppearanceConfigurable extends BaseConfigurable implements Searchab
myComponent.myWidescreenLayoutCheckBox.setSelected(settings.WIDESCREEN_SUPPORT);
myComponent.myLeftLayoutCheckBox.setSelected(settings.LEFT_HORIZONTAL_SPLIT);
myComponent.myRightLayoutCheckBox.setSelected(settings.RIGHT_HORIZONTAL_SPLIT);
+ myComponent.myEditorTooltipCheckBox.setSelected(settings.SHOW_EDITOR_TOOLTIP);
myComponent.myDisableMnemonicInControlsCheckBox.setSelected(settings.DISABLE_MNEMONICS_IN_CONTROLS);
boolean alphaModeEnabled = WindowManagerEx.getInstanceEx().isAlphaModeSupported();
@@ -318,6 +322,7 @@ public class AppearanceConfigurable extends BaseConfigurable implements Searchab
isModified |= myComponent.myWidescreenLayoutCheckBox.isSelected() != settings.WIDESCREEN_SUPPORT;
isModified |= myComponent.myLeftLayoutCheckBox.isSelected() != settings.LEFT_HORIZONTAL_SPLIT;
isModified |= myComponent.myRightLayoutCheckBox.isSelected() != settings.RIGHT_HORIZONTAL_SPLIT;
+ isModified |= myComponent.myEditorTooltipCheckBox.isSelected() != settings.SHOW_EDITOR_TOOLTIP;
isModified |= myComponent.myHideIconsInQuickNavigation.isSelected() != settings.SHOW_ICONS_IN_QUICK_NAVIGATION;
@@ -387,6 +392,7 @@ public class AppearanceConfigurable extends BaseConfigurable implements Searchab
private JCheckBox myRightLayoutCheckBox;
private JSlider myInitialTooltipDelaySlider;
private ComboBox myPresentationModeFontSize;
+ private JCheckBox myEditorTooltipCheckBox;
private JCheckBox myAllowStatusBar;
private JCheckBox myAllowLineNumbers;
private JCheckBox myAllowAnnotations;
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/AppearancePanel.form b/platform/platform-impl/src/com/intellij/ide/ui/AppearancePanel.form
index f7e131228bbf..911ca64281e1 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/AppearancePanel.form
+++ b/platform/platform-impl/src/com/intellij/ide/ui/AppearancePanel.form
@@ -256,7 +256,7 @@
</component>
</children>
</grid>
- <grid id="937be" layout-manager="GridLayoutManager" row-count="6" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <grid id="937be" layout-manager="GridLayoutManager" row-count="7" 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="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="1" fill="3" indent="0" use-parent-layout="false"/>
@@ -366,7 +366,9 @@
</component>
<component id="eba02" class="javax.swing.JCheckBox" binding="myLeftLayoutCheckBox">
<constraints>
- <grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ <grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false">
+ <preferred-size width="171" height="20"/>
+ </grid>
</constraints>
<properties>
<text resource-bundle="messages/IdeBundle" key="checkbox.left.toolwindow.layout"/>
@@ -374,12 +376,22 @@
</component>
<component id="8ce51" class="javax.swing.JCheckBox" binding="myRightLayoutCheckBox">
<constraints>
- <grid row="5" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ <grid row="5" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false">
+ <preferred-size width="177" height="20"/>
+ </grid>
</constraints>
<properties>
<text resource-bundle="messages/IdeBundle" key="checkbox.right.toolwindow.layout"/>
</properties>
</component>
+ <component id="26420" class="javax.swing.JCheckBox" binding="myEditorTooltipCheckBox">
+ <constraints>
+ <grid row="6" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <text resource-bundle="messages/IdeBundle" key="checkbox.show.editor.preview.popup"/>
+ </properties>
+ </component>
</children>
</grid>
<grid id="e3cc0" layout-manager="GridLayoutManager" row-count="2" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/IntelliJLaf.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/IntelliJLaf.java
new file mode 100644
index 000000000000..4cf39444d371
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/IntelliJLaf.java
@@ -0,0 +1,40 @@
+/*
+ * 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.ide.ui.laf;
+
+import com.intellij.ide.ui.laf.darcula.DarculaLaf;
+
+import javax.swing.plaf.metal.DefaultMetalTheme;
+
+/**
+ * @author Konstantin Bulenkov
+ */
+public class IntelliJLaf extends DarculaLaf {
+ @Override
+ public String getName() {
+ return "IntelliJ";
+ }
+
+ @Override
+ protected String getPrefix() {
+ return "intellijlaf";
+ }
+
+ @Override
+ protected DefaultMetalTheme createMetalTheme() {
+ return new IdeaBlueMetalTheme();
+ }
+}
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/IntelliJLookAndFeelInfo.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/IntelliJLookAndFeelInfo.java
new file mode 100644
index 000000000000..76ef1abfb7ac
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/IntelliJLookAndFeelInfo.java
@@ -0,0 +1,37 @@
+/*
+ * 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.ide.ui.laf;
+
+import com.intellij.ide.IdeBundle;
+
+import javax.swing.*;
+
+/**
+ * @author Konstantin Bulenkov
+ */
+public class IntelliJLookAndFeelInfo extends UIManager.LookAndFeelInfo {
+ public IntelliJLookAndFeelInfo(){
+ super(IdeBundle.message("idea.intellij.look.and.feel"), IntelliJLaf.class.getName());
+ }
+
+ public boolean equals(Object obj){
+ return (obj instanceof IdeaLookAndFeelInfo);
+ }
+
+ public int hashCode(){
+ return getName().hashCode();
+ }
+} \ No newline at end of file
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java
index 99d50c7deaa5..020313ba8f4a 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java
@@ -128,7 +128,11 @@ public final class LafManagerImpl extends LafManager implements ApplicationCompo
lafList.add(new UIManager.LookAndFeelInfo("Default", UIManager.getSystemLookAndFeelClassName()));
}
else {
- lafList.add(new IdeaLookAndFeelInfo());
+ if (Registry.is("idea.4.5.laf.enabled")) {
+ lafList.add(new IdeaLookAndFeelInfo());
+ } else {
+ lafList.add(new IntelliJLookAndFeelInfo());
+ }
for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
String name = laf.getName();
if (!"Metal".equalsIgnoreCase(name) && !"CDE/Motif".equalsIgnoreCase(name)) {
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java
index 3dca2e53c272..a24bce894bbe 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java
@@ -33,6 +33,7 @@ import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.IconUIResource;
import javax.swing.plaf.InsetsUIResource;
import javax.swing.plaf.basic.BasicLookAndFeel;
+import javax.swing.plaf.metal.DefaultMetalTheme;
import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;
@@ -46,7 +47,7 @@ import java.util.Properties;
/**
* @author Konstantin Bulenkov
*/
-public final class DarculaLaf extends BasicLookAndFeel {
+public class DarculaLaf extends BasicLookAndFeel {
public static final String NAME = "Darcula";
BasicLookAndFeel base;
@@ -105,7 +106,7 @@ public final class DarculaLaf extends BasicLookAndFeel {
patchComboBox(metalDefaults, defaults);
defaults.remove("Spinner.arrowButtonBorder");
defaults.put("Spinner.arrowButtonSize", new Dimension(16, 5));
- MetalLookAndFeel.setCurrentTheme(new DarculaMetalTheme());
+ MetalLookAndFeel.setCurrentTheme(createMetalTheme());
if (SystemInfo.isWindows) {
//JFrame.setDefaultLookAndFeelDecorated(true);
}
@@ -118,6 +119,10 @@ public final class DarculaLaf extends BasicLookAndFeel {
return super.getDefaults();
}
+ protected DefaultMetalTheme createMetalTheme() {
+ return new DarculaMetalTheme();
+ }
+
private static Font findFont(String name) {
for (Font font : GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts()) {
if (font.getName().equals(name)) {
@@ -135,10 +140,10 @@ public final class DarculaLaf extends BasicLookAndFeel {
}
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
- private static void patchStyledEditorKit() {
+ private void patchStyledEditorKit() {
try {
StyleSheet defaultStyles = new StyleSheet();
- InputStream is = DarculaLaf.class.getResourceAsStream("darcula.css");
+ InputStream is = getClass().getResourceAsStream(getPrefix() + ".css");
Reader r = new BufferedReader(new InputStreamReader(is, "UTF-8"));
defaultStyles.loadRules(r, null);
r.close();
@@ -151,6 +156,10 @@ public final class DarculaLaf extends BasicLookAndFeel {
}
}
+ protected String getPrefix() {
+ return "darcula";
+ }
+
private void call(String method) {
try {
final Method superMethod = BasicLookAndFeel.class.getDeclaredMethod(method);
@@ -167,7 +176,7 @@ public final class DarculaLaf extends BasicLookAndFeel {
}
@SuppressWarnings({"HardCodedStringLiteral"})
- static void initIdeaDefaults(UIDefaults defaults) {
+ protected void initIdeaDefaults(UIDefaults defaults) {
loadDefaults(defaults);
defaults.put("Table.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] {
"ctrl C", "copy",
@@ -222,20 +231,20 @@ public final class DarculaLaf extends BasicLookAndFeel {
}
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
- private static void loadDefaults(UIDefaults defaults) {
+ protected void loadDefaults(UIDefaults defaults) {
final Properties properties = new Properties();
final String osSuffix = SystemInfo.isMac ? "mac" : SystemInfo.isWindows ? "windows" : "linux";
try {
- InputStream stream = DarculaLaf.class.getResourceAsStream("darcula.properties");
+ InputStream stream = getClass().getResourceAsStream(getPrefix() + ".properties");
properties.load(stream);
stream.close();
- stream = DarculaLaf.class.getResourceAsStream("darcula_" + osSuffix + ".properties");
+ stream = getClass().getResourceAsStream(getPrefix() + "_" + osSuffix + ".properties");
properties.load(stream);
stream.close();
HashMap<String, Object> darculaGlobalSettings = new HashMap<String, Object>();
- final String prefix = "darcula.";
+ final String prefix = getPrefix() + ".";
for (String key : properties.stringPropertyNames()) {
if (key.startsWith(prefix)) {
darculaGlobalSettings.put(key.substring(prefix.length()), parseValue(key, properties.getProperty(key)));
@@ -260,7 +269,7 @@ public final class DarculaLaf extends BasicLookAndFeel {
catch (IOException e) {log(e);}
}
- private static Object parseValue(String key, @NotNull String value) {
+ protected Object parseValue(String key, @NotNull String value) {
if (key.endsWith("Insets")) {
final List<String> numbers = StringUtil.split(value, ",");
return new InsetsUIResource(Integer.parseInt(numbers.get(0)),
@@ -272,7 +281,7 @@ public final class DarculaLaf extends BasicLookAndFeel {
return Class.forName(value).newInstance();
} catch (Exception e) {log(e);}
} else {
- final Color color = ColorUtil.fromHex(value, null);
+ final Color color = parseColor(value);
final Integer invVal = getInteger(value);
final Boolean boolVal = "true".equals(value) ? Boolean.TRUE : "false".equals(value) ? Boolean.FALSE : null;
Icon icon = value.startsWith("AllIcons.") ? IconLoader.getIcon(value) : null;
@@ -289,6 +298,21 @@ public final class DarculaLaf extends BasicLookAndFeel {
return value;
}
+ @SuppressWarnings("UseJBColor")
+ private static Color parseColor(String value) {
+ if (value != null && value.length() == 8) {
+ final Color color = ColorUtil.fromHex(value.substring(0, 6));
+ if (color != null) {
+ try {
+ int alpha = Integer.parseInt(value.substring(6, 8), 16);
+ return new ColorUIResource(new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha));
+ } catch (Exception ignore){}
+ }
+ return null;
+ }
+ return ColorUtil.fromHex(value, null);
+ }
+
private static Integer getInteger(String value) {
try {
return Integer.parseInt(value);
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaUIUtil.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaUIUtil.java
index 68a12c48066c..924850c50287 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaUIUtil.java
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaUIUtil.java
@@ -16,6 +16,7 @@
package com.intellij.ide.ui.laf.darcula;
import com.intellij.ui.ColorUtil;
+import com.intellij.ui.JBColor;
import com.intellij.util.ui.MacUIUtil;
import com.intellij.util.ui.UIUtil;
@@ -25,24 +26,28 @@ import java.awt.*;
* @author Konstantin Bulenkov
*/
public class DarculaUIUtil {
- public static final Color GLOW_COLOR = new Color(96, 175, 255);
+ public static final Color GLOW_COLOR = new JBColor(new Color(96, 132, 212), new Color(96, 175, 255));
public static void paintFocusRing(Graphics g, int x, int y, int width, int height) {
- MacUIUtil.paintFocusRing((Graphics2D)g, GLOW_COLOR, new Rectangle(x, y, width, height));
+ MacUIUtil.paintFocusRing((Graphics2D)g, getGlow(), new Rectangle(x, y, width, height));
}
public static void paintFocusOval(Graphics g, int x, int y, int width, int height) {
- MacUIUtil.paintFocusRing((Graphics2D)g, GLOW_COLOR, new Rectangle(x, y, width, height), true);
+ MacUIUtil.paintFocusRing((Graphics2D)g, getGlow(), new Rectangle(x, y, width, height), true);
+ }
+
+ private static Color getGlow() {
+ return new JBColor(new Color(35, 121, 212), new Color(96, 175, 255));
}
public static void paintSearchFocusRing(Graphics2D g, Rectangle bounds) {
int correction = UIUtil.isUnderDarcula() ? 50 : 0;
final Color[] colors = new Color[]{
- ColorUtil.toAlpha(GLOW_COLOR, 180 - correction),
- ColorUtil.toAlpha(GLOW_COLOR, 120 - correction),
- ColorUtil.toAlpha(GLOW_COLOR, 70 - correction),
- ColorUtil.toAlpha(GLOW_COLOR, 100 - correction),
- ColorUtil.toAlpha(GLOW_COLOR, 50 - correction)
+ ColorUtil.toAlpha(getGlow(), 180 - correction),
+ ColorUtil.toAlpha(getGlow(), 120 - correction),
+ ColorUtil.toAlpha(getGlow(), 70 - correction),
+ ColorUtil.toAlpha(getGlow(), 100 - correction),
+ ColorUtil.toAlpha(getGlow(), 50 - correction)
};
final Object oldAntialiasingValue = g.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties
index aaffeb7cc5b3..260805e419eb 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties
@@ -76,6 +76,21 @@ TextArea.background=45494A
CheckBoxUI=com.intellij.ide.ui.laf.darcula.ui.DarculaCheckBoxUI
CheckBox.border=com.intellij.ide.ui.laf.darcula.ui.DarculaCheckBoxBorder
+CheckBox.darcula.inactiveFillColor=282828b4
+CheckBox.darcula.borderColor1=7878785a
+CheckBox.darcula.borderColor2=78787869
+CheckBox.darcula.disabledBorderColor1=7878785a
+CheckBox.darcula.disabledBorderColor2=78787869
+CheckBox.darcula.backgroundColor1=6e6e6e
+CheckBox.darcula.backgroundColor2=5f5f5f
+CheckBox.darcula.checkSignColor=aaaaaa
+CheckBox.darcula.checkSignColorDisabled=787878
+CheckBox.darcula.shadowColor=1e1e1e
+CheckBox.darcula.shadowColorDisabled=3c3c3c
+CheckBox.darcula.focusedArmed.backgroundColor1=646464
+CheckBox.darcula.focusedArmed.backgroundColor2=373737
+CheckBox.darcula.focused.backgroundColor1=787878
+CheckBox.darcula.focused.backgroundColor2=4b4b4b
ComboBoxUI=com.intellij.ide.ui.laf.darcula.ui.DarculaComboBoxUI
ComboBox.disabledBackground=3c3f41
@@ -89,6 +104,10 @@ StatusBar.bottomColor=2c2c2c
Button.border=com.intellij.ide.ui.laf.darcula.ui.DarculaButtonPainter
ButtonUI=com.intellij.ide.ui.laf.darcula.ui.DarculaButtonUI
+Button.darcula.color1=555a5c
+Button.darcula.color2=414648
+Button.darcula.selection.color1=384f6b
+Button.darcula.selection.color2=233143
MenuItem.acceleratorForeground=eeeeee
PopupMenu.translucentBackground=3c3f41
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaButtonUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaButtonUI.java
index 06d2e49a909b..3fc3235e32e9 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaButtonUI.java
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaButtonUI.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.
@@ -15,11 +15,15 @@
*/
package com.intellij.ide.ui.laf.darcula.ui;
+import com.intellij.openapi.ui.GraphicsConfig;
+import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.UIUtil;
+import sun.swing.SwingUtilities2;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicButtonUI;
import java.awt.*;
@@ -35,17 +39,60 @@ public class DarculaButtonUI extends BasicButtonUI {
@Override
public void paint(Graphics g, JComponent c) {
final Border border = c.getBorder();
+ final GraphicsConfig config = GraphicsUtil.setupAAPainting(g);
if (c.isEnabled() && border != null) {
final Insets ins = border.getBorderInsets(c);
final int yOff = (ins.top + ins.bottom) / 4;
if (((JButton)c).isDefaultButton()) {
- ((Graphics2D)g).setPaint(UIUtil.getGradientPaint(0, 0, new Color(0x384F6B), 0, c.getHeight(), new Color(0x233143)));
+ ((Graphics2D)g).setPaint(UIUtil.getGradientPaint(0, 0, getSelectedButtonColor1(), 0, c.getHeight(), getSelectedButtonColor2()));
}
else {
- ((Graphics2D)g).setPaint(UIUtil.getGradientPaint(0, 0, new Color(85, 90, 92), 0, c.getHeight(), new Color(65, 70, 72)));
+ ((Graphics2D)g).setPaint(UIUtil.getGradientPaint(0, 0, getButtonColor1(), 0, c.getHeight(), getButtonColor2()));
}
g.fillRoundRect(4, yOff, c.getWidth() - 2 * 4, c.getHeight() - 2 * yOff, 5, 5);
}
+ config.restore();
super.paint(g, c);
}
+
+ protected void paintText(Graphics g, JComponent c, Rectangle textRect, String text) {
+ AbstractButton button = (AbstractButton)c;
+ ButtonModel model = button.getModel();
+
+ if (model.isEnabled()) {
+ FontMetrics metrics = SwingUtilities2.getFontMetrics(c, g);
+ int mnemonicIndex = button.getDisplayedMnemonicIndex();
+
+ Color fg = button.getForeground();
+ if (fg instanceof UIResource && button instanceof JButton && ((JButton)button).isDefaultButton()) {
+ final Color selectedFg = UIManager.getColor("Button.selectedButtonForeground");
+ if (selectedFg != null) {
+ fg = selectedFg;
+ }
+ }
+ g.setColor(fg);
+ SwingUtilities2.drawStringUnderlineCharAt(c, g, text, mnemonicIndex,
+ textRect.x + getTextShiftOffset(),
+ textRect.y + metrics.getAscent() + getTextShiftOffset());
+ }
+ else {
+ super.paintText(g, c, textRect, text);
+ }
+ }
+
+ protected Color getButtonColor1() {
+ return UIManager.getColor("Button.darcula.color1");
+ }
+
+ protected Color getButtonColor2() {
+ return UIManager.getColor("Button.darcula.color2");
+ }
+
+ protected Color getSelectedButtonColor1() {
+ return UIManager.getColor("Button.darcula.selection.color1");
+ }
+
+ protected Color getSelectedButtonColor2() {
+ return UIManager.getColor("Button.darcula.selection.color2");
+ }
}
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaCheckBoxUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaCheckBoxUI.java
index 94899dbe40c4..b1b1d582df4c 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaCheckBoxUI.java
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaCheckBoxUI.java
@@ -98,28 +98,28 @@ public class DarculaCheckBoxUI extends MetalCheckBoxUI {
final boolean armed = b.getModel().isArmed();
if (c.hasFocus()) {
- g.setPaint(UIUtil.getGradientPaint(w/2, 1, armed ? Gray._100: Gray._120, w/2, h, armed ? Gray._55 : Gray._75));
+ g.setPaint(UIUtil.getGradientPaint(w/2, 1, getFocusedBackgroundColor1(armed), w/2, h, getFocusedBackgroundColor2(armed)));
g.fillRoundRect(0, 0, w - 2, h - 2, 4, 4);
DarculaUIUtil.paintFocusRing(g, 1, 1, w - 2, h - 2);
} else {
- g.setPaint(UIUtil.getGradientPaint(w / 2, 1, Gray._110, w / 2, h, Gray._95));
- g.fillRoundRect(0, 0, w , h , 4, 4);
+ g.setPaint(UIUtil.getGradientPaint(w / 2, 1, getBackgroundColor1(), w / 2, h, getBackgroundColor2()));
+ g.fillRoundRect(0, 0, w, h - 1 , 4, 4);
- g.setPaint(UIUtil.getGradientPaint(w / 2, 1, Gray._120.withAlpha(90), w / 2, h, Gray._105.withAlpha(90)));
- g.drawRoundRect(0, 1, w, h - 1, 4, 4);
+ g.setPaint(UIUtil.getGradientPaint(w / 2, 1, getBorderColor1(b.isEnabled()), w / 2, h, getBorderColor2(b.isEnabled())));
+ g.drawRoundRect(0, (UIUtil.isUnderDarcula() ? 1 : 0), w, h - 1, 4, 4);
- g.setPaint(Gray._40.withAlpha(180));
+ g.setPaint(getInactiveFillColor());
g.drawRoundRect(0, 0, w, h - 1, 4, 4);
}
if (b.getModel().isSelected()) {
g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g.setStroke(new BasicStroke(1 *2.0f, BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
- g.setPaint(b.isEnabled() ? Gray._30 : Gray._60);
+ g.setPaint(getShadowColor(b.isEnabled()));
g.drawLine(4, 7, 7, 11);
g.drawLine(7, 11, w, 2);
- g.setPaint(b.isEnabled() ? Gray._170 : Gray._120);
+ g.setPaint(getCheckSignColor(b.isEnabled()));
g.drawLine(4, 5, 7, 9);
g.drawLine(7, 9, w, 0);
}
@@ -142,6 +142,53 @@ public class DarculaCheckBoxUI extends MetalCheckBoxUI {
}
}
+ protected Color getInactiveFillColor() {
+ return getColor("inactiveFillColor", Gray._40.withAlpha(180));
+ }
+
+ protected Color getBorderColor1(boolean enabled) {
+ return enabled ? getColor("borderColor1", Gray._120.withAlpha(0x5a))
+ : getColor("disabledBorderColor1", Gray._120.withAlpha(90));
+ }
+
+ protected Color getBorderColor2(boolean enabled) {
+ return enabled ? getColor("borderColor2", Gray._105.withAlpha(90))
+ : getColor("disabledBorderColor2", Gray._105.withAlpha(90));
+ }
+
+ protected Color getBackgroundColor1() {
+ return getColor("backgroundColor1", Gray._110);
+ }
+
+ protected Color getBackgroundColor2() {
+ return getColor("backgroundColor2", Gray._95);
+ }
+
+ protected Color getCheckSignColor(boolean enabled) {
+ return enabled ? getColor("checkSignColor", Gray._170)
+ : getColor("checkSignColorDisabled", Gray._120);
+ }
+
+ protected Color getShadowColor(boolean enabled) {
+ return enabled ? getColor("shadowColor", Gray._30)
+ : getColor("shadowColorDisabled", Gray._60);
+ }
+
+ protected Color getFocusedBackgroundColor1(boolean armed) {
+ return armed ? getColor("focusedArmed.backgroundColor1", Gray._100)
+ : getColor("focused.backgroundColor1", Gray._120);
+ }
+
+ protected Color getFocusedBackgroundColor2(boolean armed) {
+ return armed ? getColor("focusedArmed.backgroundColor2", Gray._55)
+ : getColor("focused.backgroundColor2", Gray._75);
+ }
+
+ protected static Color getColor(String shortPropertyName, Color defaultValue) {
+ final Color color = UIManager.getColor("CheckBox.darcula." + shortPropertyName);
+ return color == null ? defaultValue : color;
+ }
+
@Override
public Icon getDefaultIcon() {
return new IconUIResource(EmptyIcon.create(20));
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java
index f1e01d7762a8..967a24ab56f2 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java
@@ -140,8 +140,9 @@ public class DarculaTextFieldUI extends BasicTextFieldUI {
Graphics2D g = (Graphics2D)graphics;
final JTextComponent c = getComponent();
final Container parent = c.getParent();
- if (parent != null) {
- g.setColor(parent.getBackground());
+ final Rectangle r = getDrawingRect();
+ if (!isSearchField(c) && parent != null) {
+ g.setColor(c.getBackground());
g.fillRect(0, 0, c.getWidth(), c.getHeight());
}
final GraphicsConfig config = new GraphicsConfig(g);
@@ -151,12 +152,12 @@ public class DarculaTextFieldUI extends BasicTextFieldUI {
final Border border = c.getBorder();
if (isSearchField(c)) {
g.setColor(c.getBackground());
- final Rectangle r = getDrawingRect();
+
int radius = r.height-1;
g.fillRoundRect(r.x, r.y, r.width, r.height-1, radius, radius);
g.setColor(c.isEnabled() ? Gray._100 : new Color(0x535353));
- if (c.hasFocus()) {
- DarculaUIUtil.paintSearchFocusRing(g, r);
+ if (c.hasFocus() && c.getClientProperty("JTextField.Search.noFocusRing") != Boolean.TRUE) {
+ DarculaUIUtil.paintSearchFocusRing(g, r);
} else {
g.drawRoundRect(r.x, r.y, r.width, r.height-1, radius, radius);
}
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.css b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.css
new file mode 100644
index 000000000000..1b9e1f0bba76
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.css
@@ -0,0 +1,383 @@
+/*
+ * 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.
+ */
+/*
+ * 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.
+ */
+body {
+ font-size: 14pt;
+ font-family: Serif;
+ font-weight: normal;
+ margin-left: 0;
+ margin-right: 0;
+ color: #bbbbbb
+}
+
+p {
+ margin-top: 15
+}
+
+h1 {
+ font-size: x-large;
+ font-weight: bold;
+ margin-top: 10;
+ margin-bottom: 10
+}
+
+h2 {
+ font-size: large;
+ font-weight: bold;
+ margin-top: 10;
+ margin-bottom: 10
+}
+
+h3 {
+ font-size: medium;
+ font-weight: bold;
+ margin-top: 10;
+ margin-bottom: 10
+}
+
+h4 {
+ font-size: small;
+ font-weight: bold;
+ margin-top: 10;
+ margin-bottom: 10
+}
+
+h5 {
+ font-size: x-small;
+ font-weight: bold;
+ margin-top: 10;
+ margin-bottom: 10
+}
+
+h6 {
+ font-size: xx-small;
+ font-weight: bold;
+ margin-top: 10;
+ margin-bottom: 10
+}
+
+li p {
+ margin-top: 0;
+ margin-bottom: 0
+}
+
+td p {
+ margin-top: 0
+}
+
+menu li p {
+ margin-top: 0;
+ margin-bottom: 0
+}
+
+menu li {
+ margin-left: 0;
+ margin-right: 0;
+ margin-top: 0;
+ margin-bottom: 0
+}
+
+menu {
+ margin-left-ltr: 40;
+ margin-right-rtl: 40;
+ margin-top: 10;
+ margin-bottom: 10
+}
+
+dir li p {
+ margin-top: 0;
+ margin-bottom: 0
+}
+
+dir li {
+ margin-left: 0;
+ margin-right: 0;
+ margin-top: 0;
+ margin-bottom: 0
+}
+
+dir {
+ margin-left-ltr: 40;
+ margin-right-rtl: 40;
+ margin-top: 10;
+ margin-bottom: 10
+}
+
+dd {
+ margin-left-ltr: 40;
+ margin-right-rtl: 40;
+ margin-top: 0;
+ margin-bottom: 0
+}
+
+dd p {
+ margin-left: 0;
+ margin-rigth: 0;
+ margin-top: 0;
+ margin-bottom: 0
+}
+
+dt {
+ margin-top: 0;
+ margin-bottom: 0
+}
+
+dl {
+ margin-left: 0;
+ margin-top: 10;
+ margin-bottom: 10
+}
+
+ol li {
+ margin-left: 0;
+ margin-right: 0;
+ margin-top: 0;
+ margin-bottom: 0
+}
+
+ol {
+ margin-top: 10;
+ margin-bottom: 10;
+ margin-left-ltr: 50;
+ margin-right-rtl: 50;
+ list-style-type: decimal
+}
+
+ol li p {
+ margin-top: 0;
+ margin-bottom: 0
+}
+
+ul li {
+ margin-left: 0;
+ margin-right: 0;
+ margin-top: 0;
+ margin-bottom: 0
+}
+
+ul {
+ margin-top: 10;
+ margin-bottom: 10;
+ margin-left-ltr: 50;
+ margin-right-rtl: 50;
+ list-style-type: disc;
+ -bullet-gap: 10
+}
+
+ul li ul li {
+ margin-left: 0;
+ margin-right: 0;
+ margin-top: 0;
+ margin-bottom: 0
+}
+
+ul li ul {
+ list-style-type: circle;
+ margin-left-ltr: 25;
+ margin-right-rtl: 25;
+}
+
+ul li ul li ul li {
+ margin-left: 0;
+ margin-right: 0;
+ margin-top: 0;
+ margin-bottom: 0
+}
+
+ul li ul li ul {
+ list-style-type: square;
+ margin-left-ltr: 25;
+ margin-right-rtl: 25
+}
+
+ul li menu {
+ list-style-type: circle;
+ margin-left-ltr: 25;
+ margin-right-rtl: 25;
+}
+
+ul li p {
+ margin-top: 0;
+ margin-bottom: 0
+}
+
+a {
+ color: #589df6;
+ text-decoration: underline
+}
+
+address {
+ color: #589df6;
+ font-style: italic
+}
+
+big {
+ font-size: x-large
+}
+
+small {
+ font-size: x-small
+}
+
+samp {
+ font-size: small;
+ font-family: Monospaced
+}
+
+cite {
+ font-style: italic
+}
+
+code {
+ font-size: small;
+ font-family: Monospaced
+}
+
+dfn {
+ font-style: italic
+}
+
+em {
+ font-style: italic
+}
+
+i {
+ font-style: italic
+}
+
+b {
+ font-weight: bold
+}
+
+kbd {
+ font-size: small;
+ font-family: Monospaced
+}
+
+s {
+ text-decoration: line-through
+}
+
+strike {
+ text-decoration: line-through
+}
+
+strong {
+ font-weight: bold
+}
+
+sub {
+ vertical-align: sub
+}
+
+sup {
+ vertical-align: sup
+}
+
+tt {
+ font-family: Monospaced
+}
+
+u {
+ text-decoration: underline
+}
+
+var {
+ font-weight: bold;
+ font-style: italic
+}
+
+table {
+ border-color: Gray;
+ border-style: outset
+}
+
+tr {
+ text-align: left
+}
+
+td {
+ border-color: Gray;
+ border-style: inset;
+ padding-left: 3;
+ padding-right: 3;
+ padding-top: 3;
+ padding-bottom: 3
+}
+
+th {
+ text-align: center;
+ font-weight: bold;
+ border-color: Gray;
+ border-style: inset;
+ padding-left: 3;
+ padding-right: 3;
+ padding-top: 3;
+ padding-bottom: 3
+}
+
+blockquote {
+ margin-top: 5;
+ margin-bottom: 5;
+ margin-left: 35;
+ margin-right: 35
+}
+
+center {
+ text-align: center
+}
+
+pre {
+ margin-top: 5;
+ margin-bottom: 5;
+ font-family: Monospaced
+}
+
+pre p {
+ margin-top: 0
+}
+
+caption {
+ caption-side: top;
+ text-align: center
+}
+
+table {
+ border: none;
+}
+
+td {
+ border: none;
+}
+
+nobr {
+ white-space: nowrap
+}
+
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties
new file mode 100644
index 000000000000..255eb042fa0b
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties
@@ -0,0 +1,144 @@
+# suppress inspection "UnusedProperty" for whole file
+intellijlaf.background=e8e8e8
+intellijlaf.selectionBackground=4696ff
+intellijlaf.textBackground=cccccc
+intellijlaf.foreground=000000
+intellijlaf.textForeground=000000
+intellijlaf.caretForeground=000000
+intellijlaf.inactiveBackground=ffffff
+intellijlaf.inactiveForeground=000000
+intellijlaf.selectionForeground=ffffff
+intellijlaf.selectionBackgroundInactive=27384C
+intellijlaf.selectionInactiveBackground=27384C
+intellijlaf.selectionForegroundInactive=000000
+window=e8e8e8
+
+text=000000
+textText=000000
+infoText=000000
+OptionPane.messageForeground=000000
+
+Menu.maxGutterIconWidth=18
+MenuItem.maxGutterIconWidth=18
+MenuItem.acceleratorDelimiter=-
+MenuItem.border=com.intellij.ide.ui.laf.darcula.ui.DarculaMenuItemBorder
+Menu.border=com.intellij.ide.ui.laf.darcula.ui.DarculaMenuItemBorder
+
+EditorPaneUI=com.intellij.ide.ui.laf.darcula.ui.DarculaEditorPaneUI
+
+control=cccccc
+link.foreground=589df6
+ScrollBarUI=com.intellij.ide.ui.laf.darcula.ui.DarculaScrollBarUI
+
+TableHeaderUI=com.intellij.ide.ui.laf.darcula.DarculaTableHeaderUI
+Table.gridColor=2c2c2c
+Table.ascendingSortIcon=AllIcons.General.SplitUp
+Table.descendingSortIcon=AllIcons.General.SplitDown
+Table.background=ffffff
+
+#just to suppress border painters
+TableHeader.cellBorder=com.intellij.ide.ui.laf.darcula.DarculaTableHeaderBorder
+
+TitledBorder.titleColor=000000
+
+MenuBar.disabledBackground=cccccc
+MenuBar.shadow=cccccc
+
+TabbedPaneUI=com.intellij.ide.ui.laf.darcula.ui.DarculaTabbedPaneUI
+TabbedPane.tabInsets=0,4,0,4
+TabbedPane.highlight=292b2d
+TabbedPane.light=444444
+TabbedPane.selected=626262
+TabbedPane.selectHighlight=3c3f41
+TabbedPane.contentBorderInsets=3,1,1,1
+TabbedPane.darkShadow=292b2d
+TabbedPane.shadow=3c3f41
+
+Separator.foreground=2d2d2d
+
+Focus.color=ff0000
+
+TextField.background=ffffff
+TextFieldUI=com.intellij.ide.ui.laf.darcula.ui.DarculaTextFieldUI
+TextField.border=com.intellij.ide.ui.laf.darcula.ui.DarculaTextBorder
+
+TextArea.selectionForeground=bbbbbb
+TextArea.background=ffffff
+
+Panel.background=e8e8e8
+
+PasswordField.background=45494A
+PasswordFieldUI=com.intellij.ide.ui.laf.darcula.ui.DarculaPasswordFieldUI
+PasswordField.border=com.intellij.ide.ui.laf.darcula.ui.DarculaTextBorder
+
+ProgressBarUI=com.intellij.ide.ui.laf.darcula.ui.DarculaProgressBarUI
+ProgressBar.border=com.intellij.ide.ui.laf.darcula.ui.DarculaProgressBarBorder
+ProgressBar.foreground=808080
+
+FormattedTextField.background=ffffff
+
+
+CheckBoxUI=com.intellij.ide.ui.laf.darcula.ui.DarculaCheckBoxUI
+CheckBox.border=com.intellij.ide.ui.laf.darcula.ui.DarculaCheckBoxBorder
+CheckBox.darcula.inactiveFillColor=00000000
+CheckBox.darcula.borderColor1=111111
+CheckBox.darcula.borderColor2=111111
+CheckBox.darcula.disabledBorderColor1=999999
+CheckBox.darcula.disabledBorderColor2=999999
+CheckBox.darcula.backgroundColor1=ffffff
+CheckBox.darcula.backgroundColor2=ffffff
+CheckBox.darcula.checkSignColor=111111
+CheckBox.darcula.checkSignColorDisabled=999999
+CheckBox.darcula.shadowColor=55555530
+CheckBox.darcula.shadowColorDisabled=eeeeee
+CheckBox.darcula.focusedArmed.backgroundColor1=ffffff
+CheckBox.darcula.focusedArmed.backgroundColor2=ffffff
+CheckBox.darcula.focused.backgroundColor1=eeeeee
+CheckBox.darcula.focused.backgroundColor2=eeeeee
+
+ComboBoxUI=com.intellij.ide.ui.laf.darcula.ui.DarculaComboBoxUI
+ComboBox.disabledBackground=3c3f41
+ComboBox.squareButton=false
+
+RadioButtonUI=com.intellij.ide.ui.laf.darcula.ui.DarculaRadioButtonUI
+
+StatusBar.topColor=2c2c2c
+StatusBar.top2Color=2c2c2c
+StatusBar.bottomColor=2c2c2c
+
+Button.border=com.intellij.ide.ui.laf.darcula.ui.DarculaButtonPainter
+ButtonUI=com.intellij.ide.ui.laf.darcula.ui.DarculaButtonUI
+Button.darcula.color1=eeeeee
+Button.darcula.color2=c0c0c0
+Button.darcula.selection.color1=3a74d1
+Button.darcula.selection.color2=3a6bc6
+Button.selectedButtonForeground=ffffff
+
+MenuItem.acceleratorForeground=eeeeee
+PopupMenu.translucentBackground=3c3f41
+
+ToolTip.background=5C5C42
+
+SpinnerUI=com.intellij.ide.ui.laf.darcula.ui.DarculaSpinnerUI
+Spinner.border=com.intellij.ide.ui.laf.darcula.ui.DarculaSpinnerBorder
+Spinner.background=3c3f41
+Spinner.arrowButtonInsets=1,1,1,1
+Spinner.editorBorderPainted=false
+
+SplitPane.highlight=3c3f41
+
+TreeUI=com.intellij.ide.ui.laf.darcula.ui.DarculaTreeUI
+Tree.background=ffffff
+
+List.background=ffffff
+
+Hyperlink.linkColor=589df6
+
+#List.background=45494A
+#Table.background=45494A
+
+#Tree.background=45494A
+Tree.collapsedIcon=AllIcons.Nodes.TreeRightArrow
+Tree.expandedIcon=AllIcons.Nodes.TreeDownArrow
+
+FileView.fileIcon=AllIcons.FileTypes.Unknown \ No newline at end of file
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_linux.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_linux.properties
new file mode 100644
index 000000000000..85d48e5b07ab
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_linux.properties
@@ -0,0 +1,7 @@
+# suppress inspection "UnusedProperty" for whole file
+darcula.selectionBackground=2F65CA
+darcula.selectionForeground=bbbbbb
+
+PopupMenu.border=com.intellij.ide.ui.laf.darcula.ui.DarculaPopupMenuBorder
+
+MenuBar.border=com.intellij.ide.ui.laf.darcula.ui.DarculaMenuBarBorder
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_windows.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_windows.properties
new file mode 100644
index 000000000000..50fd798d35cc
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_windows.properties
@@ -0,0 +1,10 @@
+# suppress inspection "UnusedProperty" for whole file
+darcula.selectionBackground=4A6EB7
+darcula.selectionForeground=ffffff
+
+PopupMenu.border=com.intellij.ide.ui.laf.darcula.ui.DarculaPopupMenuBorder
+
+MenuBar.border=com.intellij.ide.ui.laf.darcula.ui.DarculaMenuBarBorder
+#InternalFrameUI=com.intellij.ide.ui.laf.darcula.ui.DarculaInternalFrameUI
+#InternalFrame.border=com.intellij.ide.ui.laf.darcula.ui.DarculaInternalBorder
+#RootPaneUI=com.intellij.ide.ui.laf.darcula.ui.DarculaRootPaneUI \ No newline at end of file
diff --git a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java
index 31dd1d938891..167f16b6799e 100644
--- a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java
+++ b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java
@@ -103,8 +103,8 @@ public class StartupUtil {
Logger.setFactory(LoggerFactory.class);
Logger log = Logger.getInstance(Main.class);
startLogging(log);
- fixProcessEnvironment(log);
loadSystemLibraries(log);
+ fixProcessEnvironment(log);
if (!Main.isHeadless()) {
AppUIUtil.updateWindowIcon(JOptionPane.getRootFrame());
diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java
index 92e20275a0f8..5a2f15613327 100644
--- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionToolbarImpl.java
@@ -304,7 +304,8 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
final AnAction searchEverywhereAction = ActionManager.getInstance().getAction("SearchEverywhere");
if (searchEverywhereAction != null) {
try {
- final JComponent searchEverywhere = getCustomComponent(searchEverywhereAction.getClass().newInstance());
+ final CustomComponentAction searchEveryWhereAction = (CustomComponentAction)searchEverywhereAction.getClass().newInstance();
+ final JComponent searchEverywhere = searchEveryWhereAction.createCustomComponent(searchEverywhereAction.getTemplatePresentation());
searchEverywhere.putClientProperty("SEARCH_EVERYWHERE", Boolean.TRUE);
add(searchEverywhere);
}
@@ -724,7 +725,11 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
final Component component = getComponent(getComponentCount() - 1);
if (component instanceof JComponent && ((JComponent)component).getClientProperty("SEARCH_EVERYWHERE") == Boolean.TRUE) {
final Rectangle rect = bounds.get(bounds.size() - 1);
- bounds.set(bounds.size() - 1, new Rectangle(size2Fit.width - rect.width - 5, rect.y, rect.width, rect.height));
+ int max = 0;
+ for (int i = 0; i < bounds.size() - 2; i++) {
+ max = Math.max(max, bounds.get(i).height);
+ }
+ bounds.set(bounds.size() - 1, new Rectangle(size2Fit.width - 25, 0, 25, max));
}
}
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java
index dd2490fd916c..14346fe66407 100755
--- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java
@@ -49,6 +49,7 @@ public class ApplicationInfoImpl extends ApplicationInfoEx implements JDOMExtern
private String myMajorVersion = null;
private String myMinorVersion = null;
private String myBuildNumber = null;
+ private String myApiVersion = null;
private String myCompanyName = "JetBrains s.r.o.";
private String myCompanyUrl = "http://www.jetbrains.com/";
private Color myProgressColor = null;
@@ -110,6 +111,7 @@ public class ApplicationInfoImpl extends ApplicationInfoEx implements JDOMExtern
@NonNls private static final String ELEMENT_BUILD = "build";
@NonNls private static final String ELEMENT_COMPANY = "company";
@NonNls private static final String ATTRIBUTE_NUMBER = "number";
+ @NonNls private static final String ATTRIBUTE_API_VERSION = "apiVersion";
@NonNls private static final String ATTRIBUTE_DATE = "date";
@NonNls private static final String ATTRIBUTE_MAJOR_RELEASE_DATE = "majorReleaseDate";
@NonNls private static final String ELEMENT_LOGO = "logo";
@@ -184,6 +186,10 @@ public class ApplicationInfoImpl extends ApplicationInfoEx implements JDOMExtern
@Override
public BuildNumber getBuild() {
+ return BuildNumber.fromString(myBuildNumber, getProductPrefix());
+ }
+
+ private static String getProductPrefix() {
String prefix = null;
if (PlatformUtils.isCommunity()) {
prefix = "IC";
@@ -191,7 +197,15 @@ public class ApplicationInfoImpl extends ApplicationInfoEx implements JDOMExtern
else if (PlatformUtils.isIdea()) {
prefix = "IU";
}
- return BuildNumber.fromString(myBuildNumber, prefix);
+ return prefix;
+ }
+
+ @Override
+ public String getApiVersion() {
+ if (myApiVersion != null) {
+ return BuildNumber.fromString(myApiVersion, getProductPrefix()).asString();
+ }
+ return getBuild().asString();
}
public String getMajorVersion() {
@@ -465,7 +479,8 @@ public class ApplicationInfoImpl extends ApplicationInfoEx implements JDOMExtern
Element buildElement = parentNode.getChild(ELEMENT_BUILD);
if (buildElement != null) {
myBuildNumber = buildElement.getAttributeValue(ATTRIBUTE_NUMBER);
- PluginManagerCore.BUILD_NUMBER = myBuildNumber;
+ myApiVersion = buildElement.getAttributeValue(ATTRIBUTE_API_VERSION);
+ PluginManagerCore.BUILD_NUMBER = myApiVersion != null ? myApiVersion : myBuildNumber;
String dateString = buildElement.getAttributeValue(ATTRIBUTE_DATE);
if (dateString.equals("__BUILD_DATE__")) {
myBuildDate = new GregorianCalendar();
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java
index b75a716c9f24..8685b846b0a3 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java
@@ -16,11 +16,11 @@
package com.intellij.openapi.components.impl.stores;
import com.intellij.openapi.components.*;
+import com.intellij.openapi.options.StreamProvider;
import com.intellij.openapi.project.impl.ProjectImpl;
import com.intellij.openapi.project.impl.ProjectManagerImpl;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.options.StreamProvider;
import com.intellij.util.io.fs.IFile;
import org.jdom.Document;
import org.jdom.Element;
@@ -133,7 +133,7 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl {
@Override
@Nullable
- public StateStorage getFileStateStorage(String fileName) {
+ public StateStorage getFileStateStorage(@NotNull String fileSpec) {
return storage;
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java
index 734b242afcae..f6a4e11e5aa5 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java
@@ -32,6 +32,7 @@ class ProjectStateStorageManager extends StateStorageManagerImpl {
myProject = project;
}
+ @Override
protected StorageData createStorageData(String storageSpec) {
if (storageSpec.equals(StoragePathMacros.PROJECT_FILE)) return createIprStorageData();
if (storageSpec.equals(StoragePathMacros.WORKSPACE_FILE)) return createWsStorageData();
@@ -46,6 +47,7 @@ class ProjectStateStorageManager extends StateStorageManagerImpl {
return new ProjectStoreImpl.IprStorageData(ROOT_TAG_NAME, myProject);
}
+ @Override
protected String getOldStorageSpec(Object component, final String componentName, final StateStorageOperation operation) throws
StateStorageException {
final ComponentConfig config = myProject.getConfig(component.getClass());
@@ -65,6 +67,7 @@ class ProjectStateStorageManager extends StateStorageManagerImpl {
return name;
}
+ @Override
protected String getVersionsFilePath() {
return PathManager.getConfigPath() + "/componentVersions/" + "project" + myProject.getLocationHash() + ".xml";
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java
index 499eda682b02..0e2828e988a3 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java
@@ -37,10 +37,10 @@ public interface StateStorageManager {
TrackingPathMacroSubstitutor getMacroSubstitutor();
@Nullable
- StateStorage getStateStorage(@NotNull Storage storageSpec) throws StateStorageException;
+ StateStorage getStateStorage(@NotNull Storage storageSpec) throws StateStorageException;
@Nullable
- StateStorage getFileStateStorage(String fileName);
+ StateStorage getFileStateStorage(@NotNull String fileSpec);
Collection<String> getStorageFileNames();
@@ -48,8 +48,10 @@ public interface StateStorageManager {
@NotNull
ExternalizationSession startExternalization();
+
@NotNull
- SaveSession startSave(@NotNull ExternalizationSession externalizationSession) ;
+ SaveSession startSave(@NotNull ExternalizationSession externalizationSession);
+
void finishSave(@NotNull SaveSession saveSession);
@Nullable
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java
index 25c940a36d45..c7c4aec145d0 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java
@@ -93,7 +93,6 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
}
@Override
- @SuppressWarnings({"unchecked"})
public TrackingPathMacroSubstitutor getMacroSubstitutor() {
return myPathMacroSubstitutor;
}
@@ -125,7 +124,7 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
@Override
@Nullable
- public StateStorage getFileStateStorage(final String fileName) {
+ public StateStorage getFileStateStorage(@NotNull String fileName) {
myStorageLock.lock();
try {
StateStorage stateStorage = myStorages.get(fileName);
@@ -238,7 +237,7 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
}
String extension = FileUtilRt.getExtension(new File(expandedFile).getName());
- if (!ourHeadlessEnvironment && extension.length() == 0) {
+ if (!ourHeadlessEnvironment && extension.isEmpty()) {
throw new IllegalArgumentException("Extension is missing for storage file: " + expandedFile);
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ContextMenuImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ContextMenuImpl.java
index 6674322c21e9..28a7c2204265 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ContextMenuImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ContextMenuImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -28,7 +28,6 @@ import com.intellij.openapi.editor.event.EditorMouseEvent;
import com.intellij.openapi.editor.event.EditorMouseMotionAdapter;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.keymap.ex.KeymapManagerEx;
-import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.impl.http.HttpVirtualFile;
import com.intellij.util.ui.UIUtil;
@@ -208,7 +207,7 @@ public class ContextMenuImpl extends JPanel implements Disposable {
}
final VirtualFile file = FileDocumentManager.getInstance().getFile(document);
- return file != null && file.isValid() && (file.getFileSystem() == LocalFileSystem.getInstance() || file instanceof HttpVirtualFile);
+ return file != null && file.isValid() && (file.isInLocalFileSystem() || file instanceof HttpVirtualFile);
}
private void scheduleHide() {
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java
index 55dc5d16c58b..45831364ccfb 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java
@@ -1907,6 +1907,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
LogicalPosition clipEndPosition = xyToLogicalPosition(new Point(0, clip.y + clip.height + getLineHeight()));
int clipEndOffset = logicalPositionToOffset(clipEndPosition);
paintBackgrounds(g, clip, clipStartPosition, clipStartVisualPos, clipStartOffset, clipEndOffset);
+ if (paintPlaceholderText(g, clip)) return;
+
paintRectangularSelection(g);
paintRightMargin(g, clip);
paintCustomRenderers(g, clipStartOffset, clipEndOffset);
@@ -1914,7 +1916,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
paintLineMarkersSeparators(g, clip, docMarkup, clipStartOffset, clipEndOffset);
paintLineMarkersSeparators(g, clip, myMarkupModel, clipStartOffset, clipEndOffset);
paintText(g, clip, clipStartPosition, clipStartOffset, clipEndOffset);
- paintPlaceholderText(g, clip);
paintSegmentHighlightersBorderAndAfterEndOfLine(g, clip, clipStartOffset, clipEndOffset, docMarkup);
BorderEffect borderEffect = new BorderEffect(this, g, clipStartOffset, clipEndOffset);
borderEffect.paintHighlighters(getHighlighter());
@@ -2775,10 +2776,10 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
flushCachedChars(g);
}
- private void paintPlaceholderText(@NotNull Graphics g, @NotNull Rectangle clip) {
+ private boolean paintPlaceholderText(@NotNull Graphics g, @NotNull Rectangle clip) {
CharSequence hintText = myPlaceholderText;
if (myDocument.getTextLength() > 0 || hintText == null || hintText.length() == 0) {
- return;
+ return false;
}
if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() == myEditorComponent) {
@@ -2788,6 +2789,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
myLastBackgroundPosition = new Point(0, 0);
myLastBackgroundWidth = myLastPaintedPlaceholderWidth;
flushBackground(g, clip);
+ return false;
}
else {
myLastPaintedPlaceholderWidth = drawString(
@@ -2795,6 +2797,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
myFoldingModel.getPlaceholderAttributes().getForegroundColor()
);
flushCachedChars(g);
+ return true;
}
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java
index 174324569212..9a0b1a48bca9 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java
@@ -27,6 +27,7 @@ package com.intellij.openapi.editor.impl;
import com.intellij.codeInsight.hint.*;
import com.intellij.icons.AllIcons;
import com.intellij.ide.ui.UISettings;
+import com.intellij.ide.ui.UISettingsListener;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
@@ -38,13 +39,16 @@ import com.intellij.openapi.editor.actionSystem.DocCommandGroupId;
import com.intellij.openapi.editor.ex.*;
import com.intellij.openapi.editor.markup.ErrorStripeRenderer;
import com.intellij.openapi.editor.markup.RangeHighlighter;
+import com.intellij.openapi.fileEditor.impl.EditorWindowHolder;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.ProperTextRange;
-import com.intellij.openapi.wm.impl.IdeRootPane;
+import com.intellij.openapi.util.registry.Registry;
import com.intellij.ui.*;
import com.intellij.ui.awt.RelativePoint;
+import com.intellij.util.Alarm;
+import com.intellij.util.IJSwingUtilities;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.ButtonlessScrollBarUI;
@@ -58,14 +62,15 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.plaf.ScrollBarUI;
import java.awt.*;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.awt.event.MouseMotionListener;
+import java.awt.event.*;
import java.awt.geom.AffineTransform;
+import java.awt.geom.Area;
+import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.util.*;
import java.util.List;
import java.util.Queue;
+import java.util.concurrent.atomic.AtomicReference;
public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMarkupModel {
private static final TooltipGroup ERROR_STRIPE_TOOLTIP_GROUP = new TooltipGroup("ERROR_STRIPE_TOOLTIP_GROUP", 0);
@@ -89,8 +94,10 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
private int myMinMarkHeight = 3;
private static final int myPreviewLines = 5;// Actually preview has myPreviewLines * 2 + 1 lines (above + below + current one)
+ private static final int myCachePreviewLines = 100;// Actually cache image has myCachePreviewLines * 2 + 1 lines (above + below + current one)
private LightweightHint myEditorPreviewHint = null;
private final EditorFragmentRenderer myEditorFragmentRenderer;
+ private int myRowAdjuster = 0;
EditorMarkupModelImpl(@NotNull EditorImpl editor) {
super(editor.getDocument());
@@ -157,7 +164,7 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
boolean isVisible = area.contains(area.x, realY);//area.y < realY && area.y + area.height > realY;
TooltipRenderer bigRenderer;
- if (!(UIUtil.getRootPane(myEditor.getComponent()) instanceof IdeRootPane) || isVisible) {
+ if (IJSwingUtilities.findParentByInterface(myEditor.getComponent(), EditorWindowHolder.class) == null || isVisible || !UISettings.getInstance().SHOW_EDITOR_TOOLTIP) {
final Set<RangeHighlighter> highlighters = new THashSet<RangeHighlighter>();
getNearestHighlighters(this, me.getY(), highlighters);
getNearestHighlighters((MarkupModelEx)DocumentMarkupModel.forDocument(myEditor.getDocument(), getEditor().getProject(), true), me.getY(), highlighters);
@@ -181,6 +188,8 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
}
return false;
} else {
+ if (e.getX() > e.getComponent().getWidth() - 2) return false;//The most right edge is not active for lens
+ me = new MouseEvent(me.getComponent(), me.getID(), me.getWhen(), me.getModifiers(), me.getX(), me.getY() + myRowAdjuster, me.getClickCount(), me.isPopupTrigger());
final List<RangeHighlighterEx> highlighters = new ArrayList<RangeHighlighterEx>();
collectRangeHighlighters(this, line, highlighters);
collectRangeHighlighters((MarkupModelEx)DocumentMarkupModel.forDocument(myEditor.getDocument(), getEditor().getProject(), true), line,
@@ -446,7 +455,7 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
}
}
- private class MyErrorPanel extends ButtonlessScrollBarUI implements MouseMotionListener, MouseListener {
+ private class MyErrorPanel extends ButtonlessScrollBarUI implements MouseMotionListener, MouseListener, MouseWheelListener, UISettingsListener {
private PopupHandler myHandler;
private JButton myErrorStripeButton;
private BufferedImage myCachedTrack;
@@ -462,8 +471,10 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
super.installListeners();
scrollbar.addMouseMotionListener(this);
scrollbar.addMouseListener(this);
+ scrollbar.addMouseWheelListener(this);
myErrorStripeButton.addMouseMotionListener(this);
myErrorStripeButton.addMouseListener(this);
+ UISettings.getInstance().addUISettingsListener(this);
}
@Override
@@ -472,10 +483,18 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
scrollbar.removeMouseListener(this);
myErrorStripeButton.removeMouseMotionListener(this);
myErrorStripeButton.removeMouseListener(this);
+ UISettings.getInstance().removeUISettingsListener(this);
super.uninstallListeners();
}
@Override
+ public void uiSettingsChanged(UISettings source) {
+ if (!UISettings.getInstance().SHOW_EDITOR_TOOLTIP) {
+ hideMyEditorPreviewHint();
+ }
+ }
+
+ @Override
protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) {
if (UISettings.getInstance().PRESENTATION_MODE) {
super.paintThumb(g, c, thumbBounds);
@@ -775,6 +794,14 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
}
}
+ @Override
+ public void mouseWheelMoved(MouseWheelEvent e) {
+ if (myEditorPreviewHint == null) return;
+ myRowAdjuster += (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL ? e.getUnitsToScroll() * e.getScrollAmount() :
+ e.getWheelRotation() < 0 ? -e.getScrollAmount() : e.getScrollAmount()) / myEditor.getLineHeight();
+ showToolTipByMouseMove(e);
+ }
+
private TrafficTooltipRenderer myTrafficTooltipRenderer;
private void showTrafficLightTooltip(MouseEvent e) {
@@ -797,16 +824,21 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
}
private void cancelMyToolTips(final MouseEvent e, boolean checkIfShouldSurvive) {
- if (myEditorPreviewHint != null) {
- myEditorPreviewHint.hide();
- myEditorPreviewHint = null;
- }
+ hideMyEditorPreviewHint();
final TooltipController tooltipController = TooltipController.getInstance();
if (!checkIfShouldSurvive || !tooltipController.shouldSurvive(e)) {
tooltipController.cancelTooltip(ERROR_STRIPE_TOOLTIP_GROUP, e, true);
}
}
+ private void hideMyEditorPreviewHint() {
+ if (myEditorPreviewHint != null) {
+ myEditorPreviewHint.hide();
+ myEditorPreviewHint = null;
+ myRowAdjuster = 0;
+ }
+ }
+
@Override
public void mouseEntered(MouseEvent e) {
}
@@ -1016,23 +1048,44 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
}
private class EditorFragmentRenderer implements TooltipRenderer {
private int myLine;
- private Collection<RangeHighlighterEx> myHighlighters;
+ private final List<RangeHighlighterEx> myHighlighters = new ArrayList<RangeHighlighterEx>();
private BufferedImage myImage;
+ private BufferedImage myCacheImage;
+ private int myCacheStartLine;
+ private int myCacheEndLine;
private int myStartLine;
private int myEndLine;
private int myRelativeY;
+ private boolean myDelayed = false;
+ private final AtomicReference<Point> myPointHolder = new AtomicReference<Point>();
+ private final AtomicReference<HintHint> myHintHolder = new AtomicReference<HintHint>();
private EditorFragmentRenderer() {
update(-1, Collections.<RangeHighlighterEx>emptyList());
}
- public void update(int currentLine, Collection<RangeHighlighterEx> rangeHighlighters) {
- myLine = currentLine;
- myHighlighters = rangeHighlighters;
+ void update(int currentLine, Collection<RangeHighlighterEx> rangeHighlighters) {
+ myLine = Math.min(myEditor.getDocument().getLineCount() - 1, Math.max(0, currentLine + myRowAdjuster));
+ myHighlighters.clear();
myImage = null;
if (currentLine ==-1) return;
myStartLine = Math.max(0, myLine - myPreviewLines);
myEndLine = Math.min(myEditor.getDocument().getLineCount() - 1, myLine + myPreviewLines + 1);
+ int popupStartOffset = myEditor.getDocument().getLineStartOffset(myStartLine);
+ int popupEndOffset = myEditor.getDocument().getLineEndOffset(myEndLine);
+ for (RangeHighlighterEx rangeHighlighter : rangeHighlighters) {
+ if (rangeHighlighter.getEndOffset()> popupStartOffset && rangeHighlighter.getStartOffset() < popupEndOffset) {
+ myHighlighters.add(rangeHighlighter);
+ }
+ }
+ Collections.sort(myHighlighters, new Comparator<RangeHighlighterEx>() {
+ public int compare(RangeHighlighterEx ex1, RangeHighlighterEx ex2) {
+ LogicalPosition startPos1 = myEditor.offsetToLogicalPosition(ex1.getAffectedAreaStartOffset());
+ LogicalPosition startPos2 = myEditor.offsetToLogicalPosition(ex2.getAffectedAreaStartOffset());
+ if (startPos1.line != startPos2.line) return 0;
+ return startPos1.column - startPos2.column;
+ }
+ });
}
@Override
@@ -1040,65 +1093,70 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
@NotNull Point p,
boolean alignToRight,
@NotNull TooltipGroup group,
- @NotNull HintHint hintInfo) {
+ @NotNull final HintHint hintInfo) {
final HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl();
+ boolean needDelay = false;
if (myEditorPreviewHint == null) {
+ needDelay = true;
final JPanel editorFragmentPreviewPanel = new JPanel() {
private static final int R = 6;
- private static final int LEFT_INDENT = BalloonImpl.ARC + 5;
+ private static final int LEFT_INDENT = BalloonImpl.ARC;// + 5;
@Override
public Dimension getPreferredSize() {
int width = myEditor.getGutterComponentEx().getWidth();
width += Math.min(myEditor.getScrollingModel().getVisibleArea().width, myEditor.getContentComponent().getWidth());
+ if (UISettings.getInstance().HIDE_TOOL_STRIPES) width -=2;
return new Dimension(width - BalloonImpl.POINTER_WIDTH - LEFT_INDENT, myEditor.getLineHeight() * (myEndLine - myStartLine));
}
@Override
protected void paintComponent(Graphics g) {
if (myLine ==-1) return;
+ Dimension size = getPreferredSize();
+ EditorGutterComponentEx gutterComponentEx = myEditor.getGutterComponentEx();
+ int gutterWidth = gutterComponentEx.getWidth();
+ if (myCacheImage == null || myCacheStartLine > myStartLine || myCacheEndLine < myEndLine) {
+ int oldCacheLineCount = myCacheEndLine - myCacheStartLine;
+ myCacheStartLine = Math.max(0, myLine - myCachePreviewLines);
+ myCacheEndLine = Math.min(myEditor.getDocument().getLineCount() - 1, myLine + myCachePreviewLines + 1);
+ if (myCacheImage == null || oldCacheLineCount != (myCacheEndLine - myCacheStartLine)) {
+ myCacheImage = UIUtil.createImage(size.width, myEditor.getLineHeight() * 2 * myCachePreviewLines + 1, BufferedImage.TYPE_INT_RGB);
+ }
+ Graphics2D cg = myCacheImage.createGraphics();
+ final AffineTransform t = cg.getTransform();
+ UISettings.setupAntialiasing(cg);
+ int lineShift = -myEditor.getLineHeight() * myCacheStartLine;
+
+ AffineTransform translateInstance = AffineTransform.getTranslateInstance(0, lineShift);
+ translateInstance.preConcatenate(t);
+ cg.setTransform(translateInstance);
+
+ cg.setClip(0, 0, gutterWidth, gutterComponentEx.getHeight());
+ gutterComponentEx.paint(cg);
+ translateInstance = AffineTransform.getTranslateInstance(gutterWidth, lineShift);
+ translateInstance.preConcatenate(t);
+ cg.setTransform(translateInstance);
+ EditorComponentImpl contentComponent = myEditor.getContentComponent();
+ cg.setClip(0, 0, contentComponent.getWidth(), contentComponent.getHeight());
+ contentComponent.paint(cg);
+ }
if (myImage == null) {
myRelativeY = SwingUtilities.convertPoint(this, 0, 0, myEditor.getScrollPane()).y;
- Dimension size = getPreferredSize();
myImage = UIUtil.createImage(size.width, size.height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = myImage.createGraphics();
- AffineTransform transform = g2d.getTransform();
+ final AffineTransform transform = g2d.getTransform();
UISettings.setupAntialiasing(g2d);
+ GraphicsUtil.setupAAPainting(g2d);
g2d.setColor(myEditor.getBackgroundColor());
g2d.fillRect(0, 0, getWidth(), getHeight());
- int lineShift = -myEditor.getLineHeight() * myStartLine;//first fragment line offset
- int popupStartOffset = myEditor.getDocument().getLineStartOffset(myStartLine);
- int popupEndOffset = myEditor.getDocument().getLineEndOffset(myEndLine);
- List<RangeHighlighterEx> exs = new ArrayList<RangeHighlighterEx>();
- for (RangeHighlighterEx rangeHighlighter : myHighlighters) {
- if (rangeHighlighter.getEndOffset()> popupStartOffset && rangeHighlighter.getStartOffset() < popupEndOffset) {
- exs.add(rangeHighlighter);
- }
- }
- AffineTransform translateInstance = AffineTransform.getTranslateInstance(-LEFT_INDENT, lineShift);
- translateInstance.preConcatenate(transform);
- g2d.setTransform(translateInstance);
- EditorGutterComponentEx gutterComponentEx = myEditor.getGutterComponentEx();
- int width = gutterComponentEx.getWidth();
- g2d.setClip(0, 0, width, gutterComponentEx.getHeight());
- gutterComponentEx.paint(g2d);
- JComponent contentComponent = myEditor.getContentComponent();
- g2d.setClip(width, 0, contentComponent.getWidth(), contentComponent.getHeight());
- translateInstance = AffineTransform.getTranslateInstance(width - LEFT_INDENT, lineShift);
+ AffineTransform translateInstance = AffineTransform.getTranslateInstance(-LEFT_INDENT + gutterWidth, myEditor.getLineHeight() * (myCacheStartLine - myStartLine));
translateInstance.preConcatenate(transform);
g2d.setTransform(translateInstance);
- contentComponent.paint(g2d);
- Collections.sort(exs, new Comparator<RangeHighlighterEx>() {
- public int compare(RangeHighlighterEx ex1, RangeHighlighterEx ex2) {
- LogicalPosition startPos1 = myEditor.offsetToLogicalPosition(ex1.getAffectedAreaStartOffset());
- LogicalPosition startPos2 = myEditor.offsetToLogicalPosition(ex2.getAffectedAreaStartOffset());
- if (startPos1.line != startPos2.line) return 0;
- return startPos1.column - startPos2.column;
- }
- });
+ UIUtil.drawImage(g2d, myCacheImage, -gutterWidth, 0, null);
TIntIntHashMap rightEdges = new TIntIntHashMap();
- for (RangeHighlighterEx ex : exs) {
- //int hStartOffset = ex.getAffectedAreaStartOffset();
+ int h = myEditor.getLineHeight() - 2;
+ for (RangeHighlighterEx ex : myHighlighters) {
int hEndOffset = ex.getAffectedAreaEndOffset();
Object tooltip = ex.getErrorStripeTooltip();
if (tooltip == null) continue;
@@ -1111,41 +1169,93 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
Point placeToShow = myEditor.logicalPositionToXY(logicalPosition);
logicalPosition = myEditor.xyToLogicalPosition(placeToShow);//wraps&foldings workaround
placeToShow.x += R * 3 / 2;
- placeToShow.y += myEditor.getLineHeight() - R/2;
+ placeToShow.y -= myCacheStartLine * myEditor.getLineHeight();
int w = g2d.getFontMetrics().stringWidth(s);
int a = g2d.getFontMetrics().getAscent();
- int h = myEditor.getLineHeight();
int rightEdge = rightEdges.get(logicalPosition.line);
placeToShow.x = Math.max(placeToShow.x, rightEdge);
rightEdge = Math.max(rightEdge, placeToShow.x + w + 3 * R);
rightEdges.put(logicalPosition.line, rightEdge);
- GraphicsUtil.setupAAPainting(g2d);
g2d.setColor(MessageType.WARNING.getPopupBackground());
- g2d.fillRoundRect(placeToShow.x - R, placeToShow.y - a, w + 2 * R, h, R, R);
+ g2d.fillRoundRect(placeToShow.x, placeToShow.y, w + 2 * R, h, R, R);
g2d.setColor(new JBColor(JBColor.GRAY, Gray._200));
- g2d.drawRoundRect(placeToShow.x - R, placeToShow.y - a, w + 2 * R, h, R, R);
+ g2d.drawRoundRect(placeToShow.x, placeToShow.y, w + 2 * R, h, R, R);
g2d.setColor(JBColor.foreground());
- g2d.drawString(s, placeToShow.x, placeToShow.y);
+ g2d.drawString(s, placeToShow.x + R, placeToShow.y - g2d.getFontMetrics().getDescent() + R/2 + a);
}
}
UIUtil.drawImage(g, myImage, 0, 0, this);
+ //Add glass effect
+ GraphicsUtil.setupAAPainting(g);
+ Shape s = new Rectangle(0, 0, size.width, size.height);
+ Graphics2D g2 = (Graphics2D)g;
+ double cx = size.width / 2;
+ double cy = 0;
+ double rx = size.width / 10;
+ int ry = myEditor.getLineHeight() * 2;
+ g2.setPaint(new GradientPaint(0, 0, new Color(255, 255, 255, 80), 0, ry, new Color(255, 255, 255, 40)));
+ double pseudoMajorAxis = size.width - rx * 9 / 5;
+ Shape topShape1 = new Ellipse2D.Double(cx - rx - pseudoMajorAxis / 2, cy - ry, 2 * rx, 2 * ry);
+ Shape topShape2 = new Ellipse2D.Double(cx - rx + pseudoMajorAxis / 2, cy - ry, 2 * rx, 2 * ry);
+ Area topArea = new Area(topShape1);
+ topArea.add(new Area(topShape2));
+ topArea.add(new Area(new Rectangle.Double(cx - pseudoMajorAxis / 2, cy, pseudoMajorAxis, ry)));
+ g2.fill(topArea);
+ Area bottomArea = new Area(s);
+ bottomArea.subtract(topArea);
+ g2.setPaint(new GradientPaint(0, size.height - ry, new Color(0, 0, 0, 10), 0, size.height, new Color(255, 255, 255, 30)));
+ g2.fill(bottomArea);
+ }
+ };
+ myEditorPreviewHint = new LightweightHint(editorFragmentPreviewPanel) {
+
+ @Override
+ public void hide(boolean ok) {
+ super.hide(ok);
+ if (myCacheImage != null) {
+ myCacheImage = null;
+ myCacheStartLine = -1;
+ myCacheEndLine = -1;
+ }
+ myDelayed = false;
}
};
- myEditorPreviewHint = new LightweightHint(editorFragmentPreviewPanel);
}
- Point point = hintInfo.getOriginalPoint();
+ Point point = new Point(hintInfo.getOriginalPoint());
hintInfo.setTextBg(myEditor.getColorsScheme().getDefaultBackground());
hintInfo.setBorderColor(new JBColor(Gray._0, Gray._111));
point = SwingUtilities.convertPoint(((EditorImpl)editor).getVerticalScrollBar(), point, myEditor.getComponent().getRootPane());
- hintManager.showEditorHint(myEditorPreviewHint, myEditor, point, HintManager.HIDE_BY_ANY_KEY |
- HintManager.HIDE_BY_TEXT_CHANGE |
- HintManager.HIDE_BY_MOUSEOVER |
- HintManager.HIDE_BY_ESCAPE |
- HintManager.HIDE_BY_SCROLLING, 0, false, hintInfo);
+ myPointHolder.set(point);
+ myHintHolder.set(hintInfo);
+ if (needDelay) {
+ myDelayed = true;
+ Alarm alarm = new Alarm();
+ alarm.addRequest(new Runnable() {
+ @Override
+ public void run() {
+ if (myEditorPreviewHint == null || !myDelayed) return;
+ hintManager.showEditorHint(myEditorPreviewHint, myEditor, myPointHolder.get(), HintManager.HIDE_BY_ANY_KEY |
+ HintManager.HIDE_BY_TEXT_CHANGE |
+ HintManager.HIDE_BY_MOUSEOVER |
+ HintManager.HIDE_BY_ESCAPE |
+ HintManager.HIDE_BY_SCROLLING, 0, false,
+ myHintHolder.get());
+ myDelayed = false;
+ }
+ }, Registry.intValue("ide.tooltip.initialDelay"));
+ }
+ else if (!myDelayed) {
+ hintManager.showEditorHint(myEditorPreviewHint, myEditor, point, HintManager.HIDE_BY_ANY_KEY |
+ HintManager.HIDE_BY_TEXT_CHANGE |
+ HintManager.HIDE_BY_MOUSEOVER |
+ HintManager.HIDE_BY_ESCAPE |
+ HintManager.HIDE_BY_SCROLLING, 0, false,
+ hintInfo);
+ }
return myEditorPreviewHint;
}
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java
index 6a1e53fb7b0e..d4daeac2e34c 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java
@@ -21,7 +21,6 @@ import com.intellij.ide.ui.UISettings;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.openapi.actionSystem.DataProvider;
-import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
@@ -643,7 +642,9 @@ public class EditorWindow {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
- myTabbedPane.setSelectedIndex(index, focusEditor);
+ if (myTabbedPane != null) {
+ myTabbedPane.setSelectedIndex(index, focusEditor);
+ }
}
});
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java
index 26825b10eb81..8ebab174da4c 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java
@@ -17,7 +17,6 @@ package com.intellij.openapi.fileEditor.impl;
import com.intellij.ide.actions.ShowFilePathAction;
import com.intellij.ide.ui.UISettings;
-import com.intellij.openapi.actionSystem.CustomShortcutSet;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.actionSystem.KeyboardShortcut;
import com.intellij.openapi.actionSystem.Shortcut;
@@ -28,6 +27,7 @@ import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.impl.text.FileDropHandler;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.keymap.KeymapUtil;
+import com.intellij.openapi.keymap.MacKeymapUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.util.*;
@@ -40,6 +40,7 @@ import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.openapi.wm.impl.FrameTitleBuilder;
import com.intellij.openapi.wm.impl.IdeFrameImpl;
import com.intellij.openapi.wm.impl.IdePanePanel;
+import com.intellij.ui.ColorUtil;
import com.intellij.ui.Gray;
import com.intellij.ui.JBColor;
import com.intellij.ui.awt.RelativePoint;
@@ -156,16 +157,21 @@ public class EditorsSplitters extends IdePanePanel {
g.drawLine(0, 0, getWidth(), 0);
}
+ boolean isDarkBackground = ColorUtil.isDark(getBackground().darker());
+
if (showEmptyText()) {
UIUtil.applyRenderingHints(g);
- g.setColor(new JBColor(Gray._100, Gray._160));
+ g.setColor(new JBColor(isDarkBackground ? Gray._230 : Gray._100, Gray._160));
g.setFont(UIUtil.getLabelFont().deriveFont(UIUtil.isUnderDarcula() ? 24f : 18f));
- final UIUtil.TextPainter painter = new UIUtil.TextPainter().withShadow(true).withLineSpacing(1.4f);
- painter.appendLine("No files are open").underlined(new JBColor(Gray._150, Gray._100));
+ final UIUtil.TextPainter painter = new UIUtil.TextPainter().withLineSpacing(1.4f);
+ if (!isDarkBackground) {
+ painter.withShadow(true);
+ }
+ painter.appendLine("No files are open").underlined(new JBColor(isDarkBackground ? Gray._210 : Gray._150, Gray._100));
if (Registry.is("search.everywhere.enabled")) {
- painter.appendLine("Search Everywhere with " + KeymapUtil.getShortcutText(CustomShortcutSet.fromString("shift SPACE").getShortcuts()[0]))
+ painter.appendLine("Search Everywhere with Double " + (SystemInfo.isMac ? MacKeymapUtil.SHIFT : "Shift"))
.smaller().withBullet();
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableWrapper.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableWrapper.java
index e981d43b83f5..877e75cde10d 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableWrapper.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableWrapper.java
@@ -76,7 +76,7 @@ public class ConfigurableWrapper implements SearchableConfigurable {
private final ConfigurableEP myEp;
- public ConfigurableWrapper(ConfigurableEP ep) {
+ private ConfigurableWrapper(ConfigurableEP ep) {
myEp = ep;
}
@@ -162,7 +162,7 @@ public class ConfigurableWrapper implements SearchableConfigurable {
private Configurable[] myKids;
- public CompositeWrapper(ConfigurableEP ep, Configurable... kids) {
+ private CompositeWrapper(ConfigurableEP ep, Configurable... kids) {
super(ep);
if (ep.dynamic) {
kids = ((Composite)getConfigurable()).getConfigurables();
diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java
index c79b5cc9ed57..839b9daac2f2 100644
--- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java
+++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java
@@ -362,7 +362,7 @@ public class PluginDownloader {
}
if (url == null) {
String uuid = UpdateChecker.getInstallationUID(PropertiesComponent.getInstance());
- String buildNumber = ApplicationInfo.getInstance().getBuild().asString();
+ String buildNumber = ApplicationInfo.getInstance().getApiVersion();
url = RepositoryHelper.getDownloadUrl() + URLEncoder.encode(descriptor.getPluginId().getIdString(), "UTF8") +
"&build=" + buildNumber + "&uuid=" + URLEncoder.encode(uuid, "UTF8");
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginAdvertiserEditorNotificationProvider.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginAdvertiserEditorNotificationProvider.java
new file mode 100644
index 000000000000..7110799f3173
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginAdvertiserEditorNotificationProvider.java
@@ -0,0 +1,153 @@
+/*
+ * 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.updateSettings.impl.pluginsAdvertisement;
+
+import com.intellij.ide.plugins.*;
+import com.intellij.openapi.extensions.PluginId;
+import com.intellij.openapi.fileEditor.FileEditor;
+import com.intellij.openapi.fileTypes.FileTypeFactory;
+import com.intellij.openapi.fileTypes.PlainTextFileType;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.progress.Task;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.updateSettings.impl.PluginDownloader;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.ui.EditorNotificationPanel;
+import com.intellij.ui.EditorNotifications;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * User: anna
+ * Date: 10/11/13
+ */
+public class PluginAdvertiserEditorNotificationProvider extends EditorNotifications.Provider<EditorNotificationPanel> {
+ private static final Key<EditorNotificationPanel> KEY = Key.create("file.type.associations.detected");
+ private final Project myProject;
+ private final EditorNotifications myNotifications;
+ private final Set<String> myEnabledExtensions = new HashSet<String>();
+
+ public PluginAdvertiserEditorNotificationProvider(Project project, final EditorNotifications notifications) {
+ myProject = project;
+ myNotifications = notifications;
+ }
+
+ @Override
+ public Key<EditorNotificationPanel> getKey() {
+ return KEY;
+ }
+
+ @Nullable
+ @Override
+ public EditorNotificationPanel createNotificationPanel(VirtualFile file, FileEditor fileEditor) {
+ if (file.getFileType() != PlainTextFileType.INSTANCE) return null;
+
+ final String extension = file.getExtension();
+ if (myEnabledExtensions.contains(extension) ||
+ UnknownFeaturesCollector.getInstance(myProject).isIgnored(createExtensionFeature(extension))) return null;
+
+ final PluginsAdvertiser.KnownExtensions knownExtensions = PluginsAdvertiser.loadExtensions();
+ if (knownExtensions != null) {
+ final Set<String> plugins = knownExtensions.find(extension);
+ if (plugins != null && !plugins.isEmpty()) {
+ return createPanel(extension, plugins);
+ }
+ }
+ return null;
+ }
+
+ @NotNull
+ private EditorNotificationPanel createPanel(final String extension, final Set<String> plugins) {
+ final EditorNotificationPanel panel = new EditorNotificationPanel();
+ panel.setText("Plugins supporting *." + extension + " are found");
+ final IdeaPluginDescriptor disabledPlugin = getDisabledPlugin(plugins);
+ if (disabledPlugin != null) {
+ panel.createActionLabel("Enable " + disabledPlugin.getName() + " plugin", new Runnable() {
+ @Override
+ public void run() {
+ myEnabledExtensions.add(extension);
+ PluginManagerCore.enablePlugin(disabledPlugin.getPluginId().getIdString());
+ myNotifications.updateAllNotifications();
+ PluginManagerMain.notifyPluginsWereUpdated("Plugin was successfully enabled");
+ }
+ });
+ } else {
+ panel.createActionLabel("Install plugins", new Runnable() {
+ @Override
+ public void run() {
+ ProgressManager.getInstance().run(new Task.Modal(null, "Search for plugins in repository", true) {
+ private final Set<PluginDownloader> myPlugins = new HashSet<PluginDownloader>();
+ private List<IdeaPluginDescriptor> myAllPlugins;
+
+ @Override
+ public void run(@NotNull ProgressIndicator indicator) {
+ try {
+ myAllPlugins = RepositoryHelper.loadPluginsFromRepository(indicator);
+ for (IdeaPluginDescriptor loadedPlugin : myAllPlugins) {
+ if (plugins.contains(loadedPlugin.getPluginId().getIdString())) {
+ myPlugins.add(PluginDownloader.createDownloader(loadedPlugin));
+ }
+ }
+ }
+ catch (Exception ignore) {
+ }
+ }
+
+ @Override
+ public void onSuccess() {
+ final PluginsAdvertiserDialog advertiserDialog = new PluginsAdvertiserDialog(null, myPlugins.toArray(new PluginDownloader[myPlugins.size()]), myAllPlugins);
+ advertiserDialog.show();
+ if (advertiserDialog.isOK()) {
+ myEnabledExtensions.add(extension);
+ myNotifications.updateAllNotifications();
+ }
+ }
+ });
+ }
+ });
+ }
+ panel.createActionLabel("Ignore extension", new Runnable() {
+ @Override
+ public void run() {
+ final UnknownFeaturesCollector collectorSuggester = UnknownFeaturesCollector.getInstance(myProject);
+ collectorSuggester.ignoreFeature(createExtensionFeature(extension));
+ myNotifications.updateAllNotifications();
+ }
+ });
+ return panel;
+ }
+
+ @Nullable
+ private static IdeaPluginDescriptor getDisabledPlugin(Set<String> plugins) {
+ final List<String> disabledPlugins = new ArrayList<String>(PluginManagerCore.getDisabledPlugins());
+ disabledPlugins.retainAll(plugins);
+ if (disabledPlugins.size() == 1) {
+ return PluginManager.getPlugin(PluginId.getId(disabledPlugins.get(0)));
+ }
+ return null;
+ }
+
+ private static UnknownFeature createExtensionFeature(String extension) {
+ return new UnknownFeature(FileTypeFactory.FILE_TYPE_FACTORY_EP.getName(), extension);
+ }
+}
diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiser.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiser.java
index 10cd1ee4470e..40d1eb8cde6a 100644
--- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiser.java
+++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/PluginsAdvertiser.java
@@ -18,50 +18,64 @@ package com.intellij.openapi.updateSettings.impl.pluginsAdvertisement;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
-import com.intellij.ide.plugins.*;
+import com.google.gson.stream.JsonReader;
+import com.intellij.ide.plugins.IdeaPluginDescriptor;
+import com.intellij.ide.plugins.PluginManagerCore;
+import com.intellij.ide.plugins.RepositoryHelper;
import com.intellij.notification.*;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationInfo;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.PluginId;
+import com.intellij.openapi.fileTypes.FileTypeFactory;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupActivity;
import com.intellij.openapi.updateSettings.impl.PluginDownloader;
+import com.intellij.openapi.updateSettings.impl.UpdateSettings;
+import com.intellij.openapi.util.JDOMUtil;
+import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.net.HttpConfigurable;
+import com.intellij.util.xmlb.XmlSerializer;
+import com.intellij.util.xmlb.annotations.MapAnnotation;
+import com.intellij.util.xmlb.annotations.Tag;
+import org.jdom.Document;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
+import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
public class PluginsAdvertiser implements StartupActivity {
private static final Logger LOG = Logger.getInstance("#" + PluginsAdvertiser.class.getName());
+ private static final String FEATURE_IMPLEMENTATIONS_URL = "http://plugins.jetbrains.com/feature/getImplementations?";
+ private static final String CASHED_EXTENSIONS = "extensions.xml";
public static List<PluginId> retrieve(UnknownFeature unknownFeature) {
final String featureType = unknownFeature.getFeatureType();
final String implementationName = unknownFeature.getImplementationName();
- final String buildNumber = ApplicationInfo.getInstance().getBuild().asString();
- final String pluginRepositoryUrl = "http://plugins.jetbrains.com/feature/getImplementations?" +
+ final String buildNumber = ApplicationInfo.getInstance().getApiVersion();
+ final String pluginRepositoryUrl = FEATURE_IMPLEMENTATIONS_URL +
"featureType=" + featureType +
- "&implementationName=" + implementationName +
+ "&implementationName=" + implementationName.replaceAll("#", "%23") +
"&build=" + buildNumber;
try {
HttpURLConnection connection = HttpConfigurable.getInstance().openHttpConnection(pluginRepositoryUrl);
connection.connect();
final InputStreamReader streamReader = new InputStreamReader(connection.getInputStream());
try {
- final JsonElement jsonRootElement = new JsonParser().parse(streamReader);
+ final JsonReader jsonReader = new JsonReader(streamReader);
+ jsonReader.setLenient(true);
+ final JsonElement jsonRootElement = new JsonParser().parse(jsonReader);
final List<PluginId> result = new ArrayList<PluginId>();
for (JsonElement jsonElement : jsonRootElement.getAsJsonArray()) {
final JsonObject jsonObject = jsonElement.getAsJsonObject();
@@ -80,11 +94,70 @@ public class PluginsAdvertiser implements StartupActivity {
}
}
+ private static Map<String, Set<PluginId>> loadSupportedExtensions() {
+ final String pluginRepositoryUrl = FEATURE_IMPLEMENTATIONS_URL + "featureType=" + FileTypeFactory.FILE_TYPE_FACTORY_EP.getName();
+ try {
+ HttpURLConnection connection = HttpConfigurable.getInstance().openHttpConnection(pluginRepositoryUrl);
+ connection.connect();
+ final InputStreamReader streamReader = new InputStreamReader(connection.getInputStream());
+ try {
+ final JsonReader jsonReader = new JsonReader(streamReader);
+ jsonReader.setLenient(true);
+ final JsonElement jsonRootElement = new JsonParser().parse(jsonReader);
+ final Map<String, Set<PluginId>> result = new HashMap<String, Set<PluginId>>();
+ for (JsonElement jsonElement : jsonRootElement.getAsJsonArray()) {
+ final JsonObject jsonObject = jsonElement.getAsJsonObject();
+ final JsonElement ext = jsonObject.get("implementationName");
+ final String extension = StringUtil.unquoteString(ext.toString());
+ Set<PluginId> pluginIds = result.get(extension);
+ if (pluginIds == null) {
+ pluginIds = new HashSet<PluginId>();
+ result.put(extension, pluginIds);
+ }
+ pluginIds.add(PluginId.getId(StringUtil.unquoteString(jsonObject.get("pluginId").toString())));
+ }
+ saveExtensions(result);
+ return result;
+ }
+ finally {
+ streamReader.close();
+ }
+ }
+ catch (IOException e) {
+ LOG.info(e);
+ return null;
+ }
+ }
+
+ public static KnownExtensions loadExtensions() {
+ try {
+ File file = new File(PathManager.getPluginsPath(), CASHED_EXTENSIONS);
+ if (file.isFile()) {
+ final Document document = JDOMUtil.loadDocument(file);
+ return XmlSerializer.deserialize(document, KnownExtensions.class);
+ }
+ }
+ catch (Exception ignore) {
+ }
+ return null;
+ }
+
+ private static void saveExtensions(Map<String, Set<PluginId>> extensions) throws IOException {
+ File plugins = new File(PathManager.getPluginsPath(), CASHED_EXTENSIONS);
+ if (!plugins.isFile()) {
+ FileUtil.ensureCanCreateFile(plugins);
+ }
+ plugins.deleteOnExit();
+ JDOMUtil.writeDocument(new Document(XmlSerializer.serialize(new KnownExtensions(extensions))), plugins, "\n");
+ }
+
@Override
public void runActivity(@NotNull final Project project) {
+ if (!UpdateSettings.getInstance().CHECK_NEEDED) return;
final UnknownFeaturesCollector collectorSuggester = UnknownFeaturesCollector.getInstance(project);
final Set<UnknownFeature> unknownFeatures = collectorSuggester.getUnknownFeatures();
- if (unknownFeatures.isEmpty()) return;
+ final KnownExtensions extensions = loadExtensions();
+ if (extensions != null && unknownFeatures.isEmpty()) return;
final Runnable runnable = new Runnable() {
public void run() {
final Application application = ApplicationManager.getApplication();
@@ -95,6 +168,9 @@ public class PluginsAdvertiser implements StartupActivity {
@Override
public void run(@NotNull ProgressIndicator indicator) {
+ if (extensions == null) {
+ loadSupportedExtensions();
+ }
int idx = 0;
final Set<PluginId> ids = new HashSet<PluginId>();
for (UnknownFeature feature : unknownFeatures) {
@@ -109,7 +185,7 @@ public class PluginsAdvertiser implements StartupActivity {
}
}
}
- indicator.setFraction(idx++ / unknownFeatures.size());
+ indicator.setFraction(((double) idx++) / unknownFeatures.size());
}
try {
@@ -141,11 +217,12 @@ public class PluginsAdvertiser implements StartupActivity {
for (UnknownFeature feature : unknownFeatures) {
collectorSuggester.ignoreFeature(feature);
}
+ notification.expire();
} else if ("configure".equals(description)) {
LOG.assertTrue(myAllPlugins != null);
+ notification.expire();
new PluginsAdvertiserDialog(myProject, myPlugins.toArray(new PluginDownloader[myPlugins.size()]), myAllPlugins).show();
}
- notification.expire();
}
}
}).notify(project);
@@ -157,5 +234,42 @@ public class PluginsAdvertiser implements StartupActivity {
SwingUtilities.invokeLater(runnable);
}
+
+ @Tag("exts")
+ public static class KnownExtensions {
+ @MapAnnotation(surroundWithTag = false, surroundKeyWithTag = false, surroundValueWithTag = false)
+ public Map<String, PluginSet> myExtensions = new HashMap<String, PluginSet>();
+
+ public KnownExtensions() {
+ }
+
+ public KnownExtensions(Map<String, Set<PluginId>> extensions) {
+ for (String ext : extensions.keySet()) {
+ myExtensions.put(ext, new PluginSet(extensions.get(ext)));
+ }
+ }
+
+ public Set<String> find(String extension) {
+ final PluginSet pluginSet = myExtensions.get(extension);
+ if (pluginSet != null) {
+ return pluginSet.myPlugins;
+ }
+ return null;
+ }
+ }
+
+ @Tag("plugins")
+ public static class PluginSet {
+ public Set<String> myPlugins = new HashSet<String>();
+
+ public PluginSet() {
+ }
+
+ public PluginSet(Set<PluginId> plugins) {
+ for (PluginId plugin : plugins) {
+ myPlugins.add(plugin.toString());
+ }
+ }
+ }
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/UnknownFeaturesCollector.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/UnknownFeaturesCollector.java
index 0bd1410f012e..a7714b1e04e8 100644
--- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/UnknownFeaturesCollector.java
+++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/pluginsAdvertisement/UnknownFeaturesCollector.java
@@ -51,11 +51,15 @@ public class UnknownFeaturesCollector implements PersistentStateComponent<Elemen
public void registerUnknownFeature(String featureType, String implementationName) {
final UnknownFeature feature = new UnknownFeature(featureType, implementationName);
- if (!myIgnoredUnknownFeatures.contains(feature)) {
+ if (!isIgnored(feature)) {
myUnknownFeatures.add(feature);
}
}
-
+
+ public boolean isIgnored(UnknownFeature feature) {
+ return myIgnoredUnknownFeatures.contains(feature);
+ }
+
public void ignoreFeature(UnknownFeature feature) {
myIgnoredUnknownFeatures.add(feature);
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/ex/temp/TempFileSystem.java b/platform/platform-impl/src/com/intellij/openapi/vfs/ex/temp/TempFileSystem.java
index 1ac43ab7c5d6..92e7ed73e486 100644
--- a/platform/platform-impl/src/com/intellij/openapi/vfs/ex/temp/TempFileSystem.java
+++ b/platform/platform-impl/src/com/intellij/openapi/vfs/ex/temp/TempFileSystem.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.
@@ -21,13 +21,14 @@ import com.intellij.openapi.util.io.BufferExposingByteArrayInputStream;
import com.intellij.openapi.util.io.FileAttributes;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.impl.local.LocalFileSystemBase;
import com.intellij.openapi.vfs.newvfs.ManagingFS;
-import com.intellij.openapi.vfs.newvfs.NewVirtualFileSystem;
import com.intellij.openapi.vfs.newvfs.RefreshQueue;
import com.intellij.openapi.vfs.newvfs.VfsImplUtil;
import com.intellij.openapi.vfs.newvfs.impl.FakeVirtualFile;
import com.intellij.openapi.vfs.newvfs.persistent.FSRecords;
import com.intellij.util.ArrayUtil;
+import com.intellij.util.IncorrectOperationException;
import com.intellij.util.LocalTimeCounter;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -35,12 +36,14 @@ import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
+import java.util.Set;
/**
* @author max
*/
-public class TempFileSystem extends NewVirtualFileSystem {
+public class TempFileSystem extends LocalFileSystemBase {
private final FSItem myRoot = new FSDir(null, "/");
public static TempFileSystem getInstance() {
@@ -180,7 +183,7 @@ public class TempFileSystem extends NewVirtualFileSystem {
}
@Override
- public void setTimeStamp(@NotNull final VirtualFile file, final long timeStamp) throws IOException {
+ public void setTimeStamp(@NotNull final VirtualFile file, final long timeStamp) {
final FSItem fsItem = convert(file);
assert fsItem != null;
@@ -370,4 +373,28 @@ public class TempFileSystem extends NewVirtualFileSystem {
final long length = item instanceof FSFile ? ((FSFile)item).myContent.length : 0;
return new FileAttributes(item.isDirectory(), false, false, false, length, item.myTimestamp, item.myWritable);
}
+
+ @NotNull
+ @Override
+ public Set<WatchRequest> addRootsToWatch(@NotNull Collection<String> rootPaths, boolean watchRecursively) {
+ throw new IncorrectOperationException();
+ }
+
+ @Override
+ public void removeWatchedRoots(@NotNull Collection<WatchRequest> watchRequests) {
+ throw new IncorrectOperationException();
+ }
+
+ @Override
+ public Set<WatchRequest> replaceWatchedRoots(@NotNull Collection<WatchRequest> watchRequests,
+ @Nullable Collection<String> recursiveRoots,
+ @Nullable Collection<String> flatRoots) {
+ throw new IncorrectOperationException();
+ }
+
+ @Nullable
+ @Override
+ protected String normalize(@NotNull String path) {
+ return path;
+ }
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/FileWatcher.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/FileWatcher.java
index 09ca88b9fc7f..972165f76751 100644
--- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/FileWatcher.java
+++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/FileWatcher.java
@@ -67,6 +67,12 @@ public class FileWatcher {
public final List<String> dirtyPaths = newArrayList();
public final List<String> dirtyPathsRecursive = newArrayList();
public final List<String> dirtyDirectories = newArrayList();
+
+ private static DirtyPaths EMPTY = new DirtyPaths();
+
+ private boolean isEmpty() {
+ return dirtyPaths.isEmpty() && dirtyPathsRecursive.isEmpty() && dirtyDirectories.isEmpty();
+ }
}
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vfs.impl.local.FileWatcher");
@@ -91,14 +97,9 @@ public class FileWatcher {
private final Object myLock = new Object();
private DirtyPaths myDirtyPaths = new DirtyPaths();
- private final String[] myLastChangedPathes = new String[2];
+ private final String[] myLastChangedPaths = new String[2];
private int myLastChangedPathIndex;
- /** @deprecated use {@linkplain com.intellij.openapi.vfs.impl.local.LocalFileSystemImpl#getFileWatcher()} (to remove in IDEA 13) */
- public static FileWatcher getInstance() {
- return ((LocalFileSystemImpl)LocalFileSystem.getInstance()).getFileWatcher();
- }
-
FileWatcher(@NotNull ManagingFS managingFS) {
myManagingFS = managingFS;
@@ -153,11 +154,16 @@ public class FileWatcher {
@NotNull
public DirtyPaths getDirtyPaths() {
synchronized (myLock) {
- DirtyPaths dirtyPaths = myDirtyPaths;
- myDirtyPaths = new DirtyPaths();
- myLastChangedPathIndex = 0;
- for(int i = 0; i < myLastChangedPathes.length; ++i) myLastChangedPathes[i] = null;
- return dirtyPaths;
+ if (!myDirtyPaths.isEmpty()) {
+ DirtyPaths dirtyPaths = myDirtyPaths;
+ myDirtyPaths = new DirtyPaths();
+ myLastChangedPathIndex = 0;
+ for (int i = 0; i < myLastChangedPaths.length; ++i) myLastChangedPaths[i] = null;
+ return dirtyPaths;
+ }
+ else {
+ return DirtyPaths.EMPTY;
+ }
}
}
@@ -213,7 +219,7 @@ public class FileWatcher {
}
private static boolean isUpToDate(File executable) {
- long length = SystemInfo.isWindows ? 70216 :
+ long length = SystemInfo.isWindows ? 71208 :
SystemInfo.isMac ? 13924 :
SystemInfo.isLinux ? SystemInfo.isAMD64 ? 29155 : 22791 :
-1;
@@ -377,13 +383,13 @@ public class FileWatcher {
if (fastPath && !changedPaths.isEmpty()) break;
for (String root : flatWatchRoots) {
- if (FileUtil.pathsEqual(path, root)) {
+ if (FileUtil.namesEqual(path, root)) {
changedPaths.add(path);
continue ext;
}
if (isExact) {
String parentPath = new File(path).getParent();
- if (parentPath != null && FileUtil.pathsEqual(parentPath, root)) {
+ if (parentPath != null && FileUtil.namesEqual(parentPath, root)) {
changedPaths.add(path);
continue ext;
}
@@ -397,7 +403,7 @@ public class FileWatcher {
}
if (!isExact) {
String parentPath = new File(root).getParent();
- if (parentPath != null && FileUtil.pathsEqual(path, parentPath)) {
+ if (parentPath != null && FileUtil.namesEqual(path, parentPath)) {
changedPaths.add(root);
continue ext;
}
@@ -551,20 +557,22 @@ public class FileWatcher {
LOG.info("Change requests:" + myChangeRequests + ", filtered:" + myFilteredRequests);
}
- for(int i = 0; i < myLastChangedPathes.length; ++i) {
+ for(int i = 0; i < myLastChangedPaths.length; ++i) {
int last = myLastChangedPathIndex - i - 1;
- if (last < 0) last += myLastChangedPathes.length;
- String lastChangedPath = myLastChangedPathes[last];
+ if (last < 0) last += myLastChangedPaths.length;
+ String lastChangedPath = myLastChangedPaths[last];
if (lastChangedPath != null && lastChangedPath.equals(path)) {
++myFilteredRequests;
return;
}
}
- myLastChangedPathes[myLastChangedPathIndex ++] = path;
- if (myLastChangedPathIndex == myLastChangedPathes.length) myLastChangedPathIndex = 0;
+ myLastChangedPaths[myLastChangedPathIndex ++] = path;
+ if (myLastChangedPathIndex == myLastChangedPaths.length) myLastChangedPathIndex = 0;
}
}
+ int length = path.length();
+ if (length > 1 && path.charAt(length - 1) == '/') path = path.substring(0, length - 1);
boolean exactPath = op != WatcherOp.DIRTY && op != WatcherOp.RECDIRTY;
Collection<String> paths = checkWatchable(path, exactPath, false);
diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshSessionImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshSessionImpl.java
index d58cbb4b4e9e..a516ec88b0f1 100644
--- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshSessionImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/RefreshSessionImpl.java
@@ -103,6 +103,7 @@ public class RefreshSessionImpl extends RefreshSession {
@Override
public void launch() {
+ if (!myIsRecursive) LOG.info("[CR-IC-2706] " + myWorkQueue);
mySemaphore.down();
((RefreshQueueImpl)RefreshQueue.getInstance()).execute(this);
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/VfsImplUtil.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/VfsImplUtil.java
index bc5afa0b08a6..b2a4ab36af52 100644
--- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/VfsImplUtil.java
+++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/VfsImplUtil.java
@@ -124,7 +124,7 @@ public class VfsImplUtil {
@Nullable
private static Pair<NewVirtualFile, Iterable<String>> prepare(@NotNull NewVirtualFileSystem vfs, @NotNull String path) {
String normalizedPath = normalize(vfs, path);
- if (StringUtil.isEmptyOrSpaces(normalizedPath) || normalizedPath == null) {
+ if (StringUtil.isEmptyOrSpaces(normalizedPath)) {
return null;
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java
index 42495b57f2c0..5cb9149e4997 100644
--- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java
+++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java
@@ -228,7 +228,9 @@ public class RefreshWorker {
}
}
- file.markClean();
+ if (myIsRecursive || !file.isDirectory()) {
+ file.markClean();
+ }
}
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java
index 1e7e32b751cd..d819a63adda3 100644
--- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java
+++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java
@@ -740,13 +740,20 @@ public final class ToolWindowsPane extends JBLayeredPane implements Disposable {
splitter.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
+ if (!Splitter.PROP_ORIENTATION.equals(evt.getPropertyName())) return;
+ boolean isSplitterHorizontalNow = !splitter.isVertical();
if (anchor == ToolWindowAnchor.LEFT) {
- UISettings.getInstance().LEFT_HORIZONTAL_SPLIT = !splitter.isVertical();
+ if (UISettings.getInstance().LEFT_HORIZONTAL_SPLIT != isSplitterHorizontalNow) {
+ UISettings.getInstance().LEFT_HORIZONTAL_SPLIT = isSplitterHorizontalNow;
+ UISettings.getInstance().fireUISettingsChanged();
+ }
}
if (anchor == ToolWindowAnchor.RIGHT) {
- UISettings.getInstance().RIGHT_HORIZONTAL_SPLIT = !splitter.isVertical();
+ if (UISettings.getInstance().RIGHT_HORIZONTAL_SPLIT != isSplitterHorizontalNow) {
+ UISettings.getInstance().RIGHT_HORIZONTAL_SPLIT = isSplitterHorizontalNow;
+ UISettings.getInstance().fireUISettingsChanged();
+ }
}
- UISettings.getInstance().fireUISettingsChanged();
}
});
}
diff --git a/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java b/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java
new file mode 100644
index 000000000000..6af352487f55
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java
@@ -0,0 +1,496 @@
+package com.intellij.ui;
+
+import com.intellij.icons.AllIcons;
+import com.intellij.ide.CopyProvider;
+import com.intellij.ide.DataManager;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.ide.CopyPasteManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.wm.IdeFocusManager;
+import com.intellij.pom.Navigatable;
+import com.intellij.psi.PsiElement;
+import com.intellij.ui.components.JBLabel;
+import com.intellij.ui.components.JBList;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.Function;
+import com.intellij.util.SmartList;
+import com.intellij.util.ui.UIUtil;
+import com.intellij.util.ui.update.MergingUpdateQueue;
+import com.intellij.util.ui.update.Update;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import java.awt.*;
+import java.awt.datatransfer.StringSelection;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.util.List;
+
+public class FinderRecursivePanel<T> extends JBSplitter implements DataProvider, Disposable {
+
+ @NotNull private final Project myProject;
+ @Nullable private final String myGroupId;
+
+ private FinderRecursivePanel myParent = null;
+ private JComponent myChild = null;
+
+ private JBList myList;
+ private final CollectionListModel<T> myListModel = new CollectionListModel<T>();
+
+ private final MergingUpdateQueue myMergingUpdateQueue;
+
+ private MyListSelectionListener myListener;
+
+ private CopyProvider myCopyProvider = new CopyProvider() {
+ @Override
+ public void performCopy(@NotNull DataContext dataContext) {
+ final T value = getSelectedValue();
+ CopyPasteManager.getInstance().setContents(new StringSelection(getItemText(value)));
+ }
+
+ @Override
+ public boolean isCopyEnabled(@NotNull DataContext dataContext) {
+ return getSelectedValue() != null;
+ }
+
+ @Override
+ public boolean isCopyVisible(@NotNull DataContext dataContext) {
+ return false;
+ }
+ };
+
+ public FinderRecursivePanel(@NotNull FinderRecursivePanel parent) {
+ this(parent.getProject(), parent, parent.getGroupId());
+ }
+
+ public FinderRecursivePanel(@NotNull Project project, @Nullable String groupId) {
+ this(project, null, groupId);
+ }
+
+ protected FinderRecursivePanel(@NotNull Project project,
+ @Nullable FinderRecursivePanel parent,
+ @Nullable String groupId) {
+ super(false, 0f);
+
+ myProject = project;
+ myParent = parent;
+ myGroupId = groupId;
+ myMergingUpdateQueue = new MergingUpdateQueue("FinderRecursivePanel", 100, true, this);
+
+ if (myParent != null) {
+ Disposer.register(myParent, this);
+ }
+ Disposer.register(this, myMergingUpdateQueue);
+ }
+
+ public void init() {
+ setFirstComponent(createLeftComponent());
+ setSecondComponent(createDefaultRightComponent());
+
+ if (getGroupId() != null) {
+ setAndLoadSplitterProportionKey(getGroupId() + "[" + getIndex() + "]");
+ }
+ setDividerWidth(3);
+ setShowDividerIcon(false);
+ setShowDividerControls(true);
+
+ updatePanel();
+ }
+
+ protected JComponent createLeftComponent() {
+ myList = createList();
+
+ return ScrollPaneFactory.createScrollPane(myList,
+ ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
+ ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
+ }
+
+ protected String getListEmptyText() {
+ return "No entries";
+ }
+
+ protected JBList createList() {
+ final JBList list = new JBList(myListModel);
+ list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ list.setEmptyText(getListEmptyText());
+ list.setCellRenderer(createListCellRenderer());
+
+ installListActions(list);
+ myListener = new MyListSelectionListener();
+ list.addListSelectionListener(myListener);
+ ListScrollingUtil.installActions(list);
+
+ installSpeedSearch(list);
+
+ installEditOnDoubleClick(list);
+ return list;
+ }
+
+ private void installListActions(JBList list) {
+ AnAction previousPanelAction = new AnAction("Previous", null, AllIcons.Actions.Back) {
+ @Override
+ public void update(AnActionEvent e) {
+ e.getPresentation().setEnabled(!isRootPanel());
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ IdeFocusManager.getInstance(myProject).requestFocus(myParent.getList(), true);
+ }
+ };
+ previousPanelAction.registerCustomShortcutSet(KeyEvent.VK_LEFT, 0, list);
+
+ AnAction nextPanelAction = new AnAction("Next", null, AllIcons.Actions.Forward) {
+ @Override
+ public void update(AnActionEvent e) {
+ final T value = getSelectedValue();
+ e.getPresentation().setEnabled(value != null &&
+ hasChildren(value) &&
+ getSecondComponent() instanceof FinderRecursivePanel);
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ FinderRecursivePanel finderRecursivePanel = (FinderRecursivePanel)getSecondComponent();
+ JBList jbList = finderRecursivePanel.getList();
+ if (!jbList.isEmpty()) {
+ if (jbList.getSelectedValue() == null) {
+ jbList.setSelectedIndex(0);
+ finderRecursivePanel.updateRightComponent(true);
+ }
+ }
+ IdeFocusManager.getInstance(myProject).requestFocus(jbList, true);
+ }
+ };
+ nextPanelAction.registerCustomShortcutSet(KeyEvent.VK_RIGHT, 0, list);
+
+ AnAction editAction = new AnAction("Edit", null, AllIcons.Actions.Edit) {
+
+ @Override
+ public void update(AnActionEvent e) {
+ e.getPresentation().setEnabled(getSelectedValue() != null);
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ performEditAction();
+ }
+ };
+ editAction.registerCustomShortcutSet(CommonShortcuts.ENTER, list);
+
+ AnAction[] actions = new AnAction[]{
+ previousPanelAction,
+ nextPanelAction,
+ Separator.getInstance(),
+ editAction};
+
+ final AnAction[] customActions = getCustomListActions();
+ if (customActions.length > 0) {
+ actions = ArrayUtil.append(actions, Separator.getInstance());
+ actions = ArrayUtil.mergeArrays(actions, customActions);
+ }
+
+ ActionGroup contextActionGroup = new DefaultActionGroup(actions);
+ PopupHandler.installUnknownPopupHandler(list, contextActionGroup, ActionManager.getInstance());
+ }
+
+ protected AnAction[] getCustomListActions() {
+ return AnAction.EMPTY_ARRAY;
+ }
+
+ private void installSpeedSearch(JBList list) {
+ final ListSpeedSearch search = new ListSpeedSearch(list, new Function<Object, String>() {
+ @Override
+ public String fun(Object o) {
+ //noinspection unchecked
+ return getItemText((T)o);
+ }
+ });
+ search.setComparator(new SpeedSearchComparator(false));
+ }
+
+ private void installEditOnDoubleClick(JBList list) {
+ new DoubleClickListener() {
+ @Override
+ protected boolean onDoubleClick(MouseEvent event) {
+ performEditAction();
+ return true;
+ }
+ }.installOn(list);
+ }
+
+ protected boolean performEditAction() {
+ Navigatable data = CommonDataKeys.NAVIGATABLE.getData(DataManager.getInstance().getDataContext(getList()));
+ if (data != null) {
+ data.navigate(true);
+ }
+ return false;
+ }
+
+ protected ListCellRenderer createListCellRenderer() {
+ return new ColoredListCellRenderer() {
+
+ public Component getListCellRendererComponent(JList list,
+ Object value,
+ int index,
+ boolean isSelected,
+ boolean cellHasFocus) {
+ mySelected = isSelected;
+ myForeground = UIUtil.getTreeTextForeground();
+ mySelectionForeground = cellHasFocus ? list.getSelectionForeground() : UIUtil.getTreeTextForeground();
+
+ clear();
+ setFont(UIUtil.getListFont());
+
+ final T t = (T)value;
+ setIcon(getItemIcon(t));
+ append(getItemText(t));
+
+ doCustomizeCellRenderer(this, list, t, index, isSelected, cellHasFocus);
+
+ Color bg = isSelected ? UIUtil.getTreeSelectionBackground(cellHasFocus) : UIUtil.getTreeTextBackground();
+ setBackground(bg);
+
+ if (hasChildren(t)) {
+ JPanel result = new JPanel(new BorderLayout(0, 0));
+ JLabel childrenLabel = new JLabel();
+ childrenLabel.setOpaque(true);
+ childrenLabel.setVisible(true);
+ childrenLabel.setBackground(bg);
+
+ final boolean isDark = ColorUtil.isDark(UIUtil.getListSelectionBackground());
+ childrenLabel.setIcon(isSelected ? isDark ? AllIcons.Icons.Ide.NextStepInverted
+ : AllIcons.Icons.Ide.NextStep
+ : AllIcons.Icons.Ide.NextStepGrayed);
+ result.add(this, BorderLayout.CENTER);
+ result.add(childrenLabel, BorderLayout.EAST);
+ return result;
+ }
+ return this;
+ }
+
+ @Override
+ protected final void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) {
+ }
+ };
+ }
+
+ protected void doCustomizeCellRenderer(SimpleColoredComponent comp, JList list, T value, int index, boolean selected, boolean hasFocus) {
+ }
+
+ protected boolean hasChildren(T t) {
+ return false;
+ }
+
+ protected JBList getList() {
+ return myList;
+ }
+
+ @NotNull
+ protected String getItemText(T t) {
+ return t.toString();
+ }
+
+ @Nullable
+ protected Icon getItemIcon(T t) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public Object getData(@NonNls String dataId) {
+ Object selectedValue = getSelectedValue();
+ if (PlatformDataKeys.COPY_PROVIDER.is(dataId) && selectedValue != null) {
+ return myCopyProvider;
+ }
+ if (CommonDataKeys.PSI_ELEMENT.is(dataId) && selectedValue instanceof PsiElement) {
+ return selectedValue;
+ }
+ if (CommonDataKeys.NAVIGATABLE.is(dataId) && selectedValue instanceof Navigatable) {
+ return selectedValue;
+ }
+ if (selectedValue instanceof DataProvider) {
+ return ((DataProvider)selectedValue).getData(dataId);
+ }
+ return null;
+ }
+
+ @Override
+ public void dispose() {
+ myMergingUpdateQueue.cancelAllUpdates();
+ }
+
+ @SuppressWarnings("unchecked")
+ public T getSelectedValue() {
+ return (T)getList().getSelectedValue();
+ }
+
+ @NotNull
+ public Project getProject() {
+ return myProject;
+ }
+
+ public FinderRecursivePanel getParentPanel() {
+ return myParent;
+ }
+
+ @Nullable
+ public String getGroupId() {
+ return myGroupId;
+ }
+
+ @Nullable
+ protected JComponent createRightComponent(T t) {
+ return new JPanel();
+ }
+
+ protected JComponent createDefaultRightComponent() {
+ final JBLabel label = new JBLabel("Nothing selected", SwingConstants.CENTER);
+ label.setFontColor(UIUtil.FontColor.BRIGHTER);
+ return label;
+ }
+
+ public void updatePanel() {
+ myList.setPaintBusy(true);
+ myMergingUpdateQueue.queue(new Update("update") {
+ @Override
+ public void run() {
+ final T oldValue = getSelectedValue();
+ final int oldIndex = getList().getSelectedIndex();
+
+ ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+ @Override
+ public void run() {
+ ApplicationManager.getApplication().runReadAction(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ mergeListItems(myListModel, getListItems());
+
+ if (myList.getSelectedIndex() < 0) {
+ myList.setSelectedIndex(myListModel.getSize() > oldIndex ? oldIndex : 0);
+ }
+ else {
+ Object newValue = myList.getSelectedValue();
+ updateRightComponent(oldValue == null || oldValue != newValue);
+ }
+ }
+ });
+ }
+ finally {
+ myList.setPaintBusy(false);
+ }
+ }
+ });
+ }
+ });
+ }
+ });
+ }
+
+ public static <T> void mergeListItems(@NotNull CollectionListModel<T> listModel, @NotNull List<T> newItems) {
+ // remove items
+ for (int i = listModel.getSize() - 1; i >= 0; i--) {
+ if (!newItems.contains(listModel.getElementAt(i))) {
+ listModel.remove(i);
+ }
+ }
+ // add items
+ List<T> items = listModel.getItems();
+ for (int i = 0; i < newItems.size(); i++) {
+ T newItem = newItems.get(i);
+ if (!items.contains(newItem)) {
+ listModel.add(i, newItem);
+ }
+ }
+ }
+
+ public void updateRightComponent(boolean force) {
+ if (force) {
+ createRightComponent();
+ }
+ else if (myChild instanceof FinderRecursivePanel) {
+ ((FinderRecursivePanel)myChild).updatePanel();
+ }
+ }
+
+ private void createRightComponent() {
+ T value = getSelectedValue();
+ if (value != null) {
+ if (myChild instanceof Disposable) {
+ Disposer.dispose((Disposable)myChild);
+ }
+ myChild = createRightComponent(value);
+ if (myChild instanceof FinderRecursivePanel) {
+ ((FinderRecursivePanel)myChild).init();
+ }
+
+ setSecondComponent(myChild);
+ }
+ }
+
+ /**
+ * Called in read action.
+ *
+ * @return Items for list.
+ */
+ @NotNull
+ protected List<T> getListItems() {
+ return new SmartList<T>();
+ }
+
+ protected int getIndex() {
+ int index = 0;
+ FinderRecursivePanel parent = myParent;
+ while (parent != null) {
+ index++;
+ parent = parent.getParentPanel();
+ }
+
+ return index;
+ }
+
+ protected boolean isRootPanel() {
+ return getParentPanel() == null;
+ }
+
+ @Override
+ public void doLayout() {
+ if (myProportion == 0) {
+ int total = getOrientation() ? getHeight() : getWidth();
+ float proportion = (float)getFirstComponentPreferredSize() / (total - getDividerWidth());
+ if (proportion > .0f && proportion < 1.0f) {
+ setProportion(proportion);
+ }
+ }
+
+ super.doLayout();
+ }
+
+ protected int getFirstComponentPreferredSize() {
+ return 200;
+ }
+
+ @Nullable
+ protected JComponent getChildPanel() {
+ return myChild;
+ }
+
+ private class MyListSelectionListener implements ListSelectionListener {
+ @Override
+ public void valueChanged(ListSelectionEvent event) {
+ if (event.getValueIsAdjusting()) return;
+ updateRightComponent(true);
+ }
+ }
+}
diff --git a/platform/platform-impl/src/com/intellij/ui/popup/PopupComponent.java b/platform/platform-impl/src/com/intellij/ui/popup/PopupComponent.java
index 245a1bc029d8..ee6970495ec9 100644
--- a/platform/platform-impl/src/com/intellij/ui/popup/PopupComponent.java
+++ b/platform/platform-impl/src/com/intellij/ui/popup/PopupComponent.java
@@ -136,12 +136,23 @@ public interface PopupComponent {
if (!myRequestFocus) {
myDialog.setFocusableWindowState(false);
}
- if (UIUtil.isUnderDarcula()) {
- AWTUtilities.setWindowOpaque(myDialog, false);
+
+ try {
+ if (UIUtil.isUnderDarcula()) {
+ AWTUtilities.setWindowOpaque(myDialog, false);
+ }
}
+ catch (Exception ignore) {
+ }
+
myDialog.setVisible(true);
- if (UIUtil.isUnderDarcula()) {
- AWTUtilities.setWindowOpaque(myDialog, true);
+
+ try {
+ if (UIUtil.isUnderDarcula()) {
+ AWTUtilities.setWindowOpaque(myDialog, true);
+ }
+ }
+ catch (Exception ignore) {
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
diff --git a/platform/platform-impl/src/com/intellij/util/IJSwingUtilities.java b/platform/platform-impl/src/com/intellij/util/IJSwingUtilities.java
index 9458305d1aa0..459bade75457 100644
--- a/platform/platform-impl/src/com/intellij/util/IJSwingUtilities.java
+++ b/platform/platform-impl/src/com/intellij/util/IJSwingUtilities.java
@@ -179,6 +179,11 @@ public class IJSwingUtilities {
@Nullable
public static <T extends Component> T findParentOfType(Component focusOwner, Class<T> aClass) {
return (T)ContainerUtil.find(getParents(focusOwner), (FilteringIterator.InstanceOf<T>)FilteringIterator.instanceOf(aClass));
+
+ }
+ @Nullable
+ public static Component findParentByInterface(Component focusOwner, Class aClass) {
+ return ContainerUtil.find(getParents(focusOwner), FilteringIterator.instanceOf(aClass));
}
public static void adjustComponentsOnMac(@Nullable JComponent component) {
diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties
index bee939b62427..cb5b618baa3c 100644
--- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties
+++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties
@@ -605,12 +605,21 @@ arrangement.settings.text.general.order=Order:
arrangement.settings.text.general.xml.namespace=Namespace:
arrangement.settings.text.entry.type.xml.tag=tag
arrangement.settings.text.entry.type.xml.attribute=attribute
+arrangement.settings.additional.force.combobox.name=Force rearrange:
+arrangement.settings.additional.force.rearrange.always=Always
+arrangement.settings.additional.force.rearrange.never=Never
+arrangement.settings.additional.force.rearrange.according.to.dialog=Use current mode (toggled in the Reformat Code dialog)
+arrangement.settings.additional.title=Additional settings
+
+
checkbox.spaces.around.lambda.arrow=Lambda arrow
checkbox.spaces.around.method.ref.dbl.colon.arrow=Method reference double colon
settings.code.style.general.formatter.control=Formatter Control
settings.code.style.general.enable.formatter.tags=Enable formatter markers in comments
-settings.code.style.general.formatter.off.tag="Formatter off" marker\:
-settings.code.style.general.formatter.on.tag="Formatter on" marker\:
-settings.code.style.general.formatter.marker.regexp=Accept regular expressions
-settings.code.style.general.formatter.marker.invalid.regexp=Invalid regular expression \ No newline at end of file
+settings.code.style.general.formatter.off.tag=Formatter off\:
+settings.code.style.general.formatter.on.tag=Formatter on\:
+settings.code.style.general.formatter.marker.regexp=Regular expressions
+settings.code.style.general.formatter.marker.invalid.regexp=Invalid regular expression
+settings.code.style.general.formatter.marker.title=Markers
+settings.code.style.general.formatter.marker.options.title=Options \ No newline at end of file
diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties
index 67349d01c798..b89d9d33ba5f 100644
--- a/platform/platform-resources-en/src/messages/IdeBundle.properties
+++ b/platform/platform-resources-en/src/messages/IdeBundle.properties
@@ -327,6 +327,7 @@ title.new.annotation.type=New @interface
title.cannot.create.annotation.type=Cannot Create @interface
action.create.new.class=Create New Class
action.create.new.class.description=Create new Java class
+action.create.new.package-info.description=Create new package-info.java
prompt.enter.new.class.name=Enter a new class name:
title.new.class=New Class
progress.creating.class=Creating class {0}
@@ -630,6 +631,7 @@ checkbox.show.tool.window.bars=Show tool window bars
checkbox.widescreen.tool.window.layout=Widescreen tool window layout
checkbox.left.toolwindow.layout=Side-by-side layout on the left
checkbox.right.toolwindow.layout=Side-by-side layout on the right
+checkbox.show.editor.preview.popup=Show editor preview tooltip
checkbox.show.tool.window.numbers=Show tool window numbers
checkbox.animate.windows=Animate windows
group.transparency=Transparency
@@ -649,6 +651,7 @@ checkbox.use.antialiased.font.in.editor=Use anti-aliased font
# this string must start with "IDEA"
idea.default.look.and.feel=IDEA (4.5 default)
+idea.intellij.look.and.feel=IntelliJ
idea.dark.look.and.feel=Darcula
confirm.set.look.and.feel=Change &theme
error.cannot.set.look.and.feel=<html><body>Cannot set {0} theme:<br>{1}</body></html>
diff --git a/platform/platform-resources-en/src/messages/SMTestsRunnerBundle.properties b/platform/platform-resources-en/src/messages/SMTestsRunnerBundle.properties
index 6965dd6640e3..51a4ef7ed62d 100644
--- a/platform/platform-resources-en/src/messages/SMTestsRunnerBundle.properties
+++ b/platform/platform-resources-en/src/messages/SMTestsRunnerBundle.properties
@@ -13,7 +13,7 @@ sm.test.runner.ui.tests.tree.presentation.labels.instantiating.tests=Instantiati
sm.test.runner.ui.tests.tree.presentation.labels.not.test.results=No Test Results
sm.test.runner.ui.tests.tree.presentation.labels.was.terminated=Terminated
sm.test.runner.ui.tests.tree.presentation.labels.no.tests.were.found=No tests were found
-sm.test.runner.ui.tests.tree.presentation.labels.test.reporter.not.attached=Unable to attach test reporter to test framework or test framework quit unexpectedly
+sm.test.runner.ui.tests.tree.presentation.labels.test.reporter.not.attached=Test framework quit unexpectedly
sm.test.runner.ui.tests.tree.presentation.labels.no.tests.were.found.with.errors=No tests were found. Errors occurred
sm.test.runner.ui.tests.tree.presentation.labels.empty.test.suite=Empty test suite
sm.test.runner.ui.tests.tree.presentation.labels.all.tests.passed=All Tests Passed
diff --git a/platform/platform-resources-en/src/messages/XDebuggerBundle.properties b/platform/platform-resources-en/src/messages/XDebuggerBundle.properties
index 8e0d36d3e49a..985993c4c910 100644
--- a/platform/platform-resources-en/src/messages/XDebuggerBundle.properties
+++ b/platform/platform-resources-en/src/messages/XDebuggerBundle.properties
@@ -57,6 +57,7 @@ button.text.code.fragment.mode=Code Fragment &Mode
button.text.expression.mode=Expression &Mode
xdebugger.label.text.code.fragment=Code fragment:
xdebugger.evaluate.result=result
+xdebugger.evaluate.stack.frame.has.not.evaluator=Cannot evaluate, current stack frame doesn't support evaluation
xdebugger.popup.value.tree.set.root.action.tooltip=Set As Root
diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties
index 2116da2c7846..6887f6b5ebf0 100644
--- a/platform/platform-resources-en/src/misc/registry.properties
+++ b/platform/platform-resources-en/src/misc/registry.properties
@@ -70,7 +70,7 @@ ide.appIcon.progress=true
ide.appIcon.badge=true
ide.appIcon.requestAttention=true
-ide.windowSystem.hScrollChars=15
+ide.windowSystem.hScrollChars=5
ide.windowSystem.vScrollChars=5
ide.windowSystem.focusAppOnStartup=true
ide.windowSystem.autoShowProcessPopup=false
@@ -325,4 +325,5 @@ bigger.font.in.project.view=false
bigger.font.in.project.view.description=Increases font size in Project View
darcula.use.native.fonts.on.linux=true
darcula.use.native.fonts.on.linux.description=If false, uses DejaVu Sans 13pt
+idea.4.5.laf.enabled=true
diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml
index c948106faed7..12869478ffcc 100644
--- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml
+++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml
@@ -299,6 +299,7 @@
<postStartupActivity implementation="org.jetbrains.ide.BuiltInServerManagerImpl$MyPostStartupActivity"/>
<editorNotificationProvider implementation="com.intellij.ide.FileChangedNotificationProvider"/>
+ <editorNotificationProvider implementation="com.intellij.openapi.updateSettings.impl.pluginsAdvertisement.PluginAdvertiserEditorNotificationProvider"/>
<getDataRule key="context.ProjectFileDirectory" implementationClass="com.intellij.ide.impl.dataRules.ProjectFileDirectoryRule"/>
diff --git a/platform/platform-resources/src/META-INF/VcsExtensionPoints.xml b/platform/platform-resources/src/META-INF/VcsExtensionPoints.xml
index 2cc7f4b4022c..274036923c65 100644
--- a/platform/platform-resources/src/META-INF/VcsExtensionPoints.xml
+++ b/platform/platform-resources/src/META-INF/VcsExtensionPoints.xml
@@ -57,7 +57,5 @@
<extensionPoint name="vcs.taskHandler" interface="com.intellij.openapi.vcs.VcsTaskHandler" area="IDEA_PROJECT"/>
<extensionPoint name="vcs.rootFinder" interface="com.intellij.openapi.vcs.VcsRootFinder" area="IDEA_PROJECT"/>
-
- <extensionPoint name="logProvider" interface="com.intellij.vcs.log.VcsLogProvider" area="IDEA_PROJECT"/>
</extensionPoints>
</idea-plugin>
diff --git a/platform/platform-resources/src/idea/Keymap_Default.xml b/platform/platform-resources/src/idea/Keymap_Default.xml
index ff87611f1776..f05fc7e789e3 100644
--- a/platform/platform-resources/src/idea/Keymap_Default.xml
+++ b/platform/platform-resources/src/idea/Keymap_Default.xml
@@ -3,9 +3,6 @@
<action id="ShowNavBar">
<keyboard-shortcut first-keystroke="alt HOME"/>
</action>
- <action id="SearchEverywhere">
- <keyboard-shortcut first-keystroke="shift SPACE"/>
- </action>
<action id="FileChooser.TogglePathShowing">
<keyboard-shortcut first-keystroke="control P"/>
</action>
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.java
index 4dc17f00dfad..a941eb4c703b 100644
--- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.java
+++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.java
@@ -674,6 +674,12 @@ public class FileWatcherTest extends PlatformLangTestCase {
}
}
+ public void testPartialRefresh() throws Exception {
+ // tests the same scenario with an active file watcher (prevents explicit marking of refreshed paths)
+ File top = createTestDir("top");
+ LocalFileSystemTest.doTestPartialRefresh(top);
+ }
+
@NotNull
private LocalFileSystem.WatchRequest watch(File watchFile) {
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/LocalFileSystemTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/LocalFileSystemTest.java
index 7ee40baacf3f..ca6b5ae32ff3 100644
--- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/LocalFileSystemTest.java
+++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/LocalFileSystemTest.java
@@ -437,4 +437,40 @@ public class LocalFileSystemTest extends PlatformLangTestCase {
assertTrue(sourceFile.isValid());
assertEquals(newName, sourceFile.getName());
}
+
+ public void testPartialRefresh() throws Exception {
+ File top = createTempDirectory(false);
+ doTestPartialRefresh(top);
+ }
+
+ public static void doTestPartialRefresh(File top) throws IOException {
+ File sub = IoTestUtil.createTestDir(top, "sub");
+ File file = IoTestUtil.createTestFile(top, "sub.txt");
+ LocalFileSystem lfs = LocalFileSystem.getInstance();
+ NewVirtualFile topDir = (NewVirtualFile)lfs.refreshAndFindFileByIoFile(top);
+ assertNotNull(topDir);
+ NewVirtualFile subDir = (NewVirtualFile)lfs.refreshAndFindFileByIoFile(sub);
+ assertNotNull(subDir);
+ NewVirtualFile subFile = (NewVirtualFile)lfs.refreshAndFindFileByIoFile(file);
+ assertNotNull(subFile);
+ topDir.refresh(false, true);
+ assertFalse(topDir.isDirty());
+ assertFalse(subDir.isDirty());
+ assertFalse(subFile.isDirty());
+
+ subFile.markDirty();
+ subDir.markDirty();
+ assertTrue(topDir.isDirty());
+ assertTrue(subFile.isDirty());
+ assertTrue(subDir.isDirty());
+
+ topDir.refresh(false, false);
+ assertFalse(subFile.isDirty());
+ assertTrue(subDir.isDirty()); // should stay unvisited after non-recursive refresh
+
+ topDir.refresh(false, true);
+ assertFalse(topDir.isDirty());
+ assertFalse(subFile.isDirty());
+ assertFalse(subDir.isDirty());
+ }
}
diff --git a/platform/projectModel-api/src/com/intellij/openapi/projectRoots/ProjectJdkTable.java b/platform/projectModel-api/src/com/intellij/openapi/projectRoots/ProjectJdkTable.java
index 8fee9a1a98da..8c95d40fb068 100644
--- a/platform/projectModel-api/src/com/intellij/openapi/projectRoots/ProjectJdkTable.java
+++ b/platform/projectModel-api/src/com/intellij/openapi/projectRoots/ProjectJdkTable.java
@@ -93,5 +93,5 @@ public abstract class ProjectJdkTable {
public abstract Sdk createSdk(final String name, final SdkTypeId sdkType);
- public static Topic<Listener> JDK_TABLE_TOPIC = Topic.create("Project JDK table", Listener.class);
+ public static final Topic<Listener> JDK_TABLE_TOPIC = Topic.create("Project JDK table", Listener.class);
}
diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdater.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdater.java
index 6d5d68f636e2..12cadcd8e54c 100644
--- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdater.java
+++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdater.java
@@ -115,12 +115,7 @@ public class PushedFilePropertiesUpdater {
ProjectRootManager.getInstance(project).getFileIndex().iterateContentUnderDirectory(dir, new ContentIterator() {
@Override
public boolean processFile(final VirtualFile fileOrDir) {
- final boolean isDir = fileOrDir.isDirectory();
- for (FilePropertyPusher<Object> pusher : pushers) {
- if (!isDir && (pusher.pushDirectoriesOnly() || !pusher.acceptsFile(fileOrDir))) continue;
- else if (isDir && !pusher.acceptsDirectory(fileOrDir, myProject)) continue;
- findAndUpdateValue(project, fileOrDir, pusher, null);
- }
+ applyPushersToFile(fileOrDir, pushers, null);
return true;
}
});
@@ -159,13 +154,7 @@ public class PushedFilePropertiesUpdater {
index.iterateContentUnderDirectory(root, new ContentIterator() {
@Override
public boolean processFile(final VirtualFile fileOrDir) {
- final boolean isDir = fileOrDir.isDirectory();
- for (int i = 0, pushersLength = pushers.length; i < pushersLength; i++) {
- final FilePropertyPusher<Object> pusher = pushers[i];
- if (!isDir && (pusher.pushDirectoriesOnly() || !pusher.acceptsFile(fileOrDir))) continue;
- else if (isDir && !pusher.acceptsDirectory(fileOrDir, myProject)) continue;
- findAndUpdateValue(myProject, fileOrDir, pusher, moduleValues[i]);
- }
+ applyPushersToFile(fileOrDir, pushers, moduleValues);
return true;
}
});
@@ -173,6 +162,16 @@ public class PushedFilePropertiesUpdater {
}
}
+ private void applyPushersToFile(VirtualFile fileOrDir, FilePropertyPusher[] pushers, Object[] moduleValues) {
+ final boolean isDir = fileOrDir.isDirectory();
+ for (int i = 0, pushersLength = pushers.length; i < pushersLength; i++) {
+ final FilePropertyPusher<Object> pusher = pushers[i];
+ if (!isDir && (pusher.pushDirectoriesOnly() || !pusher.acceptsFile(fileOrDir))) continue;
+ else if (isDir && !pusher.acceptsDirectory(fileOrDir, myProject)) continue;
+ findAndUpdateValue(myProject, fileOrDir, pusher, moduleValues != null ? moduleValues[i]:null);
+ }
+ }
+
public static <T> void findAndUpdateValue(final Project project, final VirtualFile fileOrDir, final FilePropertyPusher<T> pusher, final T moduleValue) {
final T value = findPusherValuesUpwards(project, fileOrDir, pusher, moduleValue);
updateValue(fileOrDir, value, pusher);
diff --git a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtilTest.java b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtilTest.java
index ad5d8f0cbd71..a263bb186ef9 100644
--- a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtilTest.java
+++ b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/ui/TestsPresentationUtilTest.java
@@ -17,6 +17,7 @@ package com.intellij.execution.testframework.sm.runner.ui;
import com.intellij.execution.executors.DefaultDebugExecutor;
import com.intellij.execution.testframework.PoolOfTestIcons;
+import com.intellij.execution.testframework.sm.SMTestsRunnerBundle;
import com.intellij.execution.testframework.sm.UITestUtil;
import com.intellij.execution.testframework.sm.runner.BaseSMTRunnerTestCase;
import com.intellij.execution.testframework.sm.runner.SMTRunnerConsoleProperties;
@@ -575,7 +576,7 @@ public class TestsPresentationUtilTest extends BaseSMTRunnerTestCase {
assertEquals(PoolOfTestIcons.NOT_RAN, myRenderer.getIcon());
assertOneElement(myFragContainer.getFragments());
- assertEquals("Unable to attach test reporter to test framework or test framework quit unexpectedly", myFragContainer.getTextAt(0));
+ assertEquals(SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.test.reporter.not.attached"), myFragContainer.getTextAt(0));
assertEquals(SimpleTextAttributes.ERROR_ATTRIBUTES, myFragContainer.getAttribsAt(0));
}
diff --git a/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java b/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java
index 269ed4ca8546..e31569a394a6 100644
--- a/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java
+++ b/platform/testFramework/src/com/intellij/testFramework/FileStructureTestBase.java
@@ -42,10 +42,9 @@ public abstract class FileStructureTestBase extends CodeInsightFixtureTestCase {
public void setUp() throws Exception {
super.setUp();
myFixture.configureByFile(getFileName(getFileExtension()));
- myPopup = ViewStructureAction.createPopup(myFixture.getEditor(),
- myFixture.getProject(),
- null,
- TextEditorProvider.getInstance().getTextEditor(myFixture.getEditor()));
+ myPopup = ViewStructureAction.createPopup(
+ myFixture.getProject(),
+ TextEditorProvider.getInstance().getTextEditor(myFixture.getEditor()));
assert myPopup != null;
myPopup.createCenterPanel();
getBuilder().getUi().getUpdater().setPassThroughMode(true);
diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java
index ee0051b80099..fac110eec634 100644
--- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java
+++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.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,6 +44,7 @@ import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileFilter;
+import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
import com.intellij.util.Alarm;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ThrowableRunnable;
@@ -608,13 +609,14 @@ public class PlatformTestUtil {
FileDocumentManager.getInstance().saveAllDocuments();
VirtualFile[] childrenAfter = dirAfter.getChildren();
- if (dirAfter.isInLocalFileSystem()) {
+
+ if (dirAfter.isInLocalFileSystem() && dirAfter.getFileSystem() != TempFileSystem.getInstance()) {
File[] ioAfter = new File(dirAfter.getPath()).listFiles();
shallowCompare(childrenAfter, ioAfter);
}
VirtualFile[] childrenBefore = dirBefore.getChildren();
- if (dirBefore.isInLocalFileSystem()) {
+ if (dirBefore.isInLocalFileSystem() && dirBefore.getFileSystem() != TempFileSystem.getInstance()) {
File[] ioBefore = new File(dirBefore.getPath()).listFiles();
shallowCompare(childrenBefore, ioBefore);
}
diff --git a/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java
index 7d3567902f14..fd1e91d428eb 100644
--- a/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java
+++ b/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java
@@ -333,7 +333,7 @@ public class PsiTestUtil {
final String[] classRoots,
final String[] sourceRoots) {
final String parentUrl =
- VirtualFileManager.constructUrl(classRoots[0].endsWith(".jar!/") ? JarFileSystem.PROTOCOL : LocalFileSystem.PROTOCOL, libDir);
+ VirtualFileManager.constructUrl((classRoots.length > 0 ? classRoots[0]:sourceRoots[0]).endsWith(".jar!/") ? JarFileSystem.PROTOCOL : LocalFileSystem.PROTOCOL, libDir);
List<String> classesUrls = new ArrayList<String>();
List<String> sourceUrls = new ArrayList<String>();
for (String classRoot : classRoots) {
diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestUtil.java
index 464b268d2331..dd06c0d0a23d 100644
--- a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestUtil.java
+++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -43,14 +43,18 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.refactoring.rename.inplace.InplaceRefactoring;
import com.intellij.refactoring.rename.inplace.VariableInplaceRenameHandler;
+import com.intellij.testFramework.TestDataFile;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.junit.Assert;
+import java.io.File;
import java.util.List;
+import static junit.framework.Assert.assertTrue;
+
/**
* @author Dmitry Avdeev
*/
@@ -90,7 +94,7 @@ public class CodeInsightTestUtil {
}
public static void doWordSelectionTest(@NotNull final CodeInsightTestFixture fixture,
- @NotNull final String before, final String... after) {
+ @TestDataFile @NotNull final String before, @TestDataFile final String... after) {
assert after != null && after.length > 0;
fixture.configureByFile(before);
@@ -101,6 +105,27 @@ public class CodeInsightTestUtil {
fixture.checkResultByFile(file, false);
}
}
+
+ public static void doWordSelectionTestOnDirectory(@NotNull final CodeInsightTestFixture fixture,
+ @TestDataFile @NotNull final String directoryName,
+ @NotNull final String filesExtension) {
+ final SelectWordHandler action = new SelectWordHandler(null);
+ fixture.copyDirectoryToProject(directoryName, directoryName);
+ fixture.configureByFile(directoryName + "/before." + filesExtension);
+ int i = 1;
+ while (true) {
+ final String fileName = directoryName + "/after" + i + "." + filesExtension;
+ if (new File(fixture.getTestDataPath() + "/" + fileName).exists()) {
+ action.execute(fixture.getEditor(), DataManager.getInstance().getDataContext(fixture.getEditor().getComponent()));
+ fixture.checkResultByFile(fileName);
+ i++;
+ }
+ else {
+ break;
+ }
+ }
+ assertTrue("At least one 'after'-file required", i > 1);
+ }
public static void doSurroundWithTest(@NotNull final CodeInsightTestFixture fixture, @NotNull final Surrounder surrounder,
@NotNull final String before, @NotNull final String after) {
diff --git a/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java b/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java
index 3e8395d82c8c..d63c9bca7f48 100644
--- a/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java
+++ b/platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java
@@ -444,19 +444,15 @@ public class FileUtilRt {
public static boolean delete(@NotNull File file) {
if (file.isDirectory()) {
- if (!deleteChildren(file)) return false;
- }
- return deleteFile(file);
- }
-
- protected static boolean deleteChildren(@NotNull File file) {
- File[] files = file.listFiles();
- if (files != null) {
- for (File child : files) {
- if (!delete(child)) return false;
+ File[] files = file.listFiles();
+ if (files != null) {
+ for (File child : files) {
+ if (!delete(child)) return false;
+ }
}
}
- return true;
+
+ return deleteFile(file);
}
public interface RepeatableIOOperation<T, E extends Throwable> {
diff --git a/platform/util/src/com/intellij/icons/AllIcons.java b/platform/util/src/com/intellij/icons/AllIcons.java
index 0bd1a9c89f99..8027d91d483a 100644
--- a/platform/util/src/com/intellij/icons/AllIcons.java
+++ b/platform/util/src/com/intellij/icons/AllIcons.java
@@ -69,6 +69,7 @@ public class AllIcons {
public static final Icon Filter_small = IconLoader.getIcon("/actions/filter_small.png"); // 16x16
public static final Icon Find = IconLoader.getIcon("/actions/find.png"); // 16x16
public static final Icon FindPlain = IconLoader.getIcon("/actions/findPlain.png"); // 16x16
+ public static final Icon FindWhite = IconLoader.getIcon("/actions/findWhite.png"); // 16x16
public static final Icon ForceRefresh = IconLoader.getIcon("/actions/forceRefresh.png"); // 16x16
public static final Icon Forward = IconLoader.getIcon("/actions/forward.png"); // 16x16
public static final Icon GC = IconLoader.getIcon("/actions/gc.png"); // 16x16
@@ -856,8 +857,10 @@ public class AllIcons {
public static final Icon TestSourceFolder = IconLoader.getIcon("/nodes/testSourceFolder.png"); // 16x16
public static final Icon TreeClosed = IconLoader.getIcon("/nodes/TreeClosed.png"); // 16x16
public static final Icon TreeCollapseNode = IconLoader.getIcon("/nodes/treeCollapseNode.png"); // 16x16
+ public static final Icon TreeDownArrow = IconLoader.getIcon("/nodes/treeDownArrow.png"); // 11x11
public static final Icon TreeExpandNode = IconLoader.getIcon("/nodes/treeExpandNode.png"); // 16x16
public static final Icon TreeOpen = IconLoader.getIcon("/nodes/TreeOpen.png"); // 16x16
+ public static final Icon TreeRightArrow = IconLoader.getIcon("/nodes/treeRightArrow.png"); // 11x11
public static final Icon Undeploy = IconLoader.getIcon("/nodes/undeploy.png"); // 16x16
public static final Icon UnknownJdk = IconLoader.getIcon("/nodes/unknownJdk.png"); // 16x16
public static final Icon UpFolder = IconLoader.getIcon("/nodes/upFolder.png"); // 16x16
diff --git a/platform/util/src/com/intellij/openapi/util/NullableComputable.java b/platform/util/src/com/intellij/openapi/util/NullableComputable.java
index d87ef8668dc8..be75adbfd538 100644
--- a/platform/util/src/com/intellij/openapi/util/NullableComputable.java
+++ b/platform/util/src/com/intellij/openapi/util/NullableComputable.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -22,6 +22,7 @@ package com.intellij.openapi.util;
import org.jetbrains.annotations.Nullable;
public interface NullableComputable<T> extends Computable<T> {
+ @Override
@Nullable
T compute();
} \ No newline at end of file
diff --git a/platform/util/src/com/intellij/openapi/util/io/FileAttributes.java b/platform/util/src/com/intellij/openapi/util/io/FileAttributes.java
index 1064b748c2e0..910f3add5742 100644
--- a/platform/util/src/com/intellij/openapi/util/io/FileAttributes.java
+++ b/platform/util/src/com/intellij/openapi/util/io/FileAttributes.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.
@@ -29,25 +29,27 @@ public final class FileAttributes {
public enum Type { FILE, DIRECTORY, SPECIAL }
public static final byte SYM_LINK = 0x01;
- public static final byte HIDDEN = 0x20;
+ public static final byte HIDDEN = 0x02;
+ public static final byte READ_ONLY = 0x04;
- @MagicConstant(flags = {SYM_LINK, HIDDEN})
+ @MagicConstant(flags = {SYM_LINK, HIDDEN, READ_ONLY})
public @interface Flags { }
- public static final int OWNER_READ = 0400;
- public static final int OWNER_WRITE = 0200;
- public static final int OWNER_EXECUTE = 0100;
- public static final int GROUP_READ = 0040;
- public static final int GROUP_WRITE = 0020;
- public static final int GROUP_EXECUTE = 0010;
- public static final int OTHERS_READ = 0004;
- public static final int OTHERS_WRITE = 0002;
- public static final int OTHERS_EXECUTE = 0001;
-
- @MagicConstant(flags = {OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ, GROUP_WRITE, GROUP_EXECUTE, OTHERS_READ, OTHERS_WRITE, OTHERS_EXECUTE})
+ /** @deprecated (to remove in IDEA 14) */ @SuppressWarnings("unused") public static final int OWNER_READ = 0400;
+ /** @deprecated (to remove in IDEA 14) */ @SuppressWarnings("unused") public static final int OWNER_WRITE = 0200;
+ /** @deprecated (to remove in IDEA 14) */ @SuppressWarnings("unused") public static final int OWNER_EXECUTE = 0100;
+ /** @deprecated (to remove in IDEA 14) */ @SuppressWarnings("unused") public static final int GROUP_READ = 0040;
+ /** @deprecated (to remove in IDEA 14) */ @SuppressWarnings("unused") public static final int GROUP_WRITE = 0020;
+ /** @deprecated (to remove in IDEA 14) */ @SuppressWarnings("unused") public static final int GROUP_EXECUTE = 0010;
+ /** @deprecated (to remove in IDEA 14) */ @SuppressWarnings("unused") public static final int OTHERS_READ = 0004;
+ /** @deprecated (to remove in IDEA 14) */ @SuppressWarnings("unused") public static final int OTHERS_WRITE = 0002;
+ /** @deprecated (to remove in IDEA 14) */ @SuppressWarnings("unused") public static final int OTHERS_EXECUTE = 0001;
+
+ /** @deprecated (to remove in IDEA 14) */
+ @SuppressWarnings("unused")
public @interface Permissions { }
- public static final FileAttributes BROKEN_SYMLINK = new FileAttributes(null, SYM_LINK, 0, 0, -1);
+ public static final FileAttributes BROKEN_SYMLINK = new FileAttributes(null, SYM_LINK, 0, 0);
/**
* {@code null} means unknown type - typically broken symlink.
@@ -70,55 +72,39 @@ public final class FileAttributes {
*/
public final long lastModified;
- /**
- * UNIX permission bits (for Windows only OWNER_WRITE matters and OWNER_READ/EXECUTE are always set), or {@code -1} if not supported.<br/>
- * For symlinks - permissions of a link target.
- */
- @Permissions
- public final int permissions;
-
-
- public FileAttributes(final boolean isDirectory,
- final boolean isSpecial,
- final boolean isSymlink,
- final boolean isHidden,
- final long length,
- final long lastModified,
- final boolean isWritable) {
- this(type(isDirectory, isSpecial), flags(isSymlink, isHidden), length, lastModified,
- OWNER_READ | OWNER_EXECUTE | (isWritable ? OWNER_WRITE : 0));
+ /** @deprecated use {@linkplain #isWritable()} (to remove in IDEA 14) */
+ @SuppressWarnings("unused") public final int permissions;
+
+
+ public FileAttributes(boolean directory, boolean special, boolean symlink, boolean hidden, long length, long lastModified, boolean writable) {
+ this(type(directory, special), flags(symlink, hidden, !writable), length, lastModified);
}
- public FileAttributes(final boolean isDirectory,
- final boolean isSpecial,
- final boolean isSymlink,
- final long length,
- final long lastModified,
- @Permissions final int permissions) {
- this(type(isDirectory, isSpecial), flags(isSymlink, false), length, lastModified, permissions);
+ /** @deprecated use {@linkplain #FileAttributes(boolean, boolean, boolean, boolean, long, long, boolean)} (to remove in IDEA 14) */
+ @SuppressWarnings("unused")
+ public FileAttributes(boolean directory, boolean special, boolean symlink, long length, long lastModified, int permissions) {
+ this(type(directory, special), flags(symlink, false, true), length, lastModified);
}
- private FileAttributes(@Nullable final Type type,
- @Flags final byte flags,
- final long length,
- final long lastModified,
- @Permissions final int permissions) {
+ @SuppressWarnings("deprecation")
+ private FileAttributes(@Nullable Type type, @Flags byte flags, long length, long lastModified) {
this.type = type;
this.flags = flags;
this.length = length;
this.lastModified = lastModified;
- this.permissions = permissions;
+ this.permissions = -1;
}
- private static Type type(final boolean isDirectory, final boolean isSpecial) {
+ private static Type type(boolean isDirectory, boolean isSpecial) {
return isDirectory ? Type.DIRECTORY : isSpecial ? Type.SPECIAL : Type.FILE;
}
@Flags
- private static byte flags(final boolean isSymlink, final boolean isHidden) {
+ private static byte flags(boolean isSymlink, boolean isHidden, boolean isReadOnly) {
@Flags byte flags = 0;
if (isSymlink) flags |= SYM_LINK;
if (isHidden) flags |= HIDDEN;
+ if (isReadOnly) flags |= READ_ONLY;
return flags;
}
@@ -143,7 +129,7 @@ public final class FileAttributes {
}
public boolean isWritable() {
- return permissions == -1 || isSet(permissions, OWNER_WRITE) || isSet(permissions, GROUP_WRITE) || isSet(permissions, OTHERS_WRITE);
+ return !isSet(flags, READ_ONLY);
}
@Override
@@ -155,7 +141,6 @@ public final class FileAttributes {
if (flags != that.flags) return false;
if (lastModified != that.lastModified) return false;
if (length != that.length) return false;
- if (permissions != that.permissions) return false;
if (type != that.type) return false;
return true;
@@ -167,13 +152,13 @@ public final class FileAttributes {
result = 31 * result + (int)flags;
result = 31 * result + (int)(length ^ (length >>> 32));
result = 31 * result + (int)(lastModified ^ (lastModified >>> 32));
- result = 31 * result + permissions;
return result;
}
@Override
public String toString() {
- final StringBuilder sb = new StringBuilder();
+ StringBuilder sb = new StringBuilder();
+
sb.append("[type:");
if (type == Type.FILE) sb.append('f');
else if (type == Type.DIRECTORY) sb.append('d');
@@ -183,14 +168,12 @@ public final class FileAttributes {
if (isSet(flags, SYM_LINK)) sb.append('l');
if (isSet(flags, HIDDEN)) sb.append('.');
+ if (isSet(flags, READ_ONLY)) sb.append(" ro");
+
sb.append(" length:").append(length);
sb.append(" modified:").append(lastModified);
- if (permissions != -1) {
- sb.append(" mode:").append(Integer.toOctalString(permissions));
- }
-
sb.append(']');
return sb.toString();
}
diff --git a/platform/util/src/com/intellij/openapi/util/io/FileSystemUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileSystemUtil.java
index 55e09d3db198..1908f811e94c 100644
--- a/platform/util/src/com/intellij/openapi/util/io/FileSystemUtil.java
+++ b/platform/util/src/com/intellij/openapi/util/io/FileSystemUtil.java
@@ -49,17 +49,17 @@ public class FileSystemUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.io.FileSystemUtil");
- private interface Mediator {
+ private abstract static class Mediator {
@Nullable
- FileAttributes getAttributes(@NotNull String path) throws Exception;
+ protected abstract FileAttributes getAttributes(@NotNull String path) throws Exception;
@Nullable
- String resolveSymLink(@NotNull String path) throws Exception;
+ protected abstract String resolveSymLink(@NotNull String path) throws Exception;
- void setPermissions(@NotNull String path, int permissions) throws Exception;
+ protected boolean clonePermissions(@NotNull String source, @NotNull String target) throws Exception { return false; }
@NotNull
- String getName();
+ private String getName() { return getClass().getSimpleName().replace("MediatorImpl", ""); }
}
@NotNull
@@ -101,7 +101,7 @@ public class FileSystemUtil {
"Failed to load filesystem access layer (" + SystemInfo.OS_NAME + ", " + SystemInfo.JAVA_VERSION + ", " + forceUseNio2 + ")";
LOG.error(message, error);
- return new StandardMediatorImpl();
+ return new FallbackMediatorImpl();
}
private static Mediator check(final Mediator mediator) throws Exception {
@@ -110,16 +110,6 @@ public class FileSystemUtil {
return mediator;
}
- @TestOnly
- static void resetMediator() {
- ourMediator = getMediator();
- }
-
- @TestOnly
- static String getMediatorName() {
- return ourMediator.getName();
- }
-
private FileSystemUtil() { }
@Nullable
@@ -180,35 +170,42 @@ public class FileSystemUtil {
return resolveSymLink(file.getAbsolutePath());
}
+ /** @deprecated use {@link #clonePermissions(String, String)} (to remove in IDEA 14) */
+ @SuppressWarnings("UnusedDeclaration")
public static int getPermissions(@NotNull String path) {
- final FileAttributes attributes = getAttributes(path);
- return attributes != null ? attributes.permissions : -1;
+ return -1;
}
+ /** @deprecated use {@link #clonePermissions(String, String)} (to remove in IDEA 14) */
@SuppressWarnings("UnusedDeclaration")
public static int getPermissions(@NotNull File file) {
- return getPermissions(file.getAbsolutePath());
+ return -1;
}
- public static void setPermissions(@NotNull String path, int permissions) {
- if (SystemInfo.isUnix) {
- try {
- ourMediator.setPermissions(path, permissions);
- }
- catch (Exception e) {
- LOG.warn(e);
- }
- }
- }
+ /** @deprecated use {@link #clonePermissions(String, String)} (to remove in IDEA 14) */
+ @SuppressWarnings("UnusedDeclaration")
+ public static void setPermissions(@NotNull String path, int permissions) { }
+
+ /** @deprecated use {@link #clonePermissions(String, String)} (to remove in IDEA 14) */
+ @SuppressWarnings({"UnusedDeclaration", "deprecation"})
+ public static void setPermissions(@NotNull File file, int permissions) { }
- public static void setPermissions(@NotNull File file, int permissions) {
- setPermissions(file.getAbsolutePath(), permissions);
+ /**
+ * Gives the second file permissions of the first one if possible; returns true if succeed.
+ * Will do nothing on Windows.
+ */
+ public static boolean clonePermissions(@NotNull String source, @NotNull String target) {
+ try {
+ return ourMediator.clonePermissions(source, target);
+ }
+ catch (Exception e) {
+ LOG.warn(e);
+ return false;
+ }
}
- // todo[r.sh] remove reflection after migration to JDK 7
- @SuppressWarnings("OctalInteger")
- private static class Nio2MediatorImpl implements Mediator {
+ private static class Nio2MediatorImpl extends Mediator {
private final Object myDefaultFileSystem;
private final Method myGetPath;
private final Method myIsSymbolicLink;
@@ -220,10 +217,13 @@ public class FileSystemUtil {
private final String mySchema;
private Nio2MediatorImpl() throws Exception {
- if (Patches.USE_REFLECTION_TO_ACCESS_JDK7) {
+ //noinspection ConstantConditions
+ assert Patches.USE_REFLECTION_TO_ACCESS_JDK7;
+
myDefaultFileSystem = Class.forName("java.nio.file.FileSystems").getMethod("getDefault").invoke(null);
- myGetPath = Class.forName("java.nio.file.FileSystem").getMethod("getPath", String.class, String[].class);
+ final Class<?> fsClass = Class.forName("java.nio.file.FileSystem");
+ myGetPath = fsClass.getMethod("getPath", String.class, String[].class);
myGetPath.setAccessible(true);
final Class<?> pathClass = Class.forName("java.nio.file.Path");
@@ -247,16 +247,15 @@ public class FileSystemUtil {
myToMillis.setAccessible(true);
mySchema = SystemInfo.isWindows ? "dos:*" : "posix:*";
- }
}
@Override
- public FileAttributes getAttributes(@NotNull final String path) throws Exception {
+ protected FileAttributes getAttributes(@NotNull String path) throws Exception {
try {
- final Object pathObj = myGetPath.invoke(myDefaultFileSystem, path, ArrayUtil.EMPTY_STRING_ARRAY);
+ Object pathObj = myGetPath.invoke(myDefaultFileSystem, path, ArrayUtil.EMPTY_STRING_ARRAY);
Map attributes = (Map)myReadAttributes.invoke(null, pathObj, mySchema, myNoFollowLinkOptions);
- final boolean isSymbolicLink = (Boolean)attributes.get("isSymbolicLink");
+ boolean isSymbolicLink = (Boolean)attributes.get("isSymbolicLink");
if (isSymbolicLink) {
try {
attributes = (Map)myReadAttributes.invoke(null, pathObj, mySchema, myLinkOptions);
@@ -269,18 +268,18 @@ public class FileSystemUtil {
}
}
- final boolean isDirectory = (Boolean)attributes.get("isDirectory");
- final boolean isOther = (Boolean)attributes.get("isOther");
- final long size = (Long)attributes.get("size");
- final long lastModified = (Long)myToMillis.invoke(attributes.get("lastModifiedTime"));
+ boolean isDirectory = (Boolean)attributes.get("isDirectory");
+ boolean isOther = (Boolean)attributes.get("isOther");
+ long size = (Long)attributes.get("size");
+ long lastModified = (Long)myToMillis.invoke(attributes.get("lastModifiedTime"));
if (SystemInfo.isWindows) {
- final boolean isHidden = (Boolean)attributes.get("hidden");
- final boolean isWritable = !(Boolean)attributes.get("readonly");
+ boolean isHidden = new File(path).getParent() == null ? false : (Boolean)attributes.get("hidden");
+ boolean isWritable = !(Boolean)attributes.get("readonly");
return new FileAttributes(isDirectory, isOther, isSymbolicLink, isHidden, size, lastModified, isWritable);
}
else {
- final int permissions = decodePermissions(attributes.get("permissions"));
- return new FileAttributes(isDirectory, isOther, isSymbolicLink, size, lastModified, permissions);
+ boolean isWritable = new File(path).canWrite();
+ return new FileAttributes(isDirectory, isOther, isSymbolicLink, false, size, lastModified, isWritable);
}
}
catch (InvocationTargetException e) {
@@ -295,176 +294,132 @@ public class FileSystemUtil {
}
@Override
- public String resolveSymLink(@NotNull final String path) throws Exception {
+ protected String resolveSymLink(@NotNull final String path) throws Exception {
if (!new File(path).exists()) return null;
- assert Patches.USE_REFLECTION_TO_ACCESS_JDK7;
-
final Object pathObj = myGetPath.invoke(myDefaultFileSystem, path, ArrayUtil.EMPTY_STRING_ARRAY);
final Method toRealPath = pathObj.getClass().getMethod("toRealPath", myLinkOptions.getClass());
toRealPath.setAccessible(true);
return toRealPath.invoke(pathObj, myLinkOptions).toString();
-
}
@Override
- public void setPermissions(@NotNull final String path, final int permissions) throws Exception {
- final Object pathObj = myGetPath.invoke(myDefaultFileSystem, path, ArrayUtil.EMPTY_STRING_ARRAY);
- final Object attribute = encodePermissions(permissions);
- if (attribute != null) {
- mySetAttribute.invoke(null, pathObj, "posix:permissions", attribute, myLinkOptions);
- }
- }
-
- @NotNull
- @Override
- public String getName() {
- return "NIO2";
- }
-
- private static final Map<String, Integer> ATTRIBUTES_MAP;
- static {
- ATTRIBUTES_MAP = new HashMap<String, Integer>();
- ATTRIBUTES_MAP.put("OWNER_READ", FileAttributes.OWNER_READ);
- ATTRIBUTES_MAP.put("OWNER_WRITE", FileAttributes.OWNER_WRITE);
- ATTRIBUTES_MAP.put("OWNER_EXECUTE", FileAttributes.OWNER_EXECUTE);
- ATTRIBUTES_MAP.put("GROUP_READ", FileAttributes.GROUP_READ);
- ATTRIBUTES_MAP.put("GROUP_WRITE", FileAttributes.GROUP_WRITE);
- ATTRIBUTES_MAP.put("GROUP_EXECUTE", FileAttributes.GROUP_EXECUTE);
- ATTRIBUTES_MAP.put("OTHERS_READ", FileAttributes.OTHERS_READ);
- ATTRIBUTES_MAP.put("OTHERS_WRITE", FileAttributes.OTHERS_WRITE);
- ATTRIBUTES_MAP.put("OTHERS_EXECUTE", FileAttributes.OTHERS_EXECUTE);
- }
-
- @FileAttributes.Permissions
- private static int decodePermissions(final Object o) {
- if (!(o instanceof Collection)) return -1;
-
- int value = 0;
- for (Object attr : (Collection)o) {
- final Integer bit = ATTRIBUTES_MAP.get(attr.toString());
- if (bit != null) value |= bit;
- }
- //noinspection MagicConstant
- return value;
- }
-
- @Nullable
- @SuppressWarnings("unchecked")
- private static Object encodePermissions(final int value) {
- try {
- final Class aClass = Class.forName("java.nio.file.attribute.PosixFilePermission");
- final Set values = new HashSet();
- for (Map.Entry<String, Integer> entry : ATTRIBUTES_MAP.entrySet()) {
- if ((value & entry.getValue()) > 0) {
- final String name = entry.getKey();
- values.add(Enum.valueOf(aClass, name));
+ protected boolean clonePermissions(@NotNull String source, @NotNull String target) throws Exception {
+ if (SystemInfo.isUnix) {
+ Object pathObj = myGetPath.invoke(myDefaultFileSystem, source, ArrayUtil.EMPTY_STRING_ARRAY);
+ Map attributes = (Map)myReadAttributes.invoke(null, pathObj, "posix:permissions", myLinkOptions);
+ if (attributes != null && SystemProperties.getUserName().equals(attributes.get("posix:owner"))) {
+ Object permissions = attributes.get("permissions");
+ if (permissions instanceof Collection) {
+ mySetAttribute.invoke(null, pathObj, "posix:permissions", permissions, myLinkOptions);
+ return true;
}
}
- return values;
}
- catch (Exception ignore) { }
- return null;
+ return false;
}
}
- private static class IdeaWin32MediatorImpl implements Mediator {
+ private static class IdeaWin32MediatorImpl extends Mediator {
private IdeaWin32 myInstance = IdeaWin32.getInstance();
@Override
- public FileAttributes getAttributes(@NotNull final String path) throws Exception {
+ protected FileAttributes getAttributes(@NotNull final String path) throws Exception {
final FileInfo fileInfo = myInstance.getInfo(path);
return fileInfo != null ? fileInfo.toFileAttributes() : null;
}
@Override
- public String resolveSymLink(@NotNull final String path) throws Exception {
+ protected String resolveSymLink(@NotNull final String path) throws Exception {
return myInstance.resolveSymLink(path);
}
-
- @Override
- public void setPermissions(@NotNull final String path, final int permissions) throws Exception {
- }
-
- @NotNull
- @Override
- public String getName() {
- return "IdeaWin32";
- }
}
- // thanks to SVNKit for the idea
- private static class JnaUnixMediatorImpl implements Mediator {
+ // thanks to SVNKit for the idea of platform-specific offsets
+ private static class JnaUnixMediatorImpl extends Mediator {
@SuppressWarnings({"OctalInteger", "SpellCheckingInspection"})
private interface LibC extends Library {
- // from stat(2)
int S_MASK = 0177777;
int S_IFLNK = 0120000; // symbolic link
int S_IFREG = 0100000; // regular file
int S_IFDIR = 0040000; // directory
int PERM_MASK = 0777;
+ int WRITE_MASK = 0222;
+ int W_OK = 2; // write permission flag for access(2)
+ int getuid();
+ int getgid();
int lstat(String path, Pointer stat);
int stat(String path, Pointer stat);
int __lxstat64(int ver, String path, Pointer stat);
int __xstat64(int ver, String path, Pointer stat);
int chmod(String path, int mode);
+ int access(String path, int mode);
}
+ private static final int[] LINUX_32 = {16, 44, 72, 24, 28};
+ private static final int[] LINUX_64 = {24, 48, 88, 28, 32};
+ private static final int[] BSD_32 = { 8, 48, 32, 12, 16};
+ private static final int[] BSD_64 = { 8, 72, 40, 12, 16};
+ private static final int[] SUN_OS_32 = {20, 48, 64, 28, 32};
+ private static final int[] SUN_OS_64 = {16, 40, 64, 24, 28};
+
+ private static final int OFF_MODE = 0;
+ private static final int OFF_SIZE = 1;
+ private static final int OFF_TIME = 2;
+ private static final int OFF_UID = 3;
+ private static final int OFF_GID = 4;
+
private final LibC myLibC;
- private final int myModeOffset;
- private final int mySizeOffset;
- private final int myTimeOffset;
+ private final int[] myOffsets;
+ private final int myUid;
+ private final int myGid;
private final boolean myCoarseTs = SystemProperties.getBooleanProperty(COARSE_TIMESTAMP, false);
private JnaUnixMediatorImpl() throws Exception {
- myModeOffset = SystemInfo.isLinux ? (SystemInfo.is32Bit ? 16 : 24) :
- SystemInfo.isMac | SystemInfo.isFreeBSD ? 8 :
- SystemInfo.isSolaris ? (SystemInfo.is32Bit ? 20 : 16) :
- -1;
- mySizeOffset = SystemInfo.isLinux ? (SystemInfo.is32Bit ? 44 : 48) :
- SystemInfo.isMac | SystemInfo.isFreeBSD ? (SystemInfo.is32Bit ? 48 : 72) :
- SystemInfo.isSolaris ? (SystemInfo.is32Bit ? 48 : 40) :
- -1;
- myTimeOffset = SystemInfo.isLinux ? (SystemInfo.is32Bit ? 72 : 88) :
- SystemInfo.isMac | SystemInfo.isFreeBSD ? (SystemInfo.is32Bit ? 32 : 40) :
- SystemInfo.isSolaris ? 64 :
- -1;
- if (myModeOffset < 0) throw new IllegalStateException("Unsupported OS: " + SystemInfo.OS_NAME);
+ myOffsets = SystemInfo.isLinux ? (SystemInfo.is32Bit ? LINUX_32 : LINUX_64) :
+ SystemInfo.isMac | SystemInfo.isFreeBSD ? (SystemInfo.is32Bit ? BSD_32 : BSD_64) :
+ SystemInfo.isSolaris ? (SystemInfo.is32Bit ? SUN_OS_32 : SUN_OS_64) :
+ null;
+ if (myOffsets == null || myOffsets.length != 5) throw new IllegalStateException("Unsupported OS: " + SystemInfo.OS_NAME);
myLibC = (LibC)Native.loadLibrary("c", LibC.class);
+ myUid = myLibC.getuid();
+ myGid = myLibC.getgid();
}
@Override
- public FileAttributes getAttributes(@NotNull final String path) throws Exception {
+ protected FileAttributes getAttributes(@NotNull String path) throws Exception {
Memory buffer = new Memory(256);
int res = SystemInfo.isLinux ? myLibC.__lxstat64(0, path, buffer) : myLibC.lstat(path, buffer);
if (res != 0) return null;
- int mode = (SystemInfo.isLinux ? buffer.getInt(myModeOffset) : buffer.getShort(myModeOffset)) & LibC.S_MASK;
+ int mode = (SystemInfo.isLinux ? buffer.getInt(myOffsets[OFF_MODE]) : buffer.getShort(myOffsets[OFF_MODE])) & LibC.S_MASK;
boolean isSymlink = (mode & LibC.S_IFLNK) == LibC.S_IFLNK;
if (isSymlink) {
res = SystemInfo.isLinux ? myLibC.__xstat64(0, path, buffer) : myLibC.stat(path, buffer);
if (res != 0) {
return FileAttributes.BROKEN_SYMLINK;
}
- mode = (SystemInfo.isLinux ? buffer.getInt(myModeOffset) : buffer.getShort(myModeOffset)) & LibC.S_MASK;
+ mode = (SystemInfo.isLinux ? buffer.getInt(myOffsets[OFF_MODE]) : buffer.getShort(myOffsets[OFF_MODE])) & LibC.S_MASK;
}
boolean isDirectory = (mode & LibC.S_IFDIR) == LibC.S_IFDIR;
boolean isSpecial = !isDirectory && (mode & LibC.S_IFREG) == 0;
- long size = buffer.getLong(mySizeOffset);
- long mTime1 = SystemInfo.is32Bit ? buffer.getInt(myTimeOffset) : buffer.getLong(myTimeOffset);
- long mTime2 = myCoarseTs ? 0 : SystemInfo.is32Bit ? buffer.getInt(myTimeOffset + 4) : buffer.getLong(myTimeOffset + 8);
+ long size = buffer.getLong(myOffsets[OFF_SIZE]);
+ long mTime1 = SystemInfo.is32Bit ? buffer.getInt(myOffsets[OFF_TIME]) : buffer.getLong(myOffsets[OFF_TIME]);
+ long mTime2 = myCoarseTs ? 0 : SystemInfo.is32Bit ? buffer.getInt(myOffsets[OFF_TIME] + 4) : buffer.getLong(myOffsets[OFF_TIME] + 8);
long mTime = mTime1 * 1000 + mTime2 / 1000000;
- @FileAttributes.Permissions int permissions = mode & LibC.PERM_MASK;
- return new FileAttributes(isDirectory, isSpecial, isSymlink, size, mTime, permissions);
+
+ boolean writable = ownFile(buffer) ? (mode & LibC.WRITE_MASK) != 0 : myLibC.access(path, LibC.W_OK) == 0;
+
+ return new FileAttributes(isDirectory, isSpecial, isSymlink, false, size, mTime, writable);
}
@Override
- public String resolveSymLink(@NotNull final String path) throws Exception {
+ protected String resolveSymLink(@NotNull final String path) throws Exception {
try {
return new File(path).getCanonicalPath();
}
@@ -479,19 +434,24 @@ public class FileSystemUtil {
}
@Override
- public void setPermissions(@NotNull final String path, final int permissions) throws Exception {
- myLibC.chmod(path, permissions & LibC.PERM_MASK);
+ protected boolean clonePermissions(@NotNull String source, @NotNull String target) throws Exception {
+ Memory buffer = new Memory(256);
+ int res = SystemInfo.isLinux ? myLibC.__xstat64(0, source, buffer) : myLibC.stat(source, buffer);
+ if (res == 0 && ownFile(buffer)) {
+ int permissions = (SystemInfo.isLinux ? buffer.getInt(myOffsets[OFF_MODE]) : buffer.getShort(myOffsets[OFF_MODE])) & LibC.PERM_MASK;
+ return myLibC.chmod(target, permissions) == 0;
+ }
+
+ return false;
}
- @NotNull
- @Override
- public String getName() {
- return "JnaUnix";
+ private boolean ownFile(Memory buffer) {
+ return buffer.getInt(myOffsets[OFF_UID]) == myUid && buffer.getInt(myOffsets[OFF_GID]) == myGid;
}
}
- private static class StandardMediatorImpl implements Mediator {
+ private static class FallbackMediatorImpl extends Mediator {
// from java.io.FileSystem
private static final int BA_REGULAR = 0x02;
private static final int BA_DIRECTORY = 0x04;
@@ -500,7 +460,7 @@ public class FileSystemUtil {
private final Object myFileSystem;
private final Method myGetBooleanAttributes;
- private StandardMediatorImpl() {
+ private FallbackMediatorImpl() {
Object fileSystem;
Method getBooleanAttributes;
try {
@@ -520,7 +480,7 @@ public class FileSystemUtil {
}
@Override
- public FileAttributes getAttributes(@NotNull final String path) throws Exception {
+ protected FileAttributes getAttributes(@NotNull final String path) throws Exception {
final File file = new File(path);
if (myFileSystem != null) {
final int flags = (Integer)myGetBooleanAttributes.invoke(myFileSystem, file);
@@ -544,18 +504,18 @@ public class FileSystemUtil {
}
@Override
- public String resolveSymLink(@NotNull final String path) throws Exception {
+ protected String resolveSymLink(@NotNull final String path) throws Exception {
return new File(path).getCanonicalPath();
}
+ }
- @Override
- public void setPermissions(@NotNull final String path, final int permissions) throws Exception {
- }
+ @TestOnly
+ static void resetMediator() {
+ ourMediator = getMediator();
+ }
- @NotNull
- @Override
- public String getName() {
- return "fallback";
- }
+ @TestOnly
+ static String getMediatorName() {
+ return ourMediator.getName();
}
}
diff --git a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java
index 9a6363e7891d..cd3668c73250 100644
--- a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java
+++ b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java
@@ -417,7 +417,12 @@ public class FileUtil extends FileUtilRt {
if (attributes == null) return true;
if (attributes.isDirectory() && !attributes.isSymLink()) {
- if (!deleteChildren(file)) return false;
+ File[] files = file.listFiles();
+ if (files != null) {
+ for (File child : files) {
+ if (!delete(child)) return false;
+ }
+ }
}
return deleteFile(file);
@@ -484,11 +489,7 @@ public class FileUtil extends FileUtilRt {
}
if (SystemInfo.isUnix && fromFile.canExecute()) {
- final int oldPermissions = FileSystemUtil.getPermissions(fromFile);
- final int newPermissions = FileSystemUtil.getPermissions(toFile);
- if (oldPermissions != -1 && newPermissions != -1) {
- FileSystemUtil.setPermissions(toFile, oldPermissions | newPermissions);
- }
+ FileSystemUtil.clonePermissions(fromFile.getPath(), toFile.getPath());
}
}
@@ -1047,9 +1048,9 @@ public class FileUtil extends FileUtilRt {
writeToFile(file, text, 0, text.length, append);
}
- private static void writeToFile(@NotNull File file, @NotNull byte[] text, final int off, final int len, boolean append)
- throws IOException {
+ private static void writeToFile(@NotNull File file, @NotNull byte[] text, int off, int len, boolean append) throws IOException {
createParentDirs(file);
+
OutputStream stream = new FileOutputStream(file, append);
try {
stream.write(text, off, len);
diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
index 7fcfc157409b..76595763405f 100644
--- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
+++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
@@ -2219,7 +2219,8 @@ public class StringUtil extends StringUtilRt {
private static int naturalCompare(@NotNull String string1, @NotNull String string2, boolean caseSensitive) {
final int string1Length = string1.length();
final int string2Length = string2.length();
- for (int i = 0, j = 0; i < string1Length && j < string2Length; i++, j++) {
+ int i = 0, j = 0;
+ for (; i < string1Length && j < string2Length; i++, j++) {
char ch1 = string1.charAt(i);
char ch2 = string2.charAt(j);
if ((isDigit(ch1) || ch1 == ' ') && (isDigit(ch2) || ch2 == ' ')) {
@@ -2230,36 +2231,30 @@ public class StringUtil extends StringUtilRt {
ch1 = string1.charAt(startNum1);
}
int startNum2 = j;
- while (ch2 == ' ' || ch2 == '0') {
+ while (ch2 == ' ' || ch2 == '0') { // skip leading spaces and zeros
startNum2++;
if (startNum2 >= string2Length) break;
ch2 = string2.charAt(startNum2);
}
i = startNum1;
j = startNum2;
+ // find end index of number
while (i < string1Length && isDigit(string1.charAt(i))) i++;
while (j < string2Length && isDigit(string2.charAt(j))) j++;
- String digits1 = string1.substring(startNum1, i);
- String digits2 = string2.substring(startNum2, j);
- if (digits1.length() != digits2.length()) {
- return digits1.length() - digits2.length();
- }
- int numberDiff = digits1.compareTo(digits2);
- if (numberDiff != 0) {
- return numberDiff;
- }
- i--;
- j--;
final int lengthDiff = (i - startNum1) - (j - startNum2);
if (lengthDiff != 0) {
+ // numbers with more digits are always greater than shorter numbers
return lengthDiff;
}
for (; startNum1 < i; startNum1++, startNum2++) {
+ // compare numbers with equal digit count
final int diff = string1.charAt(startNum1) - string2.charAt(startNum2);
if (diff != 0) {
return diff;
}
}
+ i--;
+ j--;
}
else {
if (caseSensitive) {
@@ -2279,6 +2274,15 @@ public class StringUtil extends StringUtilRt {
}
}
}
+ // After the loop the end of one of the strings might not have been reached, if the other
+ // string ends with a number and the strings are equal until the end of that number. When
+ // there are more characters in the string, then it is greater.
+ if (i < string1Length) {
+ return 1;
+ }
+ else if (j < string2Length) {
+ return -1;
+ }
if (!caseSensitive && string1Length == string2Length) {
// do case sensitive compare if case insensitive strings are equal
return naturalCompare(string1, string2, true);
diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java
index 19affacd0fdb..d70ef92d98e7 100644
--- a/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java
+++ b/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -17,1503 +17,7158 @@
package com.intellij.util.containers;
import com.intellij.util.ConcurrencyUtil;
+import com.intellij.util.IncorrectOperationException;
import gnu.trove.TObjectHashingStrategy;
+import jsr166e.CountedCompleter;
+import jsr166e.ForkJoinPool;
import org.jetbrains.annotations.NotNull;
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
+import sun.misc.Unsafe;
+
+import java.io.*;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
+/**
+ * A hash table supporting full concurrency of retrievals and
+ * high expected concurrency for updates. This class obeys the
+ * same functional specification as {@link java.util.Hashtable}, and
+ * includes versions of methods corresponding to each method of
+ * {@code Hashtable}. However, even though all operations are
+ * thread-safe, retrieval operations do <em>not</em> entail locking,
+ * and there is <em>not</em> any support for locking the entire table
+ * in a way that prevents all access. This class is fully
+ * interoperable with {@code Hashtable} in programs that rely on its
+ * thread safety but not on its synchronization details.
+ *
+ * <p>Retrieval operations (including {@code get}) generally do not
+ * block, so may overlap with update operations (including {@code put}
+ * and {@code remove}). Retrievals reflect the results of the most
+ * recently <em>completed</em> update operations holding upon their
+ * onset. (More formally, an update operation for a given key bears a
+ * <em>happens-before</em> relation with any (non-null) retrieval for
+ * that key reporting the updated value.) For aggregate operations
+ * such as {@code putAll} and {@code clear}, concurrent retrievals may
+ * reflect insertion or removal of only some entries. Similarly,
+ * Iterators and Enumerations return elements reflecting the state of
+ * the hash table at some point at or since the creation of the
+ * iterator/enumeration. They do <em>not</em> throw {@link
+ * ConcurrentModificationException}. However, iterators are designed
+ * to be used by only one thread at a time. Bear in mind that the
+ * results of aggregate status methods including {@code size}, {@code
+ * isEmpty}, and {@code containsValue} are typically useful only when
+ * a map is not undergoing concurrent updates in other threads.
+ * Otherwise the results of these methods reflect transient states
+ * that may be adequate for monitoring or estimation purposes, but not
+ * for program control.
+ *
+ * <p>The table is dynamically expanded when there are too many
+ * collisions (i.e., keys that have distinct hash codes but fall into
+ * the same slot modulo the table size), with the expected average
+ * effect of maintaining roughly two bins per mapping (corresponding
+ * to a 0.75 load factor threshold for resizing). There may be much
+ * variance around this average as mappings are added and removed, but
+ * overall, this maintains a commonly accepted time/space tradeoff for
+ * hash tables. However, resizing this or any other kind of hash
+ * table may be a relatively slow operation. When possible, it is a
+ * good idea to provide a size estimate as an optional {@code
+ * initialCapacity} constructor argument. An additional optional
+ * {@code loadFactor} constructor argument provides a further means of
+ * customizing initial table capacity by specifying the table density
+ * to be used in calculating the amount of space to allocate for the
+ * given number of elements. Also, for compatibility with previous
+ * versions of this class, constructors may optionally specify an
+ * expected {@code concurrencyLevel} as an additional hint for
+ * internal sizing. Note that using many keys with exactly the same
+ * {@code hashCode()} is a sure way to slow down performance of any
+ * hash table. To ameliorate impact, when keys are {@link Comparable},
+ * this class may use comparison order among keys to help break ties.
+ *
+ * <p>A {@link Set} projection of a ConcurrentHashMapV8 may be created
+ * (using {@link #newKeySet()} or {@link #newKeySet(int)}), or viewed
+ * (using {@link #keySet(Object)} when only keys are of interest, and the
+ * mapped values are (perhaps transiently) not used or all take the
+ * same mapping value.
+ *
+ * <p>This class and its views and iterators implement all of the
+ * <em>optional</em> methods of the {@link Map} and {@link Iterator}
+ * interfaces.
+ *
+ * <p>Like {@link Hashtable} but unlike {@link java.util.HashMap}, this class
+ * does <em>not</em> allow {@code null} to be used as a key or value.
+ *
+ * <p>ConcurrentHashMapV8s support a set of sequential and parallel bulk
+ * operations that are designed
+ * to be safely, and often sensibly, applied even with maps that are
+ * being concurrently updated by other threads; for example, when
+ * computing a snapshot summary of the values in a shared registry.
+ * There are three kinds of operation, each with four forms, accepting
+ * functions with Keys, Values, Entries, and (Key, Value) arguments
+ * and/or return values. Because the elements of a ConcurrentHashMapV8
+ * are not ordered in any particular way, and may be processed in
+ * different orders in different parallel executions, the correctness
+ * of supplied functions should not depend on any ordering, or on any
+ * other objects or values that may transiently change while
+ * computation is in progress; and except for forEach actions, should
+ * ideally be side-effect-free. Bulk operations on {@link java.util.Map.Entry}
+ * objects do not support method {@code setValue}.
+ *
+ * <ul>
+ * <li> forEach: Perform a given action on each element.
+ * A variant form applies a given transformation on each element
+ * before performing the action.</li>
+ *
+ * <li> search: Return the first available non-null result of
+ * applying a given function on each element; skipping further
+ * search when a result is found.</li>
+ *
+ * <li> reduce: Accumulate each element. The supplied reduction
+ * function cannot rely on ordering (more formally, it should be
+ * both associative and commutative). There are five variants:
+ *
+ * <ul>
+ *
+ * <li> Plain reductions. (There is not a form of this method for
+ * (key, value) function arguments since there is no corresponding
+ * return type.)</li>
+ *
+ * <li> Mapped reductions that accumulate the results of a given
+ * function applied to each element.</li>
+ *
+ * <li> Reductions to scalar doubles, longs, and ints, using a
+ * given basis value.</li>
+ *
+ * </ul>
+ * </li>
+ * </ul>
+ *
+ * <p>These bulk operations accept a {@code parallelismThreshold}
+ * argument. Methods proceed sequentially if the current map size is
+ * estimated to be less than the given threshold. Using a value of
+ * {@code Long.MAX_VALUE} suppresses all parallelism. Using a value
+ * of {@code 1} results in maximal parallelism by partitioning into
+ * enough subtasks to fully utilize the {@link
+ * ForkJoinPool#commonPool()} that is used for all parallel
+ * computations. Normally, you would initially choose one of these
+ * extreme values, and then measure performance of using in-between
+ * values that trade off overhead versus throughput.
+ *
+ * <p>The concurrency properties of bulk operations follow
+ * from those of ConcurrentHashMapV8: Any non-null result returned
+ * from {@code get(key)} and related access methods bears a
+ * happens-before relation with the associated insertion or
+ * update. The result of any bulk operation reflects the
+ * composition of these per-element relations (but is not
+ * necessarily atomic with respect to the map as a whole unless it
+ * is somehow known to be quiescent). Conversely, because keys
+ * and values in the map are never null, null serves as a reliable
+ * atomic indicator of the current lack of any result. To
+ * maintain this property, null serves as an implicit basis for
+ * all non-scalar reduction operations. For the double, long, and
+ * int versions, the basis should be one that, when combined with
+ * any other value, returns that other value (more formally, it
+ * should be the identity element for the reduction). Most common
+ * reductions have these properties; for example, computing a sum
+ * with basis 0 or a minimum with basis MAX_VALUE.
+ *
+ * <p>Search and transformation functions provided as arguments
+ * should similarly return null to indicate the lack of any result
+ * (in which case it is not used). In the case of mapped
+ * reductions, this also enables transformations to serve as
+ * filters, returning null (or, in the case of primitive
+ * specializations, the identity basis) if the element should not
+ * be combined. You can create compound transformations and
+ * filterings by composing them yourself under this "null means
+ * there is nothing there now" rule before using them in search or
+ * reduce operations.
+ *
+ * <p>Methods accepting and/or returning Entry arguments maintain
+ * key-value associations. They may be useful for example when
+ * finding the key for the greatest value. Note that "plain" Entry
+ * arguments can be supplied using {@code new
+ * AbstractMap.SimpleEntry(k,v)}.
+ *
+ * <p>Bulk operations may complete abruptly, throwing an
+ * exception encountered in the application of a supplied
+ * function. Bear in mind when handling such exceptions that other
+ * concurrently executing functions could also have thrown
+ * exceptions, or would have done so if the first exception had
+ * not occurred.
+ *
+ * <p>Speedups for parallel compared to sequential forms are common
+ * but not guaranteed. Parallel operations involving brief functions
+ * on small maps may execute more slowly than sequential forms if the
+ * underlying work to parallelize the computation is more expensive
+ * than the computation itself. Similarly, parallelization may not
+ * lead to much actual parallelism if all processors are busy
+ * performing unrelated tasks.
+ *
+ * <p>All arguments to all task methods must be non-null.
+ *
+ * <p><em>jsr166e note: During transition, this class
+ * uses nested functional interfaces with different names but the
+ * same forms as those expected for JDK8.</em>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ */
+
+// IJ specific:
+// copied from JDK1.8 ConcurrentHashMap except:
// added hashing strategy argument
// added cacheOrGet convenience method
-// changed DEFAULT_SEGMENTS to 2 from 16
public class ConcurrentHashMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>, Serializable, TObjectHashingStrategy<K> {
private static final long serialVersionUID = 7249069246763182397L;
+ @NotNull private final TObjectHashingStrategy<K> myHashingStrategy;
+
+ /**
+ * An object for traversing and partitioning elements of a source.
+ * This interface provides a subset of the functionality of JDK8
+ * java.util.Spliterator.
+ */
+ public interface ConcurrentHashMapSpliterator<T> {
+ /**
+ * If possible, returns a new spliterator covering
+ * approximately one half of the elements, which will not be
+ * covered by this spliterator. Returns null if cannot be
+ * split.
+ */
+ ConcurrentHashMapSpliterator<T> trySplit();
+
+ /**
+ * Returns an estimate of the number of elements covered by
+ * this Spliterator.
+ */
+ long estimateSize();
- /*
- * The basic strategy is to subdivide the table among Segments,
- * each of which itself is a concurrently readable hash table.
+ /**
+ * Applies the action to each untraversed element
+ */
+ void forEachRemaining(Action<? super T> action);
+
+ /**
+ * If an element remains, applies the action and returns true.
*/
+ boolean tryAdvance(Action<? super T> action);
+ }
- /* ---------------- Constants -------------- */
+ // Sams
/**
- * The default initial number of table slots for this table.
- * Used when not otherwise specified in constructor.
+ * Interface describing a void action of one argument
*/
- static int DEFAULT_INITIAL_CAPACITY = 16;
+ public interface Action<A> {
+ void apply(A a);
+ }
/**
- * The maximum capacity, used if a higher value is implicitly
- * specified by either of the constructors with arguments. MUST
- * be a power of two <= 1<<30 to ensure that entries are indexible
- * using ints.
+ * Interface describing a void action of two arguments
*/
- static final int MAXIMUM_CAPACITY = 1 << 30;
+ public interface BiAction<A, B> {
+ void apply(A a, B b);
+ }
/**
- * The default load factor for this table. Used when not
- * otherwise specified in constructor.
+ * Interface describing a function of one argument
*/
- public static final float DEFAULT_LOAD_FACTOR = 0.75f;
+ public interface Fun<A, T> {
+ T apply(A a);
+ }
/**
- * The default number of concurrency control segments.
+ * Interface describing a function of two arguments
*/
- static final int DEFAULT_SEGMENTS = Math.min(2, Runtime.getRuntime().availableProcessors()); // CHANGED FROM 16
+ public interface BiFun<A, B, T> {
+ T apply(A a, B b);
+ }
/**
- * The maximum number of segments to allow; used to bound
- * constructor arguments.
+ * Interface describing a function mapping its argument to a double
*/
- static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
+ public interface ObjectToDouble<A> {
+ double apply(A a);
+ }
/**
- * Number of unsynchronized retries in size and containsValue
- * methods before resorting to locking. This is used to avoid
- * unbounded retries if tables undergo continuous modification
- * which would make it impossible to obtain an accurate result.
+ * Interface describing a function mapping its argument to a long
*/
- private static final int RETRIES_BEFORE_LOCK = 2;
+ public interface ObjectToLong<A> {
+ long apply(A a);
+ }
- /* ---------------- Fields -------------- */
+ /**
+ * Interface describing a function mapping its argument to an int
+ */
+ public interface ObjectToInt<A> {
+ int apply(A a);
+ }
/**
- * Mask value for indexing into segments. The upper bits of a
- * key's hash code are used to choose the segment.
+ * Interface describing a function mapping two arguments to a double
*/
- private final int segmentMask;
+ public interface ObjectByObjectToDouble<A, B> {
+ double apply(A a, B b);
+ }
/**
- * Shift value for indexing within segments.
+ * Interface describing a function mapping two arguments to a long
*/
- private final int segmentShift;
+ public interface ObjectByObjectToLong<A, B> {
+ long apply(A a, B b);
+ }
/**
- * The segments, each of which is a specialized hash table
+ * Interface describing a function mapping two arguments to an int
*/
- private final Segment[] segments;
+ public interface ObjectByObjectToInt<A, B> {
+ int apply(A a, B b);
+ }
- private transient Set<K> keySet;
- private transient Set<Entry<K, V>> entrySet;
- private transient Collection<V> values;
- private final TObjectHashingStrategy<K> myHashingStrategy;
+ /**
+ * Interface describing a function mapping two doubles to a double
+ */
+ public interface DoubleByDoubleToDouble {
+ double apply(double a, double b);
+ }
- /* ---------------- Small Utilities -------------- */
+ /**
+ * Interface describing a function mapping two longs to a long
+ */
+ public interface LongByLongToLong {
+ long apply(long a, long b);
+ }
/**
- * Returns the segment that should be used for key with given hash
- *
- * @param hash the hash code for the key
- * @return the segment
+ * Interface describing a function mapping two ints to an int
*/
- private Segment<K, V> segmentFor(int hash) {
- return segments[hash >>> segmentShift & segmentMask];
+ public interface IntByIntToInt {
+ int apply(int a, int b);
}
- /* ---------------- Inner Classes -------------- */
+ /*
+ * Overview:
+ *
+ * The primary design goal of this hash table is to maintain
+ * concurrent readability (typically method get(), but also
+ * iterators and related methods) while minimizing update
+ * contention. Secondary goals are to keep space consumption about
+ * the same or better than java.util.HashMap, and to support high
+ * initial insertion rates on an empty table by many threads.
+ *
+ * This map usually acts as a binned (bucketed) hash table. Each
+ * key-value mapping is held in a Node. Most nodes are instances
+ * of the basic Node class with hash, key, value, and next
+ * fields. However, various subclasses exist: TreeNodes are
+ * arranged in balanced trees, not lists. TreeBins hold the roots
+ * of sets of TreeNodes. ForwardingNodes are placed at the heads
+ * of bins during resizing. ReservationNodes are used as
+ * placeholders while establishing values in computeIfAbsent and
+ * related methods. The types TreeBin, ForwardingNode, and
+ * ReservationNode do not hold normal user keys, values, or
+ * hashes, and are readily distinguishable during search etc
+ * because they have negative hash fields and null key and value
+ * fields. (These special nodes are either uncommon or transient,
+ * so the impact of carrying around some unused fields is
+ * insignificant.)
+ *
+ * The table is lazily initialized to a power-of-two size upon the
+ * first insertion. Each bin in the table normally contains a
+ * list of Nodes (most often, the list has only zero or one Node).
+ * Table accesses require volatile/atomic reads, writes, and
+ * CASes. Because there is no other way to arrange this without
+ * adding further indirections, we use intrinsics
+ * (sun.misc.Unsafe) operations.
+ *
+ * We use the top (sign) bit of Node hash fields for control
+ * purposes -- it is available anyway because of addressing
+ * constraints. Nodes with negative hash fields are specially
+ * handled or ignored in map methods.
+ *
+ * Insertion (via put or its variants) of the first node in an
+ * empty bin is performed by just CASing it to the bin. This is
+ * by far the most common case for put operations under most
+ * key/hash distributions. Other update operations (insert,
+ * delete, and replace) require locks. We do not want to waste
+ * the space required to associate a distinct lock object with
+ * each bin, so instead use the first node of a bin list itself as
+ * a lock. Locking support for these locks relies on builtin
+ * "synchronized" monitors.
+ *
+ * Using the first node of a list as a lock does not by itself
+ * suffice though: When a node is locked, any update must first
+ * validate that it is still the first node after locking it, and
+ * retry if not. Because new nodes are always appended to lists,
+ * once a node is first in a bin, it remains first until deleted
+ * or the bin becomes invalidated (upon resizing).
+ *
+ * The main disadvantage of per-bin locks is that other update
+ * operations on other nodes in a bin list protected by the same
+ * lock can stall, for example when user equals() or mapping
+ * functions take a long time. However, statistically, under
+ * random hash codes, this is not a common problem. Ideally, the
+ * frequency of nodes in bins follows a Poisson distribution
+ * (http://en.wikipedia.org/wiki/Poisson_distribution) with a
+ * parameter of about 0.5 on average, given the resizing threshold
+ * of 0.75, although with a large variance because of resizing
+ * granularity. Ignoring variance, the expected occurrences of
+ * list size k are (exp(-0.5) * pow(0.5, k) / factorial(k)). The
+ * first values are:
+ *
+ * 0: 0.60653066
+ * 1: 0.30326533
+ * 2: 0.07581633
+ * 3: 0.01263606
+ * 4: 0.00157952
+ * 5: 0.00015795
+ * 6: 0.00001316
+ * 7: 0.00000094
+ * 8: 0.00000006
+ * more: less than 1 in ten million
+ *
+ * Lock contention probability for two threads accessing distinct
+ * elements is roughly 1 / (8 * #elements) under random hashes.
+ *
+ * Actual hash code distributions encountered in practice
+ * sometimes deviate significantly from uniform randomness. This
+ * includes the case when N > (1<<30), so some keys MUST collide.
+ * Similarly for dumb or hostile usages in which multiple keys are
+ * designed to have identical hash codes or ones that differs only
+ * in masked-out high bits. So we use a secondary strategy that
+ * applies when the number of nodes in a bin exceeds a
+ * threshold. These TreeBins use a balanced tree to hold nodes (a
+ * specialized form of red-black trees), bounding search time to
+ * O(log N). Each search step in a TreeBin is at least twice as
+ * slow as in a regular list, but given that N cannot exceed
+ * (1<<64) (before running out of addresses) this bounds search
+ * steps, lock hold times, etc, to reasonable constants (roughly
+ * 100 nodes inspected per operation worst case) so long as keys
+ * are Comparable (which is very common -- String, Long, etc).
+ * TreeBin nodes (TreeNodes) also maintain the same "next"
+ * traversal pointers as regular nodes, so can be traversed in
+ * iterators in the same way.
+ *
+ * The table is resized when occupancy exceeds a percentage
+ * threshold (nominally, 0.75, but see below). Any thread
+ * noticing an overfull bin may assist in resizing after the
+ * initiating thread allocates and sets up the replacement
+ * array. However, rather than stalling, these other threads may
+ * proceed with insertions etc. The use of TreeBins shields us
+ * from the worst case effects of overfilling while resizes are in
+ * progress. Resizing proceeds by transferring bins, one by one,
+ * from the table to the next table. To enable concurrency, the
+ * next table must be (incrementally) prefilled with place-holders
+ * serving as reverse forwarders to the old table. Because we are
+ * using power-of-two expansion, the elements from each bin must
+ * either stay at same index, or move with a power of two
+ * offset. We eliminate unnecessary node creation by catching
+ * cases where old nodes can be reused because their next fields
+ * won't change. On average, only about one-sixth of them need
+ * cloning when a table doubles. The nodes they replace will be
+ * garbage collectable as soon as they are no longer referenced by
+ * any reader thread that may be in the midst of concurrently
+ * traversing table. Upon transfer, the old table bin contains
+ * only a special forwarding node (with hash field "MOVED") that
+ * contains the next table as its key. On encountering a
+ * forwarding node, access and update operations restart, using
+ * the new table.
+ *
+ * Each bin transfer requires its bin lock, which can stall
+ * waiting for locks while resizing. However, because other
+ * threads can join in and help resize rather than contend for
+ * locks, average aggregate waits become shorter as resizing
+ * progresses. The transfer operation must also ensure that all
+ * accessible bins in both the old and new table are usable by any
+ * traversal. This is arranged by proceeding from the last bin
+ * (table.length - 1) up towards the first. Upon seeing a
+ * forwarding node, traversals (see class Traverser) arrange to
+ * move to the new table without revisiting nodes. However, to
+ * ensure that no intervening nodes are skipped, bin splitting can
+ * only begin after the associated reverse-forwarders are in
+ * place.
+ *
+ * The traversal scheme also applies to partial traversals of
+ * ranges of bins (via an alternate Traverser constructor)
+ * to support partitioned aggregate operations. Also, read-only
+ * operations give up if ever forwarded to a null table, which
+ * provides support for shutdown-style clearing, which is also not
+ * currently implemented.
+ *
+ * Lazy table initialization minimizes footprint until first use,
+ * and also avoids resizings when the first operation is from a
+ * putAll, constructor with map argument, or deserialization.
+ * These cases attempt to override the initial capacity settings,
+ * but harmlessly fail to take effect in cases of races.
+ *
+ * The element count is maintained using a specialization of
+ * LongAdder. We need to incorporate a specialization rather than
+ * just use a LongAdder in order to access implicit
+ * contention-sensing that leads to creation of multiple
+ * CounterCells. The counter mechanics avoid contention on
+ * updates but can encounter cache thrashing if read too
+ * frequently during concurrent access. To avoid reading so often,
+ * resizing under contention is attempted only upon adding to a
+ * bin already holding two or more nodes. Under uniform hash
+ * distributions, the probability of this occurring at threshold
+ * is around 13%, meaning that only about 1 in 8 puts check
+ * threshold (and after resizing, many fewer do so).
+ *
+ * TreeBins use a special form of comparison for search and
+ * related operations (which is the main reason we cannot use
+ * existing collections such as TreeMaps). TreeBins contain
+ * Comparable elements, but may contain others, as well as
+ * elements that are Comparable but not necessarily Comparable for
+ * the same T, so we cannot invoke compareTo among them. To handle
+ * this, the tree is ordered primarily by hash value, then by
+ * Comparable.compareTo order if applicable. On lookup at a node,
+ * if elements are not comparable or compare as 0 then both left
+ * and right children may need to be searched in the case of tied
+ * hash values. (This corresponds to the full list search that
+ * would be necessary if all elements were non-Comparable and had
+ * tied hashes.) On insertion, to keep a total ordering (or as
+ * close as is required here) across rebalancings, we compare
+ * classes and identityHashCodes as tie-breakers. The red-black
+ * balancing code is updated from pre-jdk-collections
+ * (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java)
+ * based in turn on Cormen, Leiserson, and Rivest "Introduction to
+ * Algorithms" (CLR).
+ *
+ * TreeBins also require an additional locking mechanism. While
+ * list traversal is always possible by readers even during
+ * updates, tree traversal is not, mainly because of tree-rotations
+ * that may change the root node and/or its linkages. TreeBins
+ * include a simple read-write lock mechanism parasitic on the
+ * main bin-synchronization strategy: Structural adjustments
+ * associated with an insertion or removal are already bin-locked
+ * (and so cannot conflict with other writers) but must wait for
+ * ongoing readers to finish. Since there can be only one such
+ * waiter, we use a simple scheme using a single "waiter" field to
+ * block writers. However, readers need never block. If the root
+ * lock is held, they proceed along the slow traversal path (via
+ * next-pointers) until the lock becomes available or the list is
+ * exhausted, whichever comes first. These cases are not fast, but
+ * maximize aggregate expected throughput.
+ *
+ * Maintaining API and serialization compatibility with previous
+ * versions of this class introduces several oddities. Mainly: We
+ * leave untouched but unused constructor arguments refering to
+ * concurrencyLevel. We accept a loadFactor constructor argument,
+ * but apply it only to initial table capacity (which is the only
+ * time that we can guarantee to honor it.) We also declare an
+ * unused "Segment" class that is instantiated in minimal form
+ * only when serializing.
+ *
+ * Also, solely for compatibility with previous versions of this
+ * class, it extends AbstractMap, even though all of its methods
+ * are overridden, so it is just useless baggage.
+ *
+ * This file is organized to make things a little easier to follow
+ * while reading than they might otherwise: First the main static
+ * declarations and utilities, then fields, then main public
+ * methods (with a few factorings of multiple public methods into
+ * internal ones), then sizing methods, trees, traversers, and
+ * bulk operations.
+ */
+
+ /* ---------------- Constants -------------- */
/**
- * ConcurrentHashMap list entry. Note that this is never exported
- * out as a user-visible Map.Entry.
- * <p/>
- * Because the value field is volatile, not final, it is legal wrt
- * the Java Memory Model for an unsynchronized reader to see null
- * instead of initial value when read via a data race. Although a
- * reordering leading to this is not likely to ever actually
- * occur, the Segment.readValueUnderLock method is used as a
- * backup in case a null (pre-initialized) value is ever seen in
- * an unsynchronized access method.
- */
- private static final class HashEntry<K, V> {
- private final K key;
- private final int hash;
- private volatile V value;
- private final HashEntry<K, V> next;
-
- private HashEntry(K key, int hash, HashEntry<K, V> next, V value) {
- this.key = key;
+ * The largest possible table capacity. This value must be
+ * exactly 1<<30 to stay within Java array allocation and indexing
+ * bounds for power of two table sizes, and is further required
+ * because the top two bits of 32bit hash fields are used for
+ * control purposes.
+ */
+ private static final int MAXIMUM_CAPACITY = 1 << 30;
+
+ /**
+ * The default initial table capacity. Must be a power of 2
+ * (i.e., at least 1) and at most MAXIMUM_CAPACITY.
+ */
+ static final int DEFAULT_CAPACITY = 16;
+
+ /**
+ * The largest possible (non-power of two) array size.
+ * Needed by toArray and related methods.
+ */
+ static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+ /**
+ * The default concurrency level for this table. Unused but
+ * defined for compatibility with previous versions of this class.
+ */
+ private static final int DEFAULT_CONCURRENCY_LEVEL = 16;
+
+ /**
+ * The load factor for this table. Overrides of this value in
+ * constructors affect only the initial table capacity. The
+ * actual floating point value isn't normally used -- it is
+ * simpler to use expressions such as {@code n - (n >>> 2)} for
+ * the associated resizing threshold.
+ */
+ static final float LOAD_FACTOR = 0.75f;
+
+ /**
+ * The bin count threshold for using a tree rather than list for a
+ * bin. Bins are converted to trees when adding an element to a
+ * bin with at least this many nodes. The value must be greater
+ * than 2, and should be at least 8 to mesh with assumptions in
+ * tree removal about conversion back to plain bins upon
+ * shrinkage.
+ */
+ static final int TREEIFY_THRESHOLD = 8;
+
+ /**
+ * The bin count threshold for untreeifying a (split) bin during a
+ * resize operation. Should be less than TREEIFY_THRESHOLD, and at
+ * most 6 to mesh with shrinkage detection under removal.
+ */
+ static final int UNTREEIFY_THRESHOLD = 6;
+
+ /**
+ * The smallest table capacity for which bins may be treeified.
+ * (Otherwise the table is resized if too many nodes in a bin.)
+ * The value should be at least 4 * TREEIFY_THRESHOLD to avoid
+ * conflicts between resizing and treeification thresholds.
+ */
+ static final int MIN_TREEIFY_CAPACITY = 64;
+
+ /**
+ * Minimum number of rebinnings per transfer step. Ranges are
+ * subdivided to allow multiple resizer threads. This value
+ * serves as a lower bound to avoid resizers encountering
+ * excessive memory contention. The value should be at least
+ * DEFAULT_CAPACITY.
+ */
+ private static final int MIN_TRANSFER_STRIDE = 16;
+
+ /*
+ * Encodings for Node hash fields. See above for explanation.
+ */
+ static final int MOVED = -1; // hash for forwarding nodes
+ static final int TREEBIN = -2; // hash for roots of trees
+ static final int RESERVED = -3; // hash for transient reservations
+ static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash
+
+ /**
+ * Number of CPUS, to place bounds on some sizings
+ */
+ static final int NCPU = Runtime.getRuntime().availableProcessors();
+
+ /**
+ * For serialization compatibility.
+ */
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("segments", Segment[].class),
+ new ObjectStreamField("segmentMask", Integer.TYPE),
+ new ObjectStreamField("segmentShift", Integer.TYPE)
+ };
+
+ /* ---------------- Nodes -------------- */
+
+ /**
+ * Key-value entry. This class is never exported out as a
+ * user-mutable Map.Entry (i.e., one supporting setValue; see
+ * MapEntry below), but can be used for read-only traversals used
+ * in bulk tasks. Subclasses of Node with a negative hash field
+ * are special, and contain null keys and values (but are never
+ * exported). Otherwise, keys and vals are never null.
+ */
+ static class Node<K, V> implements Map.Entry<K, V> {
+ final int hash;
+ final K key;
+ volatile V val;
+ volatile Node<K, V> next;
+ protected final TObjectHashingStrategy<K> myHashingStrategy;
+
+ Node(int hash, K key, V val, Node<K, V> next, @NotNull TObjectHashingStrategy<K> hashingStrategy) {
this.hash = hash;
+ this.key = key;
+ this.val = val;
this.next = next;
- this.value = value;
+ myHashingStrategy = hashingStrategy;
}
- }
- /**
- * Segments are specialized versions of hash tables. This
- * subclasses from ReentrantLock opportunistically, just to
- * simplify some locking and avoid separate construction.
- */
- private static final class Segment<K, V> extends ReentrantLock implements Serializable {
- /*
- * Segments maintain a table of entry lists that are ALWAYS
- * kept in a consistent state, so can be read without locking.
- * Next fields of nodes are immutable (final). All list
- * additions are performed at the front of each bin. This
- * makes it easy to check changes, and also fast to traverse.
- * When nodes would otherwise be changed, new nodes are
- * created to replace them. This works well for hash tables
- * since the bin lists tend to be short. (The average length
- * is less than two for the default load factor threshold.)
- *
- * Read operations can thus proceed without locking, but rely
- * on selected uses of volatiles to ensure that completed
- * write operations performed by other threads are
- * noticed. For most purposes, the "count" field, tracking the
- * number of elements, serves as that volatile variable
- * ensuring visibility. This is convenient because this field
- * needs to be read in many read operations anyway:
- *
- * - All (unsynchronized) read operations must first read the
- * "count" field, and should not look at table entries if
- * it is 0.
- *
- * - All (synchronized) write operations should write to
- * the "count" field after structurally changing any bin.
- * The operations must not take any action that could even
- * momentarily cause a concurrent read operation to see
- * inconsistent data. This is made easier by the nature of
- * the read operations in Map. For example, no operation
- * can reveal that the table has grown but the threshold
- * has not yet been updated, so there are no atomicity
- * requirements for this with respect to reads.
- *
- * As a guide, all critical volatile reads and writes to the
- * count field are marked in code comments.
- */
+ @Override
+ public final K getKey() {
+ return key;
+ }
- private static final long serialVersionUID = 2249069246763182397L;
+ @Override
+ public final V getValue() {
+ return val;
+ }
- /**
- * The number of elements in this segment's region.
- */
- private transient volatile int count;
+ public final int hashCode() {
+ return key.hashCode() ^ val.hashCode();
+ }
- /**
- * Number of updates that alter the size of the table. This is
- * used during bulk-read methods to make sure they see a
- * consistent snapshot: If modCounts change during a traversal
- * of segments computing size or checking containsValue, then
- * we might have an inconsistent view of state so (usually)
- * must retry.
- */
- private transient int modCount;
+ public final String toString() {
+ return key + "=" + val;
+ }
- /**
- * The table is rehashed when its size exceeds this threshold.
- * (The value of this field is always (int)(capacity *
- * loadFactor).)
- */
- private transient int threshold;
+ @Override
+ public final V setValue(V value) {
+ throw new UnsupportedOperationException();
+ }
- /**
- * The per-segment table. Declared as a raw type, casted
- * to HashEntry<K,V> on each use.
- */
- private transient volatile HashEntry[] table;
+ public final boolean equals(Object o) {
+ Object k;
+ Object v;
+ Object u;
+ Map.Entry<?, ?> e;
+ return o instanceof Entry &&
+ (k = (e = (Entry<?, ?>)o).getKey()) != null &&
+ (v = e.getValue()) != null &&
+ (k == key || myHashingStrategy.equals((K)k, key)) &&
+ (v == (u = val) || v.equals(u));
+ }
/**
- * The load factor for the hash table. Even though this value
- * is same for all segments, it is replicated to avoid needing
- * links to outer object.
- *
- * @serial
+ * Virtualized support for map.get(); overridden in subclasses.
*/
- private final float loadFactor;
- private final TObjectHashingStrategy<K> myHashingStrategy;
+ Node<K, V> find(int h, Object k) {
+ Node<K, V> e = this;
+ if (k != null) {
+ do {
+ K ek;
+ if (e.hash == h &&
+ ((ek = e.key) == k || ek != null && myHashingStrategy.equals((K)k,ek))) {
+ return e;
+ }
+ }
+ while ((e = e.next) != null);
+ }
+ return null;
+ }
+ }
- private Segment(int initialCapacity, float lf, TObjectHashingStrategy<K> hashingStrategy) {
- loadFactor = lf;
- myHashingStrategy = hashingStrategy;
- setTable(new HashEntry[initialCapacity]);
+ /* ---------------- Static utilities -------------- */
+
+ /**
+ * Spreads (XORs) higher bits of hash to lower and also forces top
+ * bit to 0. Because the table uses power-of-two masking, sets of
+ * hashes that vary only in bits above the current mask will
+ * always collide. (Among known examples are sets of Float keys
+ * holding consecutive whole numbers in small tables.) So we
+ * apply a transform that spreads the impact of higher bits
+ * downward. There is a tradeoff between speed, utility, and
+ * quality of bit-spreading. Because many common sets of hashes
+ * are already reasonably distributed (so don't benefit from
+ * spreading), and because we use trees to handle large sets of
+ * collisions in bins, we just XOR some shifted bits in the
+ * cheapest possible way to reduce systematic lossage, as well as
+ * to incorporate impact of the highest bits that would otherwise
+ * never be used in index calculations because of table bounds.
+ */
+ static int spread(int h) {
+ return (h ^ h >>> 16) & HASH_BITS;
+ }
+
+ /**
+ * Returns a power of two table size for the given desired capacity.
+ * See Hackers Delight, sec 3.2
+ */
+ private static int tableSizeFor(int c) {
+ int n = c - 1;
+ n |= n >>> 1;
+ n |= n >>> 2;
+ n |= n >>> 4;
+ n |= n >>> 8;
+ n |= n >>> 16;
+ return n < 0 ? 1 : n >= MAXIMUM_CAPACITY ? MAXIMUM_CAPACITY : n + 1;
+ }
+
+ /**
+ * Returns x's Class if it is of the form "class C implements
+ * Comparable<C>", else null.
+ */
+ static Class<?> comparableClassFor(Object x) {
+ if (x instanceof Comparable) {
+ Class<?> c;
+ if ((c = x.getClass()) == String.class) // bypass checks
+ {
+ return c;
+ }
+ Type[] ts;
+ if ((ts = c.getGenericInterfaces()) != null) {
+ for (Type t : ts) {
+ ParameterizedType p;
+ Type[] as;
+ if (t instanceof ParameterizedType &&
+ (p = (ParameterizedType)t).getRawType() ==
+ Comparable.class &&
+ (as = p.getActualTypeArguments()) != null &&
+ as.length == 1 && as[0] == c) // type arg is c
+ {
+ return c;
+ }
+ }
+ }
}
+ return null;
+ }
- /**
- * Set table to new HashEntry array.
- * Call only while holding lock or in constructor.
- */
- private void setTable(HashEntry[] newTable) {
- threshold = (int)(newTable.length * loadFactor);
- table = newTable;
+ /**
+ * Returns k.compareTo(x) if x matches kc (k's screened comparable
+ * class), else 0.
+ */
+ @SuppressWarnings({"rawtypes", "unchecked"}) // for cast to Comparable
+ static int compareComparables(Class<?> kc, Object k, Object x) {
+ return x == null || x.getClass() != kc ? 0 :
+ ((Comparable)k).compareTo(x);
+ }
+
+ /* ---------------- Table element access -------------- */
+
+ /*
+ * Volatile access methods are used for table elements as well as
+ * elements of in-progress next table while resizing. All uses of
+ * the tab arguments must be null checked by callers. All callers
+ * also paranoically precheck that tab's length is not zero (or an
+ * equivalent check), thus ensuring that any index argument taking
+ * the form of a hash value anded with (length - 1) is a valid
+ * index. Note that, to be correct wrt arbitrary concurrency
+ * errors by users, these checks must operate on local variables,
+ * which accounts for some odd-looking inline assignments below.
+ * Note that calls to setTabAt always occur within locked regions,
+ * and so in principle require only release ordering, not need
+ * full volatile semantics, but are currently coded as volatile
+ * writes to be conservative.
+ */
+
+ @SuppressWarnings("unchecked")
+ static <K, V> Node<K, V> tabAt(Node<K, V>[] tab, int i) {
+ return (Node<K, V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
+ }
+
+ static <K, V> boolean casTabAt(Node<K, V>[] tab, int i,
+ Node<K, V> c, Node<K, V> v) {
+ return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
+ }
+
+ static <K, V> void setTabAt(Node<K, V>[] tab, int i, Node<K, V> v) {
+ U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
+ }
+
+ /* ---------------- Fields -------------- */
+
+ /**
+ * The array of bins. Lazily initialized upon first insertion.
+ * Size is always a power of two. Accessed directly by iterators.
+ */
+ transient volatile Node<K, V>[] table;
+
+ /**
+ * The next table to use; non-null only while resizing.
+ */
+ private transient volatile Node<K, V>[] nextTable;
+
+ /**
+ * Base counter value, used mainly when there is no contention,
+ * but also as a fallback during table initialization
+ * races. Updated via CAS.
+ */
+ private transient volatile long baseCount;
+
+ /**
+ * Table initialization and resizing control. When negative, the
+ * table is being initialized or resized: -1 for initialization,
+ * else -(1 + the number of active resizing threads). Otherwise,
+ * when table is null, holds the initial table size to use upon
+ * creation, or 0 for default. After initialization, holds the
+ * next element count value upon which to resize the table.
+ */
+ private transient volatile int sizeCtl;
+
+ /**
+ * The next table index (plus one) to split while resizing.
+ */
+ private transient volatile int transferIndex;
+
+ /**
+ * The least available table index to split while resizing.
+ */
+ private transient volatile int transferOrigin;
+
+ /**
+ * Spinlock (locked via CAS) used when resizing and/or creating CounterCells.
+ */
+ private transient volatile int cellsBusy;
+
+ /**
+ * Table of counter cells. When non-null, size is a power of 2.
+ */
+ private transient volatile CounterCell[] counterCells;
+
+ // views
+ private transient KeySetView<K, V> keySet;
+ private transient ValuesView<K, V> values;
+ private transient EntrySetView<K, V> entrySet;
+
+
+ /* ---------------- Public operations -------------- */
+
+ /**
+ * Creates a new, empty map with the default initial table size (16).
+ */
+ public ConcurrentHashMap() {
+ myHashingStrategy = this;
+ }
+
+ public ConcurrentHashMap(@NotNull TObjectHashingStrategy<K> hashingStrategy) {
+ myHashingStrategy = hashingStrategy;
+ }
+
+ /**
+ * Creates a new, empty map with an initial table size
+ * accommodating the specified number of elements without the need
+ * to dynamically resize.
+ *
+ * @param initialCapacity The implementation performs internal
+ * sizing to accommodate this many elements.
+ * @throws IllegalArgumentException if the initial capacity of
+ * elements is negative
+ */
+ public ConcurrentHashMap(int initialCapacity) {
+ if (initialCapacity < 0) {
+ throw new IllegalArgumentException();
}
+ int cap = initialCapacity >= MAXIMUM_CAPACITY >>> 1 ?
+ MAXIMUM_CAPACITY :
+ tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1);
+ sizeCtl = cap;
+ myHashingStrategy = this;
+ }
- /**
- * Return properly casted first entry of bin for given hash
- */
- private HashEntry<K, V> getFirst(int hash) {
- HashEntry[] tab = table;
- return (HashEntry<K, V>)tab[hash & tab.length - 1];
+ /**
+ * Creates a new map with the same mappings as the given map.
+ *
+ * @param m the map
+ */
+ public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
+ sizeCtl = DEFAULT_CAPACITY;
+ myHashingStrategy = this;
+ putAll(m);
+ }
+
+ /**
+ * Creates a new, empty map with an initial table size based on
+ * the given number of elements ({@code initialCapacity}) and
+ * initial table density ({@code loadFactor}).
+ *
+ * @param initialCapacity the initial capacity. The implementation
+ * performs internal sizing to accommodate this many elements,
+ * given the specified load factor.
+ * @param loadFactor the load factor (table density) for
+ * establishing the initial table size
+ * @throws IllegalArgumentException if the initial capacity of
+ * elements is negative or the load factor is nonpositive
+ * @since 1.6
+ */
+ public ConcurrentHashMap(int initialCapacity, float loadFactor) {
+ this(initialCapacity, loadFactor, 1);
+ }
+
+ /**
+ * Creates a new, empty map with an initial table size based on
+ * the given number of elements ({@code initialCapacity}), table
+ * density ({@code loadFactor}), and number of concurrently
+ * updating threads ({@code concurrencyLevel}).
+ *
+ * @param initialCapacity the initial capacity. The implementation
+ * performs internal sizing to accommodate this many elements,
+ * given the specified load factor.
+ * @param loadFactor the load factor (table density) for
+ * establishing the initial table size
+ * @param concurrencyLevel the estimated number of concurrently
+ * updating threads. The implementation may use this value as
+ * a sizing hint.
+ * @throws IllegalArgumentException if the initial capacity is
+ * negative or the load factor or concurrencyLevel are
+ * nonpositive
+ */
+ public ConcurrentHashMap(int initialCapacity,
+ float loadFactor, int concurrencyLevel) {
+ this(initialCapacity, loadFactor, concurrencyLevel, THIS);
+ }
+ private static final TObjectHashingStrategy THIS = new TObjectHashingStrategy() {
+ @Override
+ public int computeHashCode(Object object) {
+ throw new IncorrectOperationException();
}
- /**
- * Read value field of an entry under lock. Called if value
- * field ever appears to be null. This is possible only if a
- * compiler happens to reorder a HashEntry initialization with
- * its table assignment, which is legal under memory model
- * but is not known to ever occur.
- */
- private V readValueUnderLock(HashEntry<K, V> e) {
- lock();
- try {
- return e.value;
+ @Override
+ public boolean equals(Object o1, Object o2) {
+ throw new IncorrectOperationException();
+ }
+ };
+ public ConcurrentHashMap(int initialCapacity,
+ float loadFactor, int concurrencyLevel, @NotNull TObjectHashingStrategy<K> hashingStrategy) {
+ myHashingStrategy = hashingStrategy == THIS ? this : hashingStrategy;
+ if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0) {
+ throw new IllegalArgumentException();
+ }
+ if (initialCapacity < concurrencyLevel) // Use at least as many bins
+ {
+ initialCapacity = concurrencyLevel; // as estimated threads
+ }
+ long size = (long)(1.0 + (long)initialCapacity / loadFactor);
+ int cap = size >= (long)MAXIMUM_CAPACITY ?
+ MAXIMUM_CAPACITY : tableSizeFor((int)size);
+ sizeCtl = cap;
+ }
+
+ // Original (since JDK1.2) Map methods
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int size() {
+ long n = sumCount();
+ return n < 0L ? 0 :
+ n > (long)Integer.MAX_VALUE ? Integer.MAX_VALUE :
+ (int)n;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isEmpty() {
+ return sumCount() <= 0L; // ignore transient negative values
+ }
+
+ /**
+ * Returns the value to which the specified key is mapped,
+ * or {@code null} if this map contains no mapping for the key.
+ * <p/>
+ * <p>More formally, if this map contains a mapping from a key
+ * {@code k} to a value {@code v} such that {@code key.equals(k)},
+ * then this method returns {@code v}; otherwise it returns
+ * {@code null}. (There can be at most one such mapping.)
+ *
+ * @throws NullPointerException if the specified key is null
+ */
+ @Override
+ public V get(Object key) {
+ Node<K, V>[] tab;
+ Node<K, V> e;
+ int n;
+ int h = hash((K)key);
+ if ((tab = table) != null && (n = tab.length) > 0 &&
+ (e = tabAt(tab, n - 1 & h)) != null) {
+ int eh;
+ K ek;
+ if ((eh = e.hash) == h) {
+ if ((ek = e.key) == key || ek != null && myHashingStrategy.equals((K)key,ek)) {
+ return e.val;
+ }
}
- finally {
- unlock();
+ else if (eh < 0) {
+ Node<K, V> p;
+ return (p = e.find(h, key)) != null ? p.val : null;
+ }
+ while ((e = e.next) != null) {
+ if (e.hash == h &&
+ ((ek = e.key) == key || ek != null && myHashingStrategy.equals((K)key,ek))) {
+ return e.val;
+ }
}
}
+ return null;
+ }
+
+ /**
+ * Tests if the specified object is a key in this table.
+ *
+ * @param key possible key
+ * @return {@code true} if and only if the specified object
+ * is a key in this table, as determined by the
+ * {@code equals} method; {@code false} otherwise
+ * @throws NullPointerException if the specified key is null
+ */
+ @Override
+ public boolean containsKey(Object key) {
+ return get(key) != null;
+ }
- /* Specialized implementations of map methods */
+ /**
+ * Returns {@code true} if this map maps one or more keys to the
+ * specified value. Note: This method may require a full traversal
+ * of the map, and is much slower than method {@code containsKey}.
+ *
+ * @param value value whose presence in this map is to be tested
+ * @return {@code true} if this map maps one or more keys to the
+ * specified value
+ * @throws NullPointerException if the specified value is null
+ */
+ @Override
+ public boolean containsValue(Object value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ Node<K, V>[] t;
+ if ((t = table) != null) {
+ Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
+ for (Node<K, V> p; (p = it.advance()) != null; ) {
+ V v;
+ if ((v = p.val) == value || v != null && value.equals(v)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Maps the specified key to the specified value in this table.
+ * Neither the key nor the value can be null.
+ * <p/>
+ * <p>The value can be retrieved by calling the {@code get} method
+ * with a key that is equal to the original key.
+ *
+ * @param key key with which the specified value is to be associated
+ * @param value value to be associated with the specified key
+ * @return the previous value associated with {@code key}, or
+ * {@code null} if there was no mapping for {@code key}
+ * @throws NullPointerException if the specified key or value is null
+ */
+ @Override
+ public V put(K key, V value) {
+ return putVal(key, value, false);
+ }
- private V get(K key, int hash) {
- if (count != 0) { // read-volatile
- HashEntry<K, V> e = getFirst(hash);
- while (e != null) {
- if (e.hash == hash && myHashingStrategy.equals(key, e.key)) {
- V v = e.value;
- if (v != null) {
- return v;
+ /**
+ * Implementation for put and putIfAbsent
+ */
+ final V putVal(K key, V value, boolean onlyIfAbsent) {
+ if (key == null || value == null) throw new NullPointerException();
+ int hash = hash(key);
+ int binCount = 0;
+ for (Node<K, V>[] tab = table; ; ) {
+ Node<K, V> f;
+ int n;
+ int i;
+ int fh;
+ if (tab == null || (n = tab.length) == 0) {
+ tab = initTable();
+ }
+ else if ((f = tabAt(tab, i = n - 1 & hash)) == null) {
+ if (casTabAt(tab, i, null,
+ new Node<K, V>(hash, key, value, null,myHashingStrategy))) {
+ break; // no lock when adding to empty bin
+ }
+ }
+ else if ((fh = f.hash) == MOVED) {
+ tab = helpTransfer(tab, f);
+ }
+ else {
+ V oldVal = null;
+ synchronized (f) {
+ if (tabAt(tab, i) == f) {
+ if (fh >= 0) {
+ binCount = 1;
+ for (Node<K, V> e = f; ; ++binCount) {
+ K ek;
+ if (e.hash == hash &&
+ ((ek = e.key) == key ||
+ ek != null && myHashingStrategy.equals(key,ek))) {
+ oldVal = e.val;
+ if (!onlyIfAbsent) {
+ e.val = value;
+ }
+ break;
+ }
+ Node<K, V> pred = e;
+ if ((e = e.next) == null) {
+ pred.next = new Node<K, V>(hash, key,
+ value, null,myHashingStrategy);
+ break;
+ }
+ }
+ }
+ else if (f instanceof TreeBin) {
+ binCount = 2;
+ Node<K, V> p;
+ if ((p = ((TreeBin<K, V>)f).putTreeVal(hash, key,
+ value)) != null) {
+ oldVal = p.val;
+ if (!onlyIfAbsent) {
+ p.val = value;
+ }
+ }
}
- return readValueUnderLock(e); // recheck
}
- e = e.next;
+ }
+ if (binCount != 0) {
+ if (binCount >= TREEIFY_THRESHOLD) {
+ treeifyBin(tab, i);
+ }
+ if (oldVal != null) {
+ return oldVal;
+ }
+ break;
}
}
- return null;
}
+ addCount(1L, binCount);
+ return null;
+ }
- private boolean containsKey(K key, int hash) {
- if (count != 0) { // read-volatile
- HashEntry<K, V> e = getFirst(hash);
- while (e != null) {
- if (e.hash == hash && myHashingStrategy.equals(key, e.key)) {
- return true;
+ /**
+ * Copies all of the mappings from the specified map to this one.
+ * These mappings replace any mappings that this map had for any of the
+ * keys currently in the specified map.
+ *
+ * @param m mappings to be stored in this map
+ */
+ @Override
+ public void putAll(@NotNull Map<? extends K, ? extends V> m) {
+ tryPresize(m.size());
+ for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
+ putVal(e.getKey(), e.getValue(), false);
+ }
+ }
+
+ /**
+ * Removes the key (and its corresponding value) from this map.
+ * This method does nothing if the key is not in the map.
+ *
+ * @param key the key that needs to be removed
+ * @return the previous value associated with {@code key}, or
+ * {@code null} if there was no mapping for {@code key}
+ * @throws NullPointerException if the specified key is null
+ */
+ @Override
+ public V remove(Object key) {
+ return replaceNode(key, null, null);
+ }
+
+ /**
+ * Implementation for the four public remove/replace methods:
+ * Replaces node value with v, conditional upon match of cv if
+ * non-null. If resulting value is null, delete.
+ */
+ final V replaceNode(Object key, V value, Object cv) {
+ int hash = hash((K)key);
+ for (Node<K, V>[] tab = table; ; ) {
+ Node<K, V> f;
+ int n;
+ int i;
+ int fh;
+ if (tab == null || (n = tab.length) == 0 ||
+ (f = tabAt(tab, i = n - 1 & hash)) == null) {
+ break;
+ }
+ else if ((fh = f.hash) == MOVED) {
+ tab = helpTransfer(tab, f);
+ }
+ else {
+ V oldVal = null;
+ boolean validated = false;
+ synchronized (f) {
+ if (tabAt(tab, i) == f) {
+ if (fh >= 0) {
+ validated = true;
+ for (Node<K, V> e = f, pred = null; ; ) {
+ K ek;
+ if (e.hash == hash &&
+ ((ek = e.key) == key ||
+ ek != null && myHashingStrategy.equals((K)key,ek))) {
+ V ev = e.val;
+ if (cv == null || cv == ev ||
+ ev != null && cv.equals(ev)) {
+ oldVal = ev;
+ if (value != null) {
+ e.val = value;
+ }
+ else if (pred != null) {
+ pred.next = e.next;
+ }
+ else {
+ setTabAt(tab, i, e.next);
+ }
+ }
+ break;
+ }
+ pred = e;
+ if ((e = e.next) == null) {
+ break;
+ }
+ }
+ }
+ else if (f instanceof TreeBin) {
+ validated = true;
+ TreeBin<K, V> t = (TreeBin<K, V>)f;
+ TreeNode<K, V> r;
+ TreeNode<K, V> p;
+ if ((r = t.root) != null &&
+ (p = r.findTreeNode(hash, key, null)) != null) {
+ V pv = p.val;
+ if (cv == null || cv == pv ||
+ pv != null && cv.equals(pv)) {
+ oldVal = pv;
+ if (value != null) {
+ p.val = value;
+ }
+ else if (t.removeTreeNode(p)) {
+ setTabAt(tab, i, untreeify(t.first));
+ }
+ }
+ }
+ }
}
- e = e.next;
+ }
+ if (validated) {
+ if (oldVal != null) {
+ if (value == null) {
+ addCount(-1L, -1);
+ }
+ return oldVal;
+ }
+ break;
}
}
- return false;
}
+ return null;
+ }
- private boolean containsValue(Object value) {
- if (count != 0) { // read-volatile
- HashEntry[] tab = table;
- for (HashEntry tabEntry : tab) {
- for (HashEntry<K, V> e = (HashEntry<K, V>)tabEntry;
- e != null;
- e = e.next) {
- V v = e.value;
- if (v == null) // recheck
- {
- v = readValueUnderLock(e);
- }
- if (value.equals(v)) {
- return true;
+ /**
+ * Removes all of the mappings from this map.
+ */
+ @Override
+ public void clear() {
+ long delta = 0L; // negative number of deletions
+ int i = 0;
+ Node<K, V>[] tab = table;
+ while (tab != null && i < tab.length) {
+ int fh;
+ Node<K, V> f = tabAt(tab, i);
+ if (f == null) {
+ ++i;
+ }
+ else if ((fh = f.hash) == MOVED) {
+ tab = helpTransfer(tab, f);
+ i = 0; // restart
+ }
+ else {
+ synchronized (f) {
+ if (tabAt(tab, i) == f) {
+ Node<K, V> p = fh >= 0 ? f :
+ f instanceof TreeBin ?
+ ((TreeBin<K, V>)f).first : null;
+ while (p != null) {
+ --delta;
+ p = p.next;
}
+ setTabAt(tab, i++, null);
}
}
}
- return false;
}
+ if (delta != 0L) {
+ addCount(delta, -1);
+ }
+ }
+
+ /**
+ * Returns a {@link Set} view of the keys contained in this map.
+ * The set is backed by the map, so changes to the map are
+ * reflected in the set, and vice-versa. The set supports element
+ * removal, which removes the corresponding mapping from this map,
+ * via the {@code Iterator.remove}, {@code Set.remove},
+ * {@code removeAll}, {@code retainAll}, and {@code clear}
+ * operations. It does not support the {@code add} or
+ * {@code addAll} operations.
+ * <p/>
+ * <p>The view's {@code iterator} is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
+ *
+ * @return the set view
+ */
+ @NotNull
+ @Override
+ public KeySetView<K, V> keySet() {
+ KeySetView<K, V> ks;
+ return (ks = keySet) != null ? ks : (keySet = new KeySetView<K, V>(this, null));
+ }
+
+ /**
+ * Returns a {@link Collection} view of the values contained in this map.
+ * The collection is backed by the map, so changes to the map are
+ * reflected in the collection, and vice-versa. The collection
+ * supports element removal, which removes the corresponding
+ * mapping from this map, via the {@code Iterator.remove},
+ * {@code Collection.remove}, {@code removeAll},
+ * {@code retainAll}, and {@code clear} operations. It does not
+ * support the {@code add} or {@code addAll} operations.
+ * <p/>
+ * <p>The view's {@code iterator} is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
+ *
+ * @return the collection view
+ */
+ @NotNull
+ @Override
+ public Collection<V> values() {
+ ValuesView<K, V> vs;
+ return (vs = values) != null ? vs : (values = new ValuesView<K, V>(this));
+ }
+
+ /**
+ * Returns a {@link Set} view of the mappings contained in this map.
+ * The set is backed by the map, so changes to the map are
+ * reflected in the set, and vice-versa. The set supports element
+ * removal, which removes the corresponding mapping from the map,
+ * via the {@code Iterator.remove}, {@code Set.remove},
+ * {@code removeAll}, {@code retainAll}, and {@code clear}
+ * operations.
+ * <p/>
+ * <p>The view's {@code iterator} is a "weakly consistent" iterator
+ * that will never throw {@link ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed to)
+ * reflect any modifications subsequent to construction.
+ *
+ * @return the set view
+ */
+ @NotNull
+ @Override
+ public Set<Map.Entry<K, V>> entrySet() {
+ EntrySetView<K, V> es;
+ return (es = entrySet) != null ? es : (entrySet = new EntrySetView<K, V>(this));
+ }
+
+ /**
+ * Returns the hash code value for this {@link Map}, i.e.,
+ * the sum of, for each key-value pair in the map,
+ * {@code key.hashCode() ^ value.hashCode()}.
+ *
+ * @return the hash code value for this map
+ */
+ public int hashCode() {
+ int h = 0;
+ Node<K, V>[] t;
+ if ((t = table) != null) {
+ Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
+ for (Node<K, V> p; (p = it.advance()) != null; ) {
+ h += hash(p.key) ^ p.val.hashCode();
+ }
+ }
+ return h;
+ }
- private boolean replace(K key, int hash, V oldValue, V newValue) {
- lock();
- try {
- HashEntry<K, V> e = getFirst(hash);
- while (e != null && (e.hash != hash || !myHashingStrategy.equals(key, e.key))) {
- e = e.next;
+ /**
+ * Returns a string representation of this map. The string
+ * representation consists of a list of key-value mappings (in no
+ * particular order) enclosed in braces ("{@code {}}"). Adjacent
+ * mappings are separated by the characters {@code ", "} (comma
+ * and space). Each key-value mapping is rendered as the key
+ * followed by an equals sign ("{@code =}") followed by the
+ * associated value.
+ *
+ * @return a string representation of this map
+ */
+ public String toString() {
+ Node<K, V>[] t;
+ int f = (t = table) == null ? 0 : t.length;
+ Traverser<K, V> it = new Traverser<K, V>(t, f, 0, f);
+ StringBuilder sb = new StringBuilder();
+ sb.append('{');
+ Node<K, V> p;
+ if ((p = it.advance()) != null) {
+ for (; ; ) {
+ K k = p.key;
+ V v = p.val;
+ sb.append(k == this ? "(this Map)" : k);
+ sb.append('=');
+ sb.append(v == this ? "(this Map)" : v);
+ if ((p = it.advance()) == null) {
+ break;
}
+ sb.append(',').append(' ');
+ }
+ }
+ return sb.append('}').toString();
+ }
- boolean replaced = false;
- if (e != null && oldValue.equals(e.value)) {
- replaced = true;
- e.value = newValue;
+ /**
+ * Compares the specified object with this map for equality.
+ * Returns {@code true} if the given object is a map with the same
+ * mappings as this map. This operation may return misleading
+ * results if either map is concurrently modified during execution
+ * of this method.
+ *
+ * @param o object to be compared for equality with this map
+ * @return {@code true} if the specified object is equal to this map
+ */
+ public boolean equals(Object o) {
+ if (o != this) {
+ if (!(o instanceof Map)) {
+ return false;
+ }
+ Map<?, ?> m = (Map<?, ?>)o;
+ Node<K, V>[] t;
+ int f = (t = table) == null ? 0 : t.length;
+ Traverser<K, V> it = new Traverser<K, V>(t, f, 0, f);
+ for (Node<K, V> p; (p = it.advance()) != null; ) {
+ V val = p.val;
+ Object v = m.get(p.key);
+ if (v == null || v != val && !v.equals(val)) {
+ return false;
}
- return replaced;
}
- finally {
- unlock();
+ for (Map.Entry<?, ?> e : m.entrySet()) {
+ Object mk;
+ Object mv;
+ Object v;
+ if ((mk = e.getKey()) == null ||
+ (mv = e.getValue()) == null ||
+ (v = get(mk)) == null ||
+ mv != v && !mv.equals(v)) {
+ return false;
+ }
}
}
+ return true;
+ }
- private V replace(K key, int hash, V newValue) {
- lock();
- try {
- HashEntry<K, V> e = getFirst(hash);
- while (e != null && (e.hash != hash || !myHashingStrategy.equals(key, e.key))) {
- e = e.next;
+ /**
+ * Stripped-down version of helper class used in previous version,
+ * declared for the sake of serialization compatibility
+ */
+ static class Segment<K, V> extends ReentrantLock implements Serializable {
+ private static final long serialVersionUID = 2249069246763182397L;
+ final float loadFactor;
+
+ Segment(float lf) {
+ loadFactor = lf;
+ }
+ }
+
+ /**
+ * Saves the state of the {@code ConcurrentHashMapV8} instance to a
+ * stream (i.e., serializes it).
+ *
+ * @param s the stream
+ * @throws IOException if an I/O error occurs
+ * @serialData the key (Object) and value (Object)
+ * for each key-value mapping, followed by a null pair.
+ * The key-value mappings are emitted in no particular order.
+ */
+ private void writeObject(ObjectOutputStream s)
+ throws IOException {
+ // For serialization compatibility
+ // Emulate segment calculation from previous version of this class
+ int sshift = 0;
+ int ssize = 1;
+ while (ssize < DEFAULT_CONCURRENCY_LEVEL) {
+ ++sshift;
+ ssize <<= 1;
+ }
+ int segmentShift = 32 - sshift;
+ int segmentMask = ssize - 1;
+ @SuppressWarnings("unchecked") Segment<K, V>[] segments = (Segment<K, V>[])
+ new Segment<?, ?>[DEFAULT_CONCURRENCY_LEVEL];
+ for (int i = 0; i < segments.length; ++i) {
+ segments[i] = new Segment<K, V>(LOAD_FACTOR);
+ }
+ s.putFields().put("segments", segments);
+ s.putFields().put("segmentShift", segmentShift);
+ s.putFields().put("segmentMask", segmentMask);
+ s.writeFields();
+
+ Node<K, V>[] t;
+ if ((t = table) != null) {
+ Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
+ for (Node<K, V> p; (p = it.advance()) != null; ) {
+ s.writeObject(p.key);
+ s.writeObject(p.val);
+ }
+ }
+ s.writeObject(null);
+ s.writeObject(null);
+ segments = null; // throw away
+ }
+
+ /**
+ * Reconstitutes the instance from a stream (that is, deserializes it).
+ *
+ * @param s the stream
+ * @throws ClassNotFoundException if the class of a serialized object
+ * could not be found
+ * @throws IOException if an I/O error occurs
+ */
+ private void readObject(ObjectInputStream s)
+ throws IOException, ClassNotFoundException {
+ /*
+ * To improve performance in typical cases, we create nodes
+ * while reading, then place in table once size is known.
+ * However, we must also validate uniqueness and deal with
+ * overpopulated bins while doing so, which requires
+ * specialized versions of putVal mechanics.
+ */
+ sizeCtl = -1; // force exclusion for table construction
+ s.defaultReadObject();
+ long size = 0L;
+ Node<K, V> p = null;
+ for (; ; ) {
+ @SuppressWarnings("unchecked") K k = (K)s.readObject();
+ @SuppressWarnings("unchecked") V v = (V)s.readObject();
+ if (k != null && v != null) {
+ p = new Node<K, V>(hash(k), k, v, p,myHashingStrategy);
+ ++size;
+ }
+ else {
+ break;
+ }
+ }
+ if (size == 0L) {
+ sizeCtl = 0;
+ }
+ else {
+ int n;
+ if (size >= (long)(MAXIMUM_CAPACITY >>> 1)) {
+ n = MAXIMUM_CAPACITY;
+ }
+ else {
+ int sz = (int)size;
+ n = tableSizeFor(sz + (sz >>> 1) + 1);
+ }
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ Node<K, V>[] tab = (Node<K, V>[])new Node[n];
+ int mask = n - 1;
+ long added = 0L;
+ while (p != null) {
+ boolean insertAtFront;
+ Node<K, V> next = p.next;
+ Node<K, V> first;
+ int h = p.hash;
+ int j = h & mask;
+ if ((first = tabAt(tab, j)) == null) {
+ insertAtFront = true;
}
+ else {
+ K k = p.key;
+ if (first.hash < 0) {
+ TreeBin<K, V> t = (TreeBin<K, V>)first;
+ if (t.putTreeVal(h, k, p.val) == null) {
+ ++added;
+ }
+ insertAtFront = false;
+ }
+ else {
+ insertAtFront = true;
+ Node<K, V> q;
+ int binCount = 0;
+ for (q = first; q != null; q = q.next) {
+ K qk;
+ if (q.hash == h &&
+ ((qk = q.key) == k ||
+ qk != null && myHashingStrategy.equals(k,qk))) {
+ insertAtFront = false;
+ break;
+ }
+ ++binCount;
+ }
+ if (insertAtFront && binCount >= TREEIFY_THRESHOLD) {
+ insertAtFront = false;
+ ++added;
+ p.next = first;
+ TreeNode<K, V> hd = null;
+ TreeNode<K, V> tl = null;
+ for (q = p; q != null; q = q.next) {
+ TreeNode<K, V> t = new TreeNode<K, V>
+ (q.hash, q.key, q.val, null, null, myHashingStrategy);
+ if ((t.prev = tl) == null) {
+ hd = t;
+ }
+ else {
+ tl.next = t;
+ }
+ tl = t;
+ }
+ setTabAt(tab, j, new TreeBin<K, V>(hd, myHashingStrategy));
+ }
+ }
+ }
+ if (insertAtFront) {
+ ++added;
+ p.next = first;
+ setTabAt(tab, j, p);
+ }
+ p = next;
+ }
+ table = tab;
+ sizeCtl = n - (n >>> 2);
+ baseCount = added;
+ }
+ }
- V oldValue = null;
- if (e != null) {
- oldValue = e.value;
- e.value = newValue;
+ // ConcurrentMap methods
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return the previous value associated with the specified key,
+ * or {@code null} if there was no mapping for the key
+ * @throws NullPointerException if the specified key or value is null
+ */
+ @Override
+ public V putIfAbsent(@NotNull K key, V value) {
+ return putVal(key, value, true);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws NullPointerException if the specified key is null
+ */
+ @Override
+ public boolean remove(@NotNull Object key, Object value) {
+ return value != null && replaceNode(key, null, value) != null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws NullPointerException if any of the arguments are null
+ */
+ @Override
+ public boolean replace(@NotNull K key, @NotNull V oldValue, @NotNull V newValue) {
+ return replaceNode(key, newValue, oldValue) != null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return the previous value associated with the specified key,
+ * or {@code null} if there was no mapping for the key
+ * @throws NullPointerException if the specified key or value is null
+ */
+ @Override
+ public V replace(@NotNull K key, @NotNull V value) {
+ return replaceNode(key, value, null);
+ }
+
+ // Overrides of JDK8+ Map extension method defaults
+
+ /**
+ * Returns the value to which the specified key is mapped, or the
+ * given default value if this map contains no mapping for the
+ * key.
+ *
+ * @param key the key whose associated value is to be returned
+ * @param defaultValue the value to return if this map contains
+ * no mapping for the given key
+ * @return the mapping for the key, if present; else the default value
+ * @throws NullPointerException if the specified key is null
+ */
+// TODO no method in JDK6
+// @Override
+ public V getOrDefault(Object key, V defaultValue) {
+ V v;
+ return (v = get(key)) == null ? defaultValue : v;
+ }
+
+ public void forEach(BiAction<? super K, ? super V> action) {
+ if (action == null) throw new NullPointerException();
+ Node<K, V>[] t;
+ if ((t = table) != null) {
+ Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
+ for (Node<K, V> p; (p = it.advance()) != null; ) {
+ action.apply(p.key, p.val);
+ }
+ }
+ }
+
+ public void replaceAll(BiFun<? super K, ? super V, ? extends V> function) {
+ if (function == null) throw new NullPointerException();
+ Node<K, V>[] t;
+ if ((t = table) != null) {
+ Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
+ for (Node<K, V> p; (p = it.advance()) != null; ) {
+ V oldValue = p.val;
+ for (K key = p.key; ; ) {
+ V newValue = function.apply(key, oldValue);
+ if (newValue == null) {
+ throw new NullPointerException();
+ }
+ if (replaceNode(key, newValue, oldValue) != null ||
+ (oldValue = get(key)) == null) {
+ break;
+ }
}
- return oldValue;
}
- finally {
- unlock();
+ }
+ }
+
+ /**
+ * If the specified key is not already associated with a value,
+ * attempts to compute its value using the given mapping function
+ * and enters it into this map unless {@code null}. The entire
+ * method invocation is performed atomically, so the function is
+ * applied at most once per key. Some attempted update operations
+ * on this map by other threads may be blocked while computation
+ * is in progress, so the computation should be short and simple,
+ * and must not attempt to update any other mappings of this map.
+ *
+ * @param key key with which the specified value is to be associated
+ * @param mappingFunction the function to compute a value
+ * @return the current (existing or computed) value associated with
+ * the specified key, or null if the computed value is null
+ * @throws NullPointerException if the specified key or mappingFunction
+ * is null
+ * @throws IllegalStateException if the computation detectably
+ * attempts a recursive update to this map that would
+ * otherwise never complete
+ * @throws RuntimeException or Error if the mappingFunction does so,
+ * in which case the mapping is left unestablished
+ */
+ public V computeIfAbsent(K key, Fun<? super K, ? extends V> mappingFunction) {
+ if (key == null || mappingFunction == null) {
+ throw new NullPointerException();
+ }
+ int h = hash(key);
+ V val = null;
+ int binCount = 0;
+ for (Node<K, V>[] tab = table; ; ) {
+ Node<K, V> f;
+ int n;
+ int i;
+ int fh;
+ if (tab == null || (n = tab.length) == 0) {
+ tab = initTable();
+ }
+ else if ((f = tabAt(tab, i = n - 1 & h)) == null) {
+ Node<K, V> r = new ReservationNode<K, V>();
+ synchronized (r) {
+ if (casTabAt(tab, i, null, r)) {
+ binCount = 1;
+ Node<K, V> node = null;
+ try {
+ if ((val = mappingFunction.apply(key)) != null) {
+ node = new Node<K, V>(h, key, val, null,myHashingStrategy);
+ }
+ }
+ finally {
+ setTabAt(tab, i, node);
+ }
+ }
+ }
+ if (binCount != 0) {
+ break;
+ }
+ }
+ else if ((fh = f.hash) == MOVED) {
+ tab = helpTransfer(tab, f);
+ }
+ else {
+ boolean added = false;
+ synchronized (f) {
+ if (tabAt(tab, i) == f) {
+ if (fh >= 0) {
+ binCount = 1;
+ for (Node<K, V> e = f; ; ++binCount) {
+ K ek;
+ if (e.hash == h &&
+ ((ek = e.key) == key ||
+ ek != null && myHashingStrategy.equals(key,ek))) {
+ val = e.val;
+ break;
+ }
+ Node<K, V> pred = e;
+ if ((e = e.next) == null) {
+ if ((val = mappingFunction.apply(key)) != null) {
+ added = true;
+ pred.next = new Node<K, V>(h, key, val, null,myHashingStrategy);
+ }
+ break;
+ }
+ }
+ }
+ else if (f instanceof TreeBin) {
+ binCount = 2;
+ TreeBin<K, V> t = (TreeBin<K, V>)f;
+ TreeNode<K, V> r;
+ TreeNode<K, V> p;
+ if ((r = t.root) != null &&
+ (p = r.findTreeNode(h, key, null)) != null) {
+ val = p.val;
+ }
+ else if ((val = mappingFunction.apply(key)) != null) {
+ added = true;
+ t.putTreeVal(h, key, val);
+ }
+ }
+ }
+ }
+ if (binCount != 0) {
+ if (binCount >= TREEIFY_THRESHOLD) {
+ treeifyBin(tab, i);
+ }
+ if (!added) {
+ return val;
+ }
+ break;
+ }
}
}
+ if (val != null) {
+ addCount(1L, binCount);
+ }
+ return val;
+ }
- private V put(K key, int hash, V value, boolean onlyIfAbsent) {
- lock();
- try {
- int c = count;
- if (c++ > threshold) // ensure capacity
- {
- rehash();
+ /**
+ * If the value for the specified key is present, attempts to
+ * compute a new mapping given the key and its current mapped
+ * value. The entire method invocation is performed atomically.
+ * Some attempted update operations on this map by other threads
+ * may be blocked while computation is in progress, so the
+ * computation should be short and simple, and must not attempt to
+ * update any other mappings of this map.
+ *
+ * @param key key with which a value may be associated
+ * @param remappingFunction the function to compute a value
+ * @return the new value associated with the specified key, or null if none
+ * @throws NullPointerException if the specified key or remappingFunction
+ * is null
+ * @throws IllegalStateException if the computation detectably
+ * attempts a recursive update to this map that would
+ * otherwise never complete
+ * @throws RuntimeException or Error if the remappingFunction does so,
+ * in which case the mapping is unchanged
+ */
+ public V computeIfPresent(K key, BiFun<? super K, ? super V, ? extends V> remappingFunction) {
+ if (key == null || remappingFunction == null) {
+ throw new NullPointerException();
+ }
+ int h = hash(key);
+ V val = null;
+ int delta = 0;
+ int binCount = 0;
+ for (Node<K, V>[] tab = table; ; ) {
+ Node<K, V> f;
+ int n;
+ int i;
+ int fh;
+ if (tab == null || (n = tab.length) == 0) {
+ tab = initTable();
+ }
+ else if ((f = tabAt(tab, i = n - 1 & h)) == null) {
+ break;
+ }
+ else if ((fh = f.hash) == MOVED) {
+ tab = helpTransfer(tab, f);
+ }
+ else {
+ synchronized (f) {
+ if (tabAt(tab, i) == f) {
+ if (fh >= 0) {
+ binCount = 1;
+ for (Node<K, V> e = f, pred = null; ; ++binCount) {
+ K ek;
+ if (e.hash == h &&
+ ((ek = e.key) == key ||
+ ek != null && myHashingStrategy.equals(key,ek))) {
+ val = remappingFunction.apply(key, e.val);
+ if (val != null) {
+ e.val = val;
+ }
+ else {
+ delta = -1;
+ Node<K, V> en = e.next;
+ if (pred != null) {
+ pred.next = en;
+ }
+ else {
+ setTabAt(tab, i, en);
+ }
+ }
+ break;
+ }
+ pred = e;
+ if ((e = e.next) == null) {
+ break;
+ }
+ }
+ }
+ else if (f instanceof TreeBin) {
+ binCount = 2;
+ TreeBin<K, V> t = (TreeBin<K, V>)f;
+ TreeNode<K, V> r;
+ TreeNode<K, V> p;
+ if ((r = t.root) != null &&
+ (p = r.findTreeNode(h, key, null)) != null) {
+ val = remappingFunction.apply(key, p.val);
+ if (val != null) {
+ p.val = val;
+ }
+ else {
+ delta = -1;
+ if (t.removeTreeNode(p)) {
+ setTabAt(tab, i, untreeify(t.first));
+ }
+ }
+ }
+ }
+ }
}
- HashEntry[] tab = table;
- int index = hash & tab.length - 1;
- HashEntry<K, V> first = (HashEntry<K, V>)tab[index];
- HashEntry<K, V> e = first;
- while (e != null && (e.hash != hash || !myHashingStrategy.equals(key, e.key))) {
- e = e.next;
+ if (binCount != 0) {
+ break;
}
+ }
+ }
+ if (delta != 0) {
+ addCount((long)delta, binCount);
+ }
+ return val;
+ }
- V oldValue;
- if (e != null) {
- oldValue = e.value;
- if (!onlyIfAbsent) {
- e.value = value;
+ /**
+ * Attempts to compute a mapping for the specified key and its
+ * current mapped value (or {@code null} if there is no current
+ * mapping). The entire method invocation is performed atomically.
+ * Some attempted update operations on this map by other threads
+ * may be blocked while computation is in progress, so the
+ * computation should be short and simple, and must not attempt to
+ * update any other mappings of this Map.
+ *
+ * @param key key with which the specified value is to be associated
+ * @param remappingFunction the function to compute a value
+ * @return the new value associated with the specified key, or null if none
+ * @throws NullPointerException if the specified key or remappingFunction
+ * is null
+ * @throws IllegalStateException if the computation detectably
+ * attempts a recursive update to this map that would
+ * otherwise never complete
+ * @throws RuntimeException or Error if the remappingFunction does so,
+ * in which case the mapping is unchanged
+ */
+ public V compute(K key,
+ BiFun<? super K, ? super V, ? extends V> remappingFunction) {
+ if (key == null || remappingFunction == null) {
+ throw new NullPointerException();
+ }
+ int h = hash(key);
+ V val = null;
+ int delta = 0;
+ int binCount = 0;
+ for (Node<K, V>[] tab = table; ; ) {
+ Node<K, V> f;
+ int n;
+ int i;
+ int fh;
+ if (tab == null || (n = tab.length) == 0) {
+ tab = initTable();
+ }
+ else if ((f = tabAt(tab, i = n - 1 & h)) == null) {
+ Node<K, V> r = new ReservationNode<K, V>();
+ synchronized (r) {
+ if (casTabAt(tab, i, null, r)) {
+ binCount = 1;
+ Node<K, V> node = null;
+ try {
+ if ((val = remappingFunction.apply(key, null)) != null) {
+ delta = 1;
+ node = new Node<K, V>(h, key, val, null,myHashingStrategy);
+ }
+ }
+ finally {
+ setTabAt(tab, i, node);
+ }
}
}
- else {
- oldValue = null;
- ++modCount;
- tab[index] = new HashEntry<K, V>(key, hash, first, value);
- count = c; // write-volatile
+ if (binCount != 0) {
+ break;
}
- return oldValue;
}
- finally {
- unlock();
+ else if ((fh = f.hash) == MOVED) {
+ tab = helpTransfer(tab, f);
+ }
+ else {
+ synchronized (f) {
+ if (tabAt(tab, i) == f) {
+ if (fh >= 0) {
+ binCount = 1;
+ for (Node<K, V> e = f, pred = null; ; ++binCount) {
+ K ek;
+ if (e.hash == h &&
+ ((ek = e.key) == key ||
+ ek != null && myHashingStrategy.equals(key,ek))) {
+ val = remappingFunction.apply(key, e.val);
+ if (val != null) {
+ e.val = val;
+ }
+ else {
+ delta = -1;
+ Node<K, V> en = e.next;
+ if (pred != null) {
+ pred.next = en;
+ }
+ else {
+ setTabAt(tab, i, en);
+ }
+ }
+ break;
+ }
+ pred = e;
+ if ((e = e.next) == null) {
+ val = remappingFunction.apply(key, null);
+ if (val != null) {
+ delta = 1;
+ pred.next =
+ new Node<K, V>(h, key, val, null,myHashingStrategy);
+ }
+ break;
+ }
+ }
+ }
+ else if (f instanceof TreeBin) {
+ binCount = 1;
+ TreeBin<K, V> t = (TreeBin<K, V>)f;
+ TreeNode<K, V> r;
+ TreeNode<K, V> p;
+ if ((r = t.root) != null) {
+ p = r.findTreeNode(h, key, null);
+ }
+ else {
+ p = null;
+ }
+ V pv = p == null ? null : p.val;
+ val = remappingFunction.apply(key, pv);
+ if (val != null) {
+ if (p != null) {
+ p.val = val;
+ }
+ else {
+ delta = 1;
+ t.putTreeVal(h, key, val);
+ }
+ }
+ else if (p != null) {
+ delta = -1;
+ if (t.removeTreeNode(p)) {
+ setTabAt(tab, i, untreeify(t.first));
+ }
+ }
+ }
+ }
+ }
+ if (binCount != 0) {
+ if (binCount >= TREEIFY_THRESHOLD) {
+ treeifyBin(tab, i);
+ }
+ break;
+ }
+ }
+ }
+ if (delta != 0) {
+ addCount((long)delta, binCount);
+ }
+ return val;
+ }
+
+ /**
+ * If the specified key is not already associated with a
+ * (non-null) value, associates it with the given value.
+ * Otherwise, replaces the value with the results of the given
+ * remapping function, or removes if {@code null}. The entire
+ * method invocation is performed atomically. Some attempted
+ * update operations on this map by other threads may be blocked
+ * while computation is in progress, so the computation should be
+ * short and simple, and must not attempt to update any other
+ * mappings of this Map.
+ *
+ * @param key key with which the specified value is to be associated
+ * @param value the value to use if absent
+ * @param remappingFunction the function to recompute a value if present
+ * @return the new value associated with the specified key, or null if none
+ * @throws NullPointerException if the specified key or the
+ * remappingFunction is null
+ * @throws RuntimeException or Error if the remappingFunction does so,
+ * in which case the mapping is unchanged
+ */
+ public V merge(K key, V value, BiFun<? super V, ? super V, ? extends V> remappingFunction) {
+ if (key == null || value == null || remappingFunction == null) {
+ throw new NullPointerException();
+ }
+ int h = hash(key);
+ V val = null;
+ int delta = 0;
+ int binCount = 0;
+ for (Node<K, V>[] tab = table; ; ) {
+ Node<K, V> f;
+ int n;
+ int i;
+ int fh;
+ if (tab == null || (n = tab.length) == 0) {
+ tab = initTable();
+ }
+ else if ((f = tabAt(tab, i = n - 1 & h)) == null) {
+ if (casTabAt(tab, i, null, new Node<K, V>(h, key, value, null,myHashingStrategy))) {
+ delta = 1;
+ val = value;
+ break;
+ }
+ }
+ else if ((fh = f.hash) == MOVED) {
+ tab = helpTransfer(tab, f);
+ }
+ else {
+ synchronized (f) {
+ if (tabAt(tab, i) == f) {
+ if (fh >= 0) {
+ binCount = 1;
+ for (Node<K, V> e = f, pred = null; ; ++binCount) {
+ K ek;
+ if (e.hash == h &&
+ ((ek = e.key) == key ||
+ ek != null && myHashingStrategy.equals(key, ek))) {
+ val = remappingFunction.apply(e.val, value);
+ if (val != null) {
+ e.val = val;
+ }
+ else {
+ delta = -1;
+ Node<K, V> en = e.next;
+ if (pred != null) {
+ pred.next = en;
+ }
+ else {
+ setTabAt(tab, i, en);
+ }
+ }
+ break;
+ }
+ pred = e;
+ if ((e = e.next) == null) {
+ delta = 1;
+ val = value;
+ pred.next =
+ new Node<K, V>(h, key, val, null,myHashingStrategy);
+ break;
+ }
+ }
+ }
+ else if (f instanceof TreeBin) {
+ binCount = 2;
+ TreeBin<K, V> t = (TreeBin<K, V>)f;
+ TreeNode<K, V> r = t.root;
+ TreeNode<K, V> p = r == null ? null :
+ r.findTreeNode(h, key, null);
+ val = p == null ? value :
+ remappingFunction.apply(p.val, value);
+ if (val != null) {
+ if (p != null) {
+ p.val = val;
+ }
+ else {
+ delta = 1;
+ t.putTreeVal(h, key, val);
+ }
+ }
+ else if (p != null) {
+ delta = -1;
+ if (t.removeTreeNode(p)) {
+ setTabAt(tab, i, untreeify(t.first));
+ }
+ }
+ }
+ }
+ }
+ if (binCount != 0) {
+ if (binCount >= TREEIFY_THRESHOLD) {
+ treeifyBin(tab, i);
+ }
+ break;
+ }
+ }
+ }
+ if (delta != 0) {
+ addCount((long)delta, binCount);
+ }
+ return val;
+ }
+
+ // Hashtable legacy methods
+
+ /**
+ * Legacy method testing if some key maps into the specified value
+ * in this table. This method is identical in functionality to
+ * {@link #containsValue(Object)}, and exists solely to ensure
+ * full compatibility with class {@link java.util.Hashtable},
+ * which supported this method prior to introduction of the
+ * Java Collections framework.
+ *
+ * @param value a value to search for
+ * @return {@code true} if and only if some key maps to the
+ * {@code value} argument in this table as
+ * determined by the {@code equals} method;
+ * {@code false} otherwise
+ * @throws NullPointerException if the specified value is null
+ */
+ @Deprecated
+ public boolean contains(Object value) {
+ return containsValue(value);
+ }
+
+ /**
+ * Returns an enumeration of the keys in this table.
+ *
+ * @return an enumeration of the keys in this table
+ * @see #keySet()
+ */
+ public Enumeration<K> keys() {
+ Node<K, V>[] t;
+ int f = (t = table) == null ? 0 : t.length;
+ return new KeyIterator<K, V>(t, f, 0, f, this);
+ }
+
+ /**
+ * Returns an enumeration of the values in this table.
+ *
+ * @return an enumeration of the values in this table
+ * @see #values()
+ */
+ public Enumeration<V> elements() {
+ Node<K, V>[] t;
+ int f = (t = table) == null ? 0 : t.length;
+ return new ValueIterator<K, V>(t, f, 0, f, this);
+ }
+
+ // ConcurrentHashMapV8-only methods
+
+ /**
+ * Returns the number of mappings. This method should be used
+ * instead of {@link #size} because a ConcurrentHashMapV8 may
+ * contain more mappings than can be represented as an int. The
+ * value returned is an estimate; the actual count may differ if
+ * there are concurrent insertions or removals.
+ *
+ * @return the number of mappings
+ * @since 1.8
+ */
+ public long mappingCount() {
+ long n = sumCount();
+ return n < 0L ? 0L : n; // ignore transient negative values
+ }
+
+ /**
+ * Creates a new {@link Set} backed by a ConcurrentHashMapV8
+ * from the given type to {@code Boolean.TRUE}.
+ *
+ * @return the new set
+ * @since 1.8
+ */
+ public static <K> KeySetView<K, Boolean> newKeySet() {
+ return new KeySetView<K, Boolean>
+ (new ConcurrentHashMap<K, Boolean>(), Boolean.TRUE);
+ }
+
+ /**
+ * Creates a new {@link Set} backed by a ConcurrentHashMapV8
+ * from the given type to {@code Boolean.TRUE}.
+ *
+ * @param initialCapacity The implementation performs internal
+ * sizing to accommodate this many elements.
+ * @return the new set
+ * @throws IllegalArgumentException if the initial capacity of
+ * elements is negative
+ * @since 1.8
+ */
+ public static <K> KeySetView<K, Boolean> newKeySet(int initialCapacity) {
+ return new KeySetView<K, Boolean>
+ (new ConcurrentHashMap<K, Boolean>(initialCapacity), Boolean.TRUE);
+ }
+
+ /**
+ * Returns a {@link Set} view of the keys in this map, using the
+ * given common mapped value for any additions (i.e., {@link
+ * Collection#add} and {@link Collection#addAll(Collection)}).
+ * This is of course only appropriate if it is acceptable to use
+ * the same value for all additions from this view.
+ *
+ * @param mappedValue the mapped value to use for any additions
+ * @return the set view
+ * @throws NullPointerException if the mappedValue is null
+ */
+ public KeySetView<K, V> keySet(V mappedValue) {
+ if (mappedValue == null) {
+ throw new NullPointerException();
+ }
+ return new KeySetView<K, V>(this, mappedValue);
+ }
+
+ /* ---------------- Special Nodes -------------- */
+
+ /**
+ * A node inserted at head of bins during transfer operations.
+ */
+ static final class ForwardingNode<K, V> extends Node<K, V> {
+ final Node<K, V>[] nextTable;
+
+ ForwardingNode(Node<K, V>[] tab, TObjectHashingStrategy<K> hashingStrategy) {
+ super(MOVED, null, null, null, hashingStrategy);
+ nextTable = tab;
+ }
+
+ @Override
+ Node<K, V> find(int h, Object k) {
+ // loop to avoid arbitrarily deep recursion on forwarding nodes
+ outer:
+ for (Node<K, V>[] tab = nextTable; ; ) {
+ Node<K, V> e;
+ int n;
+ if (k == null || tab == null || (n = tab.length) == 0 ||
+ (e = tabAt(tab, n - 1 & h)) == null) {
+ return null;
+ }
+ for (; ; ) {
+ int eh;
+ K ek;
+ if ((eh = e.hash) == h &&
+ ((ek = e.key) == k || ek != null && myHashingStrategy.equals((K)k, ek))) {
+ return e;
+ }
+ if (eh < 0) {
+ if (e instanceof ForwardingNode) {
+ tab = ((ForwardingNode<K, V>)e).nextTable;
+ continue outer;
+ }
+ else {
+ return e.find(h, k);
+ }
+ }
+ if ((e = e.next) == null) {
+ return null;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * A place-holder node used in computeIfAbsent and compute
+ */
+ static final class ReservationNode<K, V> extends Node<K, V> {
+ ReservationNode() {
+ super(RESERVED, null, null, null,null);
+ }
+
+ @Override
+ Node<K, V> find(int h, Object k) {
+ return null;
+ }
+ }
+
+ /* ---------------- Table Initialization and Resizing -------------- */
+
+ /**
+ * Initializes table, using the size recorded in sizeCtl.
+ */
+ private Node<K, V>[] initTable() {
+ Node<K, V>[] tab;
+ while ((tab = table) == null || tab.length == 0) {
+ int sc;
+ if ((sc = sizeCtl) < 0) {
+ Thread.yield(); // lost initialization race; just spin
+ }
+ else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
+ try {
+ if ((tab = table) == null || tab.length == 0) {
+ int n = sc > 0 ? sc : DEFAULT_CAPACITY;
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ Node<K, V>[] nt = (Node<K, V>[])new Node[n];
+ table = tab = nt;
+ sc = n - (n >>> 2);
+ }
+ }
+ finally {
+ sizeCtl = sc;
+ }
+ break;
}
}
+ return tab;
+ }
- private void rehash() {
- HashEntry[] oldTable = table;
- int oldCapacity = oldTable.length;
- if (oldCapacity >= MAXIMUM_CAPACITY) {
+ /**
+ * Adds to count, and if table is too small and not already
+ * resizing, initiates transfer. If already resizing, helps
+ * perform transfer if work is available. Rechecks occupancy
+ * after a transfer to see if another resize is already needed
+ * because resizings are lagging additions.
+ *
+ * @param x the count to add
+ * @param check if <0, don't check resize, if <= 1 only check if uncontended
+ */
+ private void addCount(long x, int check) {
+ CounterCell[] as;
+ long b;
+ long s;
+ if ((as = counterCells) != null ||
+ !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
+ CounterHashCode hc;
+ CounterCell a;
+ long v;
+ int m;
+ boolean uncontended = true;
+ if ((hc = threadCounterHashCode.get()) == null ||
+ as == null || (m = as.length - 1) < 0 ||
+ (a = as[m & hc.code]) == null ||
+ !(uncontended =
+ U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {
+ fullAddCount(x, hc, uncontended);
+ return;
+ }
+ if (check <= 1) {
return;
}
+ s = sumCount();
+ }
+ if (check >= 0) {
+ Node<K, V>[] tab;
+ int sc;
+ while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
+ tab.length < MAXIMUM_CAPACITY) {
+ if (sc < 0) {
+ Node<K, V>[] nt;
+ if (sc == -1 || transferIndex <= transferOrigin ||
+ (nt = nextTable) == null) {
+ break;
+ }
+ if (U.compareAndSwapInt(this, SIZECTL, sc, sc - 1)) {
+ transfer(tab, nt);
+ }
+ }
+ else if (U.compareAndSwapInt(this, SIZECTL, sc, -2)) {
+ transfer(tab, null);
+ }
+ s = sumCount();
+ }
+ }
+ }
- /*
- * Reclassify nodes in each list to new Map. Because we are
- * using power-of-two expansion, the elements from each bin
- * must either stay at same index, or move with a power of two
- * offset. We eliminate unnecessary node creation by catching
- * cases where old nodes can be reused because their next
- * fields won't change. Statistically, at the default
- * threshold, only about one-sixth of them need cloning when
- * a table doubles. The nodes they replace will be garbage
- * collectable as soon as they are no longer referenced by any
- * reader thread that may be in the midst of traversing table
- * right now.
- */
-
- HashEntry[] newTable = new HashEntry[oldCapacity << 1];
- threshold = (int)(newTable.length * loadFactor);
- int sizeMask = newTable.length - 1;
- for (int i = 0; i < oldCapacity; i++) {
- // We need to guarantee that any existing reads of old Map can
- // proceed. So we cannot yet null out each bin.
- HashEntry<K, V> e = (HashEntry<K, V>)oldTable[i];
+ /**
+ * Helps transfer if a resize is in progress.
+ */
+ final Node<K, V>[] helpTransfer(Node<K, V>[] tab, Node<K, V> f) {
+ Node<K, V>[] nextTab;
+ if (f instanceof ForwardingNode &&
+ (nextTab = ((ForwardingNode<K, V>)f).nextTable) != null) {
+ int sc;
+ if (nextTab == nextTable && tab == table &&
+ transferIndex > transferOrigin && (sc = sizeCtl) < -1 &&
+ U.compareAndSwapInt(this, SIZECTL, sc, sc - 1)) {
+ transfer(tab, nextTab);
+ }
+ return nextTab;
+ }
+ return table;
+ }
- if (e != null) {
- HashEntry<K, V> next = e.next;
- int idx = e.hash & sizeMask;
+ /**
+ * Tries to presize table to accommodate the given number of elements.
+ *
+ * @param size number of elements (doesn't need to be perfectly accurate)
+ */
+ private void tryPresize(int size) {
+ int c = size >= MAXIMUM_CAPACITY >>> 1 ? MAXIMUM_CAPACITY :
+ tableSizeFor(size + (size >>> 1) + 1);
+ int sc;
+ while ((sc = sizeCtl) >= 0) {
+ Node<K, V>[] tab = table;
+ int n;
+ if (tab == null || (n = tab.length) == 0) {
+ n = sc > c ? sc : c;
+ if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
+ try {
+ if (table == tab) {
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ Node<K, V>[] nt = (Node<K, V>[])new Node[n];
+ table = nt;
+ sc = n - (n >>> 2);
+ }
+ }
+ finally {
+ sizeCtl = sc;
+ }
+ }
+ }
+ else if (c <= sc || n >= MAXIMUM_CAPACITY) {
+ break;
+ }
+ else if (tab == table &&
+ U.compareAndSwapInt(this, SIZECTL, sc, -2)) {
+ transfer(tab, null);
+ }
+ }
+ }
+
+ /**
+ * Moves and/or copies the nodes in each bin to new table. See
+ * above for explanation.
+ */
+ private void transfer(Node<K, V>[] tab, Node<K, V>[] nextTab) {
+ int n = tab.length;
+ int stride;
+ if ((stride = NCPU > 1 ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE) {
+ stride = MIN_TRANSFER_STRIDE; // subdivide range
+ }
+ if (nextTab == null) { // initiating
+ try {
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ Node<K, V>[] nt = (Node<K, V>[])new Node[n << 1];
+ nextTab = nt;
+ }
+ catch (Throwable ex) { // try to cope with OOME
+ sizeCtl = Integer.MAX_VALUE;
+ return;
+ }
+ nextTable = nextTab;
+ transferOrigin = n;
+ transferIndex = n;
+ ForwardingNode<K, V> rev = new ForwardingNode<K, V>(tab, myHashingStrategy);
+ for (int k = n; k > 0; ) { // progressively reveal ready slots
+ int nextk = k > stride ? k - stride : 0;
+ for (int m = nextk; m < k; ++m) {
+ nextTab[m] = rev;
+ }
+ for (int m = n + nextk; m < n + k; ++m) {
+ nextTab[m] = rev;
+ }
+ U.putOrderedInt(this, TRANSFERORIGIN, k = nextk);
+ }
+ }
+ int nextn = nextTab.length;
+ ForwardingNode<K, V> fwd = new ForwardingNode<K, V>(nextTab, myHashingStrategy);
+ boolean advance = true;
+ boolean finishing = false; // to ensure sweep before committing nextTab
+ for (int i = 0, bound = 0; ; ) {
+ while (advance) {
+ int nextIndex;
+ int nextBound;
+ if (--i >= bound || finishing) {
+ advance = false;
+ }
+ else if ((nextIndex = transferIndex) <= transferOrigin) {
+ i = -1;
+ advance = false;
+ }
+ else if (U.compareAndSwapInt
+ (this, TRANSFERINDEX, nextIndex,
+ nextBound = nextIndex > stride ?
+ nextIndex - stride : 0)) {
+ bound = nextBound;
+ i = nextIndex - 1;
+ advance = false;
+ }
+ }
+ int fh;
+ Node<K, V> f;
+ if (i < 0 || i >= n || i + n >= nextn) {
+ if (finishing) {
+ nextTable = null;
+ table = nextTab;
+ sizeCtl = (n << 1) - (n >>> 1);
+ return;
+ }
+ for (int sc; ; ) {
+ if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, ++sc)) {
+ if (sc != -1) {
+ return;
+ }
+ finishing = advance = true;
+ i = n; // recheck before commit
+ break;
+ }
+ }
+ }
+ else if ((f = tabAt(tab, i)) == null) {
+ if (casTabAt(tab, i, null, fwd)) {
+ setTabAt(nextTab, i, null);
+ setTabAt(nextTab, i + n, null);
+ advance = true;
+ }
+ }
+ else if ((fh = f.hash) == MOVED) {
+ advance = true; // already processed
+ }
+ else {
+ synchronized (f) {
+ if (tabAt(tab, i) == f) {
+ Node<K, V> ln;
+ Node<K, V> hn;
+ if (fh >= 0) {
+ int runBit = fh & n;
+ Node<K, V> lastRun = f;
+ for (Node<K, V> p = f.next; p != null; p = p.next) {
+ int b = p.hash & n;
+ if (b != runBit) {
+ runBit = b;
+ lastRun = p;
+ }
+ }
+ if (runBit == 0) {
+ ln = lastRun;
+ hn = null;
+ }
+ else {
+ hn = lastRun;
+ ln = null;
+ }
+ for (Node<K, V> p = f; p != lastRun; p = p.next) {
+ int ph = p.hash;
+ K pk = p.key;
+ V pv = p.val;
+ if ((ph & n) == 0) {
+ ln = new Node<K, V>(ph, pk, pv, ln,myHashingStrategy);
+ }
+ else {
+ hn = new Node<K, V>(ph, pk, pv, hn,myHashingStrategy);
+ }
+ }
+ setTabAt(nextTab, i, ln);
+ setTabAt(nextTab, i + n, hn);
+ setTabAt(tab, i, fwd);
+ advance = true;
+ }
+ else if (f instanceof TreeBin) {
+ TreeBin<K, V> t = (TreeBin<K, V>)f;
+ TreeNode<K, V> lo = null;
+ TreeNode<K, V> loTail = null;
+ TreeNode<K, V> hi = null;
+ TreeNode<K, V> hiTail = null;
+ int lc = 0;
+ int hc = 0;
+ for (Node<K, V> e = t.first; e != null; e = e.next) {
+ int h = e.hash;
+ TreeNode<K, V> p = new TreeNode<K, V>
+ (h, e.key, e.val, null, null, myHashingStrategy);
+ if ((h & n) == 0) {
+ if ((p.prev = loTail) == null) {
+ lo = p;
+ }
+ else {
+ loTail.next = p;
+ }
+ loTail = p;
+ ++lc;
+ }
+ else {
+ if ((p.prev = hiTail) == null) {
+ hi = p;
+ }
+ else {
+ hiTail.next = p;
+ }
+ hiTail = p;
+ ++hc;
+ }
+ }
+ ln = lc <= UNTREEIFY_THRESHOLD ? untreeify(lo) :
+ hc != 0 ? new TreeBin<K, V>(lo, myHashingStrategy) : t;
+ hn = hc <= UNTREEIFY_THRESHOLD ? untreeify(hi) :
+ lc != 0 ? new TreeBin<K, V>(hi, myHashingStrategy) : t;
+ setTabAt(nextTab, i, ln);
+ setTabAt(nextTab, i + n, hn);
+ setTabAt(tab, i, fwd);
+ advance = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* ---------------- Conversion from/to TreeBins -------------- */
- // Single node on list
- if (next == null) {
- newTable[idx] = e;
+ /**
+ * Replaces all linked nodes in bin at given index unless table is
+ * too small, in which case resizes instead.
+ */
+ private void treeifyBin(Node<K, V>[] tab, int index) {
+ if (tab != null) {
+ Node<K, V> b;
+ if (tab.length < MIN_TREEIFY_CAPACITY) {
+ int sc;
+ if (tab == table && (sc = sizeCtl) >= 0 &&
+ U.compareAndSwapInt(this, SIZECTL, sc, -2)) {
+ transfer(tab, null);
+ }
+ }
+ else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {
+ synchronized (b) {
+ if (tabAt(tab, index) == b) {
+ TreeNode<K, V> hd = null;
+ TreeNode<K, V> tl = null;
+ for (Node<K, V> e = b; e != null; e = e.next) {
+ TreeNode<K, V> p =
+ new TreeNode<K, V>(e.hash, e.key, e.val,
+ null, null, myHashingStrategy);
+ if ((p.prev = tl) == null) {
+ hd = p;
+ }
+ else {
+ tl.next = p;
+ }
+ tl = p;
+ }
+ setTabAt(tab, index, new TreeBin<K, V>(hd, myHashingStrategy));
}
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns a list on non-TreeNodes replacing those in given list.
+ */
+ static <K, V> Node<K, V> untreeify(Node<K, V> b) {
+ Node<K, V> hd = null;
+ Node<K, V> tl = null;
+ for (Node<K, V> q = b; q != null; q = q.next) {
+ Node<K, V> p = new Node<K, V>(q.hash, q.key, q.val, null,q.myHashingStrategy);
+ if (tl == null) {
+ hd = p;
+ }
+ else {
+ tl.next = p;
+ }
+ tl = p;
+ }
+ return hd;
+ }
+ /* ---------------- TreeNodes -------------- */
+
+ /**
+ * Nodes for use in TreeBins
+ */
+ static final class TreeNode<K, V> extends Node<K, V> {
+ TreeNode<K, V> parent; // red-black tree links
+ TreeNode<K, V> left;
+ TreeNode<K, V> right;
+ TreeNode<K, V> prev; // needed to unlink next upon deletion
+ boolean red;
+
+ TreeNode(int hash, K key, V val, Node<K, V> next,
+ TreeNode<K, V> parent, TObjectHashingStrategy<K> hashingStrategy) {
+ super(hash, key, val, next, hashingStrategy);
+ this.parent = parent;
+ }
+
+ @Override
+ Node<K, V> find(int h, Object k) {
+ return findTreeNode(h, k, null);
+ }
+
+ /**
+ * Returns the TreeNode (or null if not found) for the given key
+ * starting at given root.
+ */
+ final TreeNode<K, V> findTreeNode(int h, Object k, Class<?> kc) {
+ if (k != null) {
+ TreeNode<K, V> p = this;
+ do {
+ int ph;
+ int dir;
+ K pk;
+ TreeNode<K, V> q;
+ TreeNode<K, V> pl = p.left;
+ TreeNode<K, V> pr = p.right;
+ if ((ph = p.hash) > h) {
+ p = pl;
+ }
+ else if (ph < h) {
+ p = pr;
+ }
+ else if ((pk = p.key) == k || pk != null && myHashingStrategy.equals((K)k,pk)) {
+ return p;
+ }
+ else if (pl == null) {
+ p = pr;
+ }
+ else if (pr == null) {
+ p = pl;
+ }
+ else if ((kc != null ||
+ (kc = comparableClassFor(k)) != null) &&
+ (dir = compareComparables(kc, k, pk)) != 0) {
+ p = dir < 0 ? pl : pr;
+ }
+ else if ((q = pr.findTreeNode(h, k, kc)) != null) {
+ return q;
+ }
else {
- // Reuse trailing consecutive sequence at same slot
- HashEntry<K, V> lastRun = e;
- int lastIdx = idx;
- for (HashEntry<K, V> last = next;
- last != null;
- last = last.next) {
- int k = last.hash & sizeMask;
- if (k != lastIdx) {
- lastIdx = k;
- lastRun = last;
+ p = pl;
+ }
+ }
+ while (p != null);
+ }
+ return null;
+ }
+ }
+
+ /* ---------------- TreeBins -------------- */
+
+ /**
+ * TreeNodes used at the heads of bins. TreeBins do not hold user
+ * keys or values, but instead point to list of TreeNodes and
+ * their root. They also maintain a parasitic read-write lock
+ * forcing writers (who hold bin lock) to wait for readers (who do
+ * not) to complete before tree restructuring operations.
+ */
+ static final class TreeBin<K, V> extends Node<K, V> {
+ TreeNode<K, V> root;
+ volatile TreeNode<K, V> first;
+ volatile Thread waiter;
+ volatile int lockState;
+ // values for lockState
+ static final int WRITER = 1; // set while holding write lock
+ static final int WAITER = 2; // set when waiting for write lock
+ static final int READER = 4; // increment value for setting read lock
+
+ /**
+ * Tie-breaking utility for ordering insertions when equal
+ * hashCodes and non-comparable. We don't require a total
+ * order, just a consistent insertion rule to maintain
+ * equivalence across rebalancings. Tie-breaking further than
+ * necessary simplifies testing a bit.
+ */
+ static int tieBreakOrder(Object a, Object b) {
+ int d;
+ if (a == null || b == null ||
+ (d = a.getClass().getName().
+ compareTo(b.getClass().getName())) == 0) {
+ d = System.identityHashCode(a) <= System.identityHashCode(b) ?
+ -1 : 1;
+ }
+ return d;
+ }
+
+ /**
+ * Creates bin with initial set of nodes headed by b.
+ */
+ TreeBin(TreeNode<K, V> b, TObjectHashingStrategy<K> hashingStrategy) {
+ super(TREEBIN, null, null, null, hashingStrategy);
+ first = b;
+ TreeNode<K, V> r = null;
+ for (TreeNode<K, V> x = b, next; x != null; x = next) {
+ next = (TreeNode<K, V>)x.next;
+ x.left = x.right = null;
+ if (r == null) {
+ x.parent = null;
+ x.red = false;
+ r = x;
+ }
+ else {
+ K k = x.key;
+ int h = x.hash;
+ Class<?> kc = null;
+ for (TreeNode<K, V> p = r; ; ) {
+ int dir;
+ int ph;
+ K pk = p.key;
+ if ((ph = p.hash) > h) {
+ dir = -1;
+ }
+ else if (ph < h) {
+ dir = 1;
+ }
+ else if (kc == null &&
+ (kc = comparableClassFor(k)) == null ||
+ (dir = compareComparables(kc, k, pk)) == 0) {
+ dir = tieBreakOrder(k, pk);
+ }
+ TreeNode<K, V> xp = p;
+ if ((p = dir <= 0 ? p.left : p.right) == null) {
+ x.parent = xp;
+ if (dir <= 0) {
+ xp.left = x;
+ }
+ else {
+ xp.right = x;
}
+ r = balanceInsertion(r, x);
+ break;
}
- newTable[lastIdx] = lastRun;
+ }
+ }
+ }
+ root = r;
+ assert checkInvariants(root);
+ }
- // Clone all remaining nodes
- for (HashEntry<K, V> p = e; p != lastRun; p = p.next) {
- int k = p.hash & sizeMask;
- HashEntry<K, V> n = (HashEntry<K, V>)newTable[k];
- newTable[k] = new HashEntry<K, V>(p.key, p.hash,
- n, p.value);
+ /**
+ * Acquires write lock for tree restructuring.
+ */
+ private void lockRoot() {
+ if (!U.compareAndSwapInt(this, LOCKSTATE, 0, WRITER)) {
+ contendedLock(); // offload to separate method
+ }
+ }
+
+ /**
+ * Releases write lock for tree restructuring.
+ */
+ private void unlockRoot() {
+ lockState = 0;
+ }
+
+ /**
+ * Possibly blocks awaiting root lock.
+ */
+ private void contendedLock() {
+ boolean waiting = false;
+ for (int s; ; ) {
+ if (((s = lockState) & WRITER) == 0) {
+ if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) {
+ if (waiting) {
+ waiter = null;
+ }
+ return;
+ }
+ }
+ else if ((s & WAITER) == 0) {
+ if (U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)) {
+ waiting = true;
+ waiter = Thread.currentThread();
+ }
+ }
+ else if (waiting) {
+ LockSupport.park(this);
+ }
+ }
+ }
+
+ /**
+ * Returns matching node or null if none. Tries to search
+ * using tree comparisons from root, but continues linear
+ * search when lock not available.
+ */
+ @Override
+ final Node<K, V> find(int h, Object k) {
+ if (k != null) {
+ for (Node<K, V> e = first; e != null; e = e.next) {
+ int s;
+ if (((s = lockState) & (WAITER | WRITER)) != 0) {
+ K ek;
+ if (e.hash == h &&
+ ((ek = e.key) == k || ek != null && myHashingStrategy.equals((K)k,ek))) {
+ return e;
+ }
+ }
+ else if (U.compareAndSwapInt(this, LOCKSTATE, s,
+ s + READER)) {
+ TreeNode<K, V> p;
+ try {
+ TreeNode<K, V> r;
+ p = (r = root) == null ? null :
+ r.findTreeNode(h, k, null);
+ }
+ finally {
+ int ls;
+ do {
+ }
+ while (!U.compareAndSwapInt
+ (this, LOCKSTATE,
+ ls = lockState, ls - READER));
+ Thread w;
+ if (ls == (READER | WAITER) && (w = waiter) != null) {
+ LockSupport.unpark(w);
+ }
+ }
+ return p;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Finds or adds a node.
+ *
+ * @return null if added
+ */
+ final TreeNode<K, V> putTreeVal(int h, K k, V v) {
+ Class<?> kc = null;
+ boolean searched = false;
+ for (TreeNode<K, V> p = root; ; ) {
+ int dir;
+ int ph;
+ K pk;
+ if (p == null) {
+ first = root = new TreeNode<K, V>(h, k, v, null, null, myHashingStrategy);
+ break;
+ }
+ else if ((ph = p.hash) > h) {
+ dir = -1;
+ }
+ else if (ph < h) {
+ dir = 1;
+ }
+ else if ((pk = p.key) == k || pk != null && myHashingStrategy.equals(k,pk)) {
+ return p;
+ }
+ else if (kc == null &&
+ (kc = comparableClassFor(k)) == null ||
+ (dir = compareComparables(kc, k, pk)) == 0) {
+ if (!searched) {
+ searched = true;
+ TreeNode<K, V> q;
+ TreeNode<K, V> ch;
+ if ((ch = p.left) != null &&
+ (q = ch.findTreeNode(h, k, kc)) != null ||
+ (ch = p.right) != null &&
+ (q = ch.findTreeNode(h, k, kc)) != null) {
+ return q;
}
}
+ dir = tieBreakOrder(k, pk);
+ }
+
+ TreeNode<K, V> xp = p;
+ if ((p = dir <= 0 ? p.left : p.right) == null) {
+ TreeNode<K, V> x;
+ TreeNode<K, V> f = first;
+ first = x = new TreeNode<K, V>(h, k, v, f, xp, myHashingStrategy);
+ if (f != null) {
+ f.prev = x;
+ }
+ if (dir <= 0) {
+ xp.left = x;
+ }
+ else {
+ xp.right = x;
+ }
+ if (!xp.red) {
+ x.red = true;
+ }
+ else {
+ lockRoot();
+ try {
+ root = balanceInsertion(root, x);
+ }
+ finally {
+ unlockRoot();
+ }
+ }
+ break;
}
}
- table = newTable;
+ assert checkInvariants(root);
+ return null;
}
/**
- * Remove; match on key only if value null, else match both.
+ * Removes the given node, that must be present before this
+ * call. This is messier than typical red-black deletion code
+ * because we cannot swap the contents of an interior node
+ * with a leaf successor that is pinned by "next" pointers
+ * that are accessible independently of lock. So instead we
+ * swap the tree linkages.
+ *
+ * @return true if now too small, so should be untreeified
*/
- private V remove(K key, int hash, V value) {
- lock();
+ final boolean removeTreeNode(TreeNode<K, V> p) {
+ TreeNode<K, V> next = (TreeNode<K, V>)p.next;
+ TreeNode<K, V> pred = p.prev; // unlink traversal pointers
+ if (pred == null) {
+ first = next;
+ }
+ else {
+ pred.next = next;
+ }
+ if (next != null) {
+ next.prev = pred;
+ }
+ if (first == null) {
+ root = null;
+ return true;
+ }
+ TreeNode<K, V> r;
+ TreeNode<K, V> rl;
+ if ((r = root) == null || r.right == null || // too small
+ (rl = r.left) == null || rl.left == null) {
+ return true;
+ }
+ lockRoot();
try {
- int c = count - 1;
- HashEntry[] tab = table;
- int index = hash & tab.length - 1;
- HashEntry<K, V> first = (HashEntry<K, V>)tab[index];
- HashEntry<K, V> e = first;
- while (e != null && (e.hash != hash || !myHashingStrategy.equals(key, e.key))) {
- e = e.next;
+ TreeNode<K, V> replacement;
+ TreeNode<K, V> pl = p.left;
+ TreeNode<K, V> pr = p.right;
+ if (pl != null && pr != null) {
+ TreeNode<K, V> s = pr;
+ TreeNode<K, V> sl;
+ while ((sl = s.left) != null) // find successor
+ {
+ s = sl;
+ }
+ boolean c = s.red;
+ s.red = p.red;
+ p.red = c; // swap colors
+ TreeNode<K, V> sr = s.right;
+ TreeNode<K, V> pp = p.parent;
+ if (s == pr) { // p was s's direct parent
+ p.parent = s;
+ s.right = p;
+ }
+ else {
+ TreeNode<K, V> sp = s.parent;
+ if ((p.parent = sp) != null) {
+ if (s == sp.left) {
+ sp.left = p;
+ }
+ else {
+ sp.right = p;
+ }
+ }
+ if ((s.right = pr) != null) {
+ pr.parent = s;
+ }
+ }
+ p.left = null;
+ if ((p.right = sr) != null) {
+ sr.parent = p;
+ }
+ if ((s.left = pl) != null) {
+ pl.parent = s;
+ }
+ if ((s.parent = pp) == null) {
+ r = s;
+ }
+ else if (p == pp.left) {
+ pp.left = s;
+ }
+ else {
+ pp.right = s;
+ }
+ if (sr != null) {
+ replacement = sr;
+ }
+ else {
+ replacement = p;
+ }
+ }
+ else if (pl != null) {
+ replacement = pl;
+ }
+ else if (pr != null) {
+ replacement = pr;
+ }
+ else {
+ replacement = p;
+ }
+ if (replacement != p) {
+ TreeNode<K, V> pp = replacement.parent = p.parent;
+ if (pp == null) {
+ r = replacement;
+ }
+ else if (p == pp.left) {
+ pp.left = replacement;
+ }
+ else {
+ pp.right = replacement;
+ }
+ p.left = p.right = p.parent = null;
}
- V oldValue = null;
- if (e != null) {
- V v = e.value;
- if (value == null || value.equals(v)) {
- oldValue = v;
- // All entries following removed node can stay
- // in list, but all preceding ones need to be
- // cloned.
- ++modCount;
- HashEntry<K, V> newFirst = e.next;
- for (HashEntry<K, V> p = first; p != e; p = p.next) {
- newFirst = new HashEntry<K, V>(p.key, p.hash, newFirst, p.value);
+ root = p.red ? r : balanceDeletion(r, replacement);
+
+ if (p == replacement) { // detach pointers
+ TreeNode<K, V> pp;
+ if ((pp = p.parent) != null) {
+ if (p == pp.left) {
+ pp.left = null;
}
- tab[index] = newFirst;
- count = c; // write-volatile
+ else if (p == pp.right) {
+ pp.right = null;
+ }
+ p.parent = null;
}
}
- return oldValue;
}
finally {
- unlock();
+ unlockRoot();
}
+ assert checkInvariants(root);
+ return false;
}
- private void clear() {
- if (count != 0) {
- lock();
- try {
- HashEntry[] tab = table;
- for (int i = 0; i < tab.length; i++) {
- tab[i] = null;
+ /* ------------------------------------------------------------ */
+ // Red-black tree methods, all adapted from CLR
+
+ static <K, V> TreeNode<K, V> rotateLeft(TreeNode<K, V> root,
+ TreeNode<K, V> p) {
+ TreeNode<K, V> r;
+ if (p != null && (r = p.right) != null) {
+ TreeNode<K, V> rl;
+ if ((rl = p.right = r.left) != null) {
+ rl.parent = p;
+ }
+ TreeNode<K, V> pp;
+ if ((pp = r.parent = p.parent) == null) {
+ (root = r).red = false;
+ }
+ else if (pp.left == p) {
+ pp.left = r;
+ }
+ else {
+ pp.right = r;
+ }
+ r.left = p;
+ p.parent = r;
+ }
+ return root;
+ }
+
+ static <K, V> TreeNode<K, V> rotateRight(TreeNode<K, V> root,
+ TreeNode<K, V> p) {
+ TreeNode<K, V> l;
+ if (p != null && (l = p.left) != null) {
+ TreeNode<K, V> lr;
+ if ((lr = p.left = l.right) != null) {
+ lr.parent = p;
+ }
+ TreeNode<K, V> pp;
+ if ((pp = l.parent = p.parent) == null) {
+ (root = l).red = false;
+ }
+ else if (pp.right == p) {
+ pp.right = l;
+ }
+ else {
+ pp.left = l;
+ }
+ l.right = p;
+ p.parent = l;
+ }
+ return root;
+ }
+
+ static <K, V> TreeNode<K, V> balanceInsertion(TreeNode<K, V> root,
+ TreeNode<K, V> x) {
+ x.red = true;
+ for (TreeNode<K, V> xp, xpp, xppl, xppr; ; ) {
+ if ((xp = x.parent) == null) {
+ x.red = false;
+ return x;
+ }
+ else if (!xp.red || (xpp = xp.parent) == null) {
+ return root;
+ }
+ if (xp == (xppl = xpp.left)) {
+ if ((xppr = xpp.right) != null && xppr.red) {
+ xppr.red = false;
+ xp.red = false;
+ xpp.red = true;
+ x = xpp;
+ }
+ else {
+ if (x == xp.right) {
+ root = rotateLeft(root, x = xp);
+ xpp = (xp = x.parent) == null ? null : xp.parent;
+ }
+ if (xp != null) {
+ xp.red = false;
+ if (xpp != null) {
+ xpp.red = true;
+ root = rotateRight(root, xpp);
+ }
+ }
}
- ++modCount;
- count = 0; // write-volatile
}
- finally {
- unlock();
+ else {
+ if (xppl != null && xppl.red) {
+ xppl.red = false;
+ xp.red = false;
+ xpp.red = true;
+ x = xpp;
+ }
+ else {
+ if (x == xp.left) {
+ root = rotateRight(root, x = xp);
+ xpp = (xp = x.parent) == null ? null : xp.parent;
+ }
+ if (xp != null) {
+ xp.red = false;
+ if (xpp != null) {
+ xpp.red = true;
+ root = rotateLeft(root, xpp);
+ }
+ }
+ }
}
}
}
- }
- /* ---------------- Public operations -------------- */
+ static <K, V> TreeNode<K, V> balanceDeletion(TreeNode<K, V> root,
+ TreeNode<K, V> x) {
+ for (TreeNode<K, V> xp, xpl, xpr; ; ) {
+ if (x == null || x == root) {
+ return root;
+ }
+ else if ((xp = x.parent) == null) {
+ x.red = false;
+ return x;
+ }
+ else if (x.red) {
+ x.red = false;
+ return root;
+ }
+ else if ((xpl = xp.left) == x) {
+ if ((xpr = xp.right) != null && xpr.red) {
+ xpr.red = false;
+ xp.red = true;
+ root = rotateLeft(root, xp);
+ xpr = (xp = x.parent) == null ? null : xp.right;
+ }
+ if (xpr == null) {
+ x = xp;
+ }
+ else {
+ TreeNode<K, V> sl = xpr.left;
+ TreeNode<K, V> sr = xpr.right;
+ if ((sr == null || !sr.red) &&
+ (sl == null || !sl.red)) {
+ xpr.red = true;
+ x = xp;
+ }
+ else {
+ if (sr == null || !sr.red) {
+ if (sl != null) {
+ sl.red = false;
+ }
+ xpr.red = true;
+ root = rotateRight(root, xpr);
+ xpr = (xp = x.parent) == null ?
+ null : xp.right;
+ }
+ if (xpr != null) {
+ xpr.red = xp == null ? false : xp.red;
+ if ((sr = xpr.right) != null) {
+ sr.red = false;
+ }
+ }
+ if (xp != null) {
+ xp.red = false;
+ root = rotateLeft(root, xp);
+ }
+ x = root;
+ }
+ }
+ }
+ else { // symmetric
+ if (xpl != null && xpl.red) {
+ xpl.red = false;
+ xp.red = true;
+ root = rotateRight(root, xp);
+ xpl = (xp = x.parent) == null ? null : xp.left;
+ }
+ if (xpl == null) {
+ x = xp;
+ }
+ else {
+ TreeNode<K, V> sl = xpl.left;
+ TreeNode<K, V> sr = xpl.right;
+ if ((sl == null || !sl.red) &&
+ (sr == null || !sr.red)) {
+ xpl.red = true;
+ x = xp;
+ }
+ else {
+ if (sl == null || !sl.red) {
+ if (sr != null) {
+ sr.red = false;
+ }
+ xpl.red = true;
+ root = rotateLeft(root, xpl);
+ xpl = (xp = x.parent) == null ?
+ null : xp.left;
+ }
+ if (xpl != null) {
+ xpl.red = xp == null ? false : xp.red;
+ if ((sl = xpl.left) != null) {
+ sl.red = false;
+ }
+ }
+ if (xp != null) {
+ xp.red = false;
+ root = rotateRight(root, xp);
+ }
+ x = root;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Recursive invariant check
+ */
+ static <K, V> boolean checkInvariants(TreeNode<K, V> t) {
+ TreeNode<K, V> tp = t.parent;
+ TreeNode<K, V> tl = t.left;
+ TreeNode<K, V> tr = t.right;
+ TreeNode<K, V> tb = t.prev;
+ TreeNode<K, V> tn = (TreeNode<K, V>)t.next;
+ if (tb != null && tb.next != t) {
+ return false;
+ }
+ if (tn != null && tn.prev != t) {
+ return false;
+ }
+ if (tp != null && t != tp.left && t != tp.right) {
+ return false;
+ }
+ if (tl != null && (tl.parent != t || tl.hash > t.hash)) {
+ return false;
+ }
+ if (tr != null && (tr.parent != t || tr.hash < t.hash)) {
+ return false;
+ }
+ if (t.red && tl != null && tl.red && tr != null && tr.red) {
+ return false;
+ }
+ if (tl != null && !checkInvariants(tl)) {
+ return false;
+ }
+ if (tr != null && !checkInvariants(tr)) {
+ return false;
+ }
+ return true;
+ }
+
+ private static final Unsafe U;
+ private static final long LOCKSTATE;
- public ConcurrentHashMap(TObjectHashingStrategy<K> hashingStrategy) {
- this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS, hashingStrategy);
+ static {
+ try {
+ U = getUnsafe();
+ Class<?> k = TreeBin.class;
+ LOCKSTATE = U.objectFieldOffset
+ (k.getDeclaredField("lockState"));
+ }
+ catch (Exception e) {
+ throw new Error(e);
+ }
+ }
}
+ /* ----------------Table Traversal -------------- */
+
/**
- * Creates a new, empty map with the specified initial
- * capacity, load factor, and concurrency level.
- *
- * @param initialCapacity the initial capacity. The implementation
- * performs internal sizing to accommodate this many elements.
- * @param loadFactor the load factor threshold, used to control resizing.
- * Resizing may be performed when the average number of elements per
- * bin exceeds this threshold.
- * @param concurrencyLevel the estimated number of concurrently
- * updating threads. The implementation performs internal sizing
- * to try to accommodate this many threads.
- * @throws IllegalArgumentException if the initial capacity is
- * negative or the load factor or concurrencyLevel are
- * nonpositive.
+ * Encapsulates traversal for methods such as containsValue; also
+ * serves as a base class for other iterators and spliterators.
+ * <p/>
+ * Method advance visits once each still-valid node that was
+ * reachable upon iterator construction. It might miss some that
+ * were added to a bin after the bin was visited, which is OK wrt
+ * consistency guarantees. Maintaining this property in the face
+ * of possible ongoing resizes requires a fair amount of
+ * bookkeeping state that is difficult to optimize away amidst
+ * volatile accesses. Even so, traversal maintains reasonable
+ * throughput.
+ * <p/>
+ * Normally, iteration proceeds bin-by-bin traversing lists.
+ * However, if the table has been resized, then all future steps
+ * must traverse both the bin at the current index as well as at
+ * (index + baseSize); and so on for further resizings. To
+ * paranoically cope with potential sharing by users of iterators
+ * across threads, iteration terminates if a bounds checks fails
+ * for a table read.
*/
- public ConcurrentHashMap(int initialCapacity,
- float loadFactor, int concurrencyLevel) {
- this(initialCapacity, loadFactor, concurrencyLevel, null);
+ static class Traverser<K, V> {
+ Node<K, V>[] tab; // current table; updated if resized
+ Node<K, V> next; // the next entry to use
+ int index; // index of bin to use next
+ int baseIndex; // current index of initial table
+ int baseLimit; // index bound for initial table
+ final int baseSize; // initial table size
+
+ Traverser(Node<K, V>[] tab, int size, int index, int limit) {
+ this.tab = tab;
+ baseSize = size;
+ baseIndex = this.index = index;
+ baseLimit = limit;
+ next = null;
+ }
+
+ /**
+ * Advances if possible, returning next valid node, or null if none.
+ */
+ final Node<K, V> advance() {
+ Node<K, V> e;
+ if ((e = next) != null) {
+ e = e.next;
+ }
+ for (; ; ) {
+ if (e != null) {
+ return next = e;
+ }
+ Node<K, V>[] t;
+ int i;
+ int n;
+ if (baseIndex >= baseLimit || (t = tab) == null ||
+ (n = t.length) <= (i = index) || i < 0) {
+ return next = null;
+ }
+ if ((e = tabAt(t, index)) != null && e.hash < 0) {
+ if (e instanceof ForwardingNode) {
+ tab = ((ForwardingNode<K, V>)e).nextTable;
+ e = null;
+ continue;
+ }
+ else if (e instanceof TreeBin) {
+ e = ((TreeBin<K, V>)e).first;
+ }
+ else {
+ e = null;
+ }
+ }
+ if ((index += baseSize) >= n) {
+ index = ++baseIndex; // visit upper slots if present
+ }
+ }
+ }
}
- public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel, TObjectHashingStrategy<K> hashingStrategy) {
- if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0) {
- throw new IllegalArgumentException();
+ /**
+ * Base of key, value, and entry Iterators. Adds fields to
+ * Traverser to support iterator.remove.
+ */
+ static class BaseIterator<K, V> extends Traverser<K, V> {
+ final ConcurrentHashMap<K, V> map;
+ Node<K, V> lastReturned;
+
+ BaseIterator(Node<K, V>[] tab, int size, int index, int limit,
+ ConcurrentHashMap<K, V> map) {
+ super(tab, size, index, limit);
+ this.map = map;
+ advance();
}
- if (concurrencyLevel > MAX_SEGMENTS) {
- concurrencyLevel = MAX_SEGMENTS;
+ public final boolean hasNext() {
+ return next != null;
}
- // Find power-of-two sizes best matching arguments
- int ssize = 1;
- while (ssize < concurrencyLevel) {
- ssize <<= 1;
+ public final boolean hasMoreElements() {
+ return next != null;
}
- segmentShift =
- 12; // the middle of the hash is much more random that its HSB. Especially when we use TObjectHashingStrategy.CANONICAl as a hash provider
- segmentMask = ssize - 1;
- segments = new Segment[ssize];
- if (initialCapacity > MAXIMUM_CAPACITY) {
- initialCapacity = MAXIMUM_CAPACITY;
+ public final void remove() {
+ Node<K, V> p;
+ if ((p = lastReturned) == null) {
+ throw new IllegalStateException();
+ }
+ lastReturned = null;
+ map.replaceNode(p.key, null, null);
}
- int c = initialCapacity / ssize;
- if (c * ssize < initialCapacity) {
- ++c;
+ }
+
+ static final class KeyIterator<K, V> extends BaseIterator<K, V>
+ implements Iterator<K>, Enumeration<K> {
+ KeyIterator(Node<K, V>[] tab, int index, int size, int limit,
+ ConcurrentHashMap<K, V> map) {
+ super(tab, index, size, limit, map);
}
- int cap = 1;
- while (cap < c) {
- cap <<= 1;
+
+ @Override
+ public final K next() {
+ Node<K, V> p;
+ if ((p = next) == null) {
+ throw new NoSuchElementException();
+ }
+ K k = p.key;
+ lastReturned = p;
+ advance();
+ return k;
}
- hashingStrategy = hashingStrategy == null ? this : hashingStrategy;
- for (int i = 0; i < segments.length; ++i) {
- segments[i] = new Segment<K, V>(cap, loadFactor, hashingStrategy);
+ @Override
+ public final K nextElement() {
+ return next();
}
- myHashingStrategy = hashingStrategy;
}
- /**
- * Creates a new, empty map with the specified initial
- * capacity, and with default load factor and concurrencyLevel.
- *
- * @param initialCapacity the initial capacity. The implementation
- * performs internal sizing to accommodate this many elements.
- * @throws IllegalArgumentException if the initial capacity of
- * elements is negative.
- */
- public ConcurrentHashMap(int initialCapacity) {
- this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS);
+ static final class ValueIterator<K, V> extends BaseIterator<K, V>
+ implements Iterator<V>, Enumeration<V> {
+ ValueIterator(Node<K, V>[] tab, int index, int size, int limit,
+ ConcurrentHashMap<K, V> map) {
+ super(tab, index, size, limit, map);
+ }
+
+ @Override
+ public final V next() {
+ Node<K, V> p;
+ if ((p = next) == null) {
+ throw new NoSuchElementException();
+ }
+ V v = p.val;
+ lastReturned = p;
+ advance();
+ return v;
+ }
+
+ @Override
+ public final V nextElement() {
+ return next();
+ }
}
- /**
- * Creates a new, empty map with a default initial capacity,
- * load factor, and concurrencyLevel.
- */
- public ConcurrentHashMap() {
- this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS);
+ static final class EntryIterator<K, V> extends BaseIterator<K, V>
+ implements Iterator<Map.Entry<K, V>> {
+ EntryIterator(Node<K, V>[] tab, int index, int size, int limit,
+ ConcurrentHashMap<K, V> map) {
+ super(tab, index, size, limit, map);
+ }
+
+ @Override
+ public final Map.Entry<K, V> next() {
+ Node<K, V> p;
+ if ((p = next) == null) {
+ throw new NoSuchElementException();
+ }
+ K k = p.key;
+ V v = p.val;
+ lastReturned = p;
+ advance();
+ return new MapEntry<K, V>(k, v, map);
+ }
}
/**
- * Creates a new map with the same mappings as the given map. The
- * map is created with a capacity of twice the number of mappings in
- * the given map or 11 (whichever is greater), and a default load factor
- * and concurrencyLevel.
- *
- * @param t the map
+ * Exported Entry for EntryIterator
*/
- public ConcurrentHashMap(Map<? extends K, ? extends V> t) {
- this(Math.max((int)(t.size() / DEFAULT_LOAD_FACTOR) + 1,
- 11),
- DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS);
- putAll(t);
+ static final class MapEntry<K, V> implements Map.Entry<K, V> {
+ final K key; // non-null
+ V val; // non-null
+ final ConcurrentHashMap<K, V> map;
+
+ MapEntry(K key, V val, ConcurrentHashMap<K, V> map) {
+ this.key = key;
+ this.val = val;
+ this.map = map;
+ }
+
+ @Override
+ public K getKey() {
+ return key;
+ }
+
+ @Override
+ public V getValue() {
+ return val;
+ }
+
+ public int hashCode() {
+ return key.hashCode() ^ val.hashCode();
+ }
+
+ public String toString() {
+ return key + "=" + val;
+ }
+
+ public boolean equals(Object o) {
+ Object k;
+ Object v;
+ Map.Entry<?, ?> e;
+ return o instanceof Entry &&
+ (k = (e = (Entry<?, ?>)o).getKey()) != null &&
+ (v = e.getValue()) != null &&
+ (k == key || map.myHashingStrategy.equals((K)k,key)) &&
+ (v == val || v.equals(val));
+ }
+
+ /**
+ * Sets our entry's value and writes through to the map. The
+ * value to return is somewhat arbitrary here. Since we do not
+ * necessarily track asynchronous changes, the most recent
+ * "previous" value could be different from what we return (or
+ * could even have been removed, in which case the put will
+ * re-establish). We do not and cannot guarantee more.
+ */
+ @Override
+ public V setValue(V value) {
+ if (value == null) throw new NullPointerException();
+ V v = val;
+ val = value;
+ map.put(key, value);
+ return v;
+ }
}
- // inherit Map javadoc
- @Override
- public boolean isEmpty() {
- final Segment[] segments = this.segments;
- /*
- * We keep track of per-segment modCounts to avoid ABA
- * problems in which an element in one segment was added and
- * in another removed during traversal, in which case the
- * table was never actually empty at any point. Note the
- * similar use of modCounts in the size() and containsValue()
- * methods, which are the only other methods also susceptible
- * to ABA problems.
- */
- int[] mc = new int[segments.length];
- int mcsum = 0;
- for (int i = 0; i < segments.length; ++i) {
- if (segments[i].count != 0) {
+ static final class KeySpliterator<K, V> extends Traverser<K, V>
+ implements ConcurrentHashMapSpliterator<K> {
+ long est; // size estimate
+
+ KeySpliterator(Node<K, V>[] tab, int size, int index, int limit,
+ long est) {
+ super(tab, size, index, limit);
+ this.est = est;
+ }
+
+ @Override
+ public ConcurrentHashMapSpliterator<K> trySplit() {
+ int i;
+ int f;
+ int h;
+ return (h = (i = baseIndex) + (f = baseLimit) >>> 1) <= i ? null :
+ new KeySpliterator<K, V>(tab, baseSize, baseLimit = h,
+ f, est >>>= 1);
+ }
+
+ @Override
+ public void forEachRemaining(Action<? super K> action) {
+ if (action == null) throw new NullPointerException();
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ action.apply(p.key);
+ }
+ }
+
+ @Override
+ public boolean tryAdvance(Action<? super K> action) {
+ if (action == null) throw new NullPointerException();
+ Node<K, V> p;
+ if ((p = advance()) == null) {
return false;
}
- else {
- mcsum += mc[i] = segments[i].modCount;
+ action.apply(p.key);
+ return true;
+ }
+
+ @Override
+ public long estimateSize() {
+ return est;
+ }
+ }
+
+ static final class ValueSpliterator<K, V> extends Traverser<K, V>
+ implements ConcurrentHashMapSpliterator<V> {
+ long est; // size estimate
+
+ ValueSpliterator(Node<K, V>[] tab, int size, int index, int limit,
+ long est) {
+ super(tab, size, index, limit);
+ this.est = est;
+ }
+
+ @Override
+ public ConcurrentHashMapSpliterator<V> trySplit() {
+ int i;
+ int f;
+ int h;
+ return (h = (i = baseIndex) + (f = baseLimit) >>> 1) <= i ? null :
+ new ValueSpliterator<K, V>(tab, baseSize, baseLimit = h,
+ f, est >>>= 1);
+ }
+
+ @Override
+ public void forEachRemaining(Action<? super V> action) {
+ if (action == null) throw new NullPointerException();
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ action.apply(p.val);
}
}
- // If mcsum happens to be zero, then we know we got a snapshot
- // before any modifications at all were made. This is
- // probably common enough to bother tracking.
- if (mcsum != 0) {
- for (int i = 0; i < segments.length; ++i) {
- if (segments[i].count != 0 ||
- mc[i] != segments[i].modCount) {
- return false;
- }
+
+ @Override
+ public boolean tryAdvance(Action<? super V> action) {
+ if (action == null) throw new NullPointerException();
+ Node<K, V> p;
+ if ((p = advance()) == null) {
+ return false;
}
+ action.apply(p.val);
+ return true;
+ }
+
+ @Override
+ public long estimateSize() {
+ return est;
}
- return true;
}
- // inherit Map javadoc
- @Override
- public int size() {
- final Segment[] segments = this.segments;
- long sum = 0;
- long check = 0;
- int[] mc = new int[segments.length];
- // Try a few times to get accurate count. On failure due to
- // continuous async changes in table, resort to locking.
- for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) {
- check = 0;
- sum = 0;
- int mcsum = 0;
- for (int i = 0; i < segments.length; ++i) {
- sum += segments[i].count;
- mcsum += mc[i] = segments[i].modCount;
- }
- if (mcsum != 0) {
- for (int i = 0; i < segments.length; ++i) {
- check += segments[i].count;
- if (mc[i] != segments[i].modCount) {
- check = -1; // force retry
- break;
- }
- }
+ static final class EntrySpliterator<K, V> extends Traverser<K, V>
+ implements ConcurrentHashMapSpliterator<Map.Entry<K, V>> {
+ final ConcurrentHashMap<K, V> map; // To export MapEntry
+ long est; // size estimate
+
+ EntrySpliterator(Node<K, V>[] tab, int size, int index, int limit,
+ long est, ConcurrentHashMap<K, V> map) {
+ super(tab, size, index, limit);
+ this.map = map;
+ this.est = est;
+ }
+
+ @Override
+ public ConcurrentHashMapSpliterator<Map.Entry<K, V>> trySplit() {
+ int i;
+ int f;
+ int h;
+ return (h = (i = baseIndex) + (f = baseLimit) >>> 1) <= i ? null :
+ new EntrySpliterator<K, V>(tab, baseSize, baseLimit = h,
+ f, est >>>= 1, map);
+ }
+
+ @Override
+ public void forEachRemaining(Action<? super Map.Entry<K, V>> action) {
+ if (action == null) throw new NullPointerException();
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ action.apply(new MapEntry<K, V>(p.key, p.val, map));
}
- if (check == sum) {
- break;
+ }
+
+ @Override
+ public boolean tryAdvance(Action<? super Map.Entry<K, V>> action) {
+ if (action == null) throw new NullPointerException();
+ Node<K, V> p;
+ if ((p = advance()) == null) {
+ return false;
}
+ action.apply(new MapEntry<K, V>(p.key, p.val, map));
+ return true;
}
- if (check != sum) { // Resort to locking all segments
- sum = 0;
- for (Segment segment : segments) segment.lock();
- for (Segment segment : segments) sum += segment.count;
- for (Segment segment : segments) segment.unlock();
+
+ @Override
+ public long estimateSize() {
+ return est;
}
- return sum > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)sum;
}
+ // Parallel bulk operations
/**
- * Returns the value to which the specified key is mapped in this table.
+ * Computes initial batch value for bulk tasks. The returned value
+ * is approximately exp2 of the number of times (minus one) to
+ * split task by two before executing leaf action. This value is
+ * faster to compute and more convenient to use as a guide to
+ * splitting than is the depth, since it is used while dividing by
+ * two anyway.
+ */
+ final int batchFor(long b) {
+ long n;
+ if (b == Long.MAX_VALUE || (n = sumCount()) <= 1L || n < b) {
+ return 0;
+ }
+ int sp = ForkJoinPool.getCommonPoolParallelism() << 2; // slack of 4
+ return b <= 0L || (n /= b) >= sp ? sp : (int)n;
+ }
+
+ /**
+ * Performs the given action for each (key, value).
*
- * @param key a key in the table.
- * @return the value to which the key is mapped in this table;
- * <tt>null</tt> if the key is not mapped to any value in
- * this table.
- * @throws NullPointerException if the key is
- * <tt>null</tt>.
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param action the action
+ * @since 1.8
*/
- @Override
- public V get(Object key) {
- int hash = myHashingStrategy.computeHashCode((K)key); // throws NullPointerException if key null
- return segmentFor(hash).get((K)key, hash);
+ public void forEach(long parallelismThreshold,
+ BiAction<? super K, ? super V> action) {
+ if (action == null) throw new NullPointerException();
+ new ForEachMappingTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ action).invoke();
}
/**
- * Tests if the specified object is a key in this table.
+ * Performs the given action for each non-null transformation
+ * of each (key, value).
*
- * @param key possible key.
- * @return <tt>true</tt> if and only if the specified object
- * is a key in this table, as determined by the
- * <tt>equals</tt> method; <tt>false</tt> otherwise.
- * @throws NullPointerException if the key is
- * <tt>null</tt>.
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element, or null if there is no transformation (in
+ * which case the action is not applied)
+ * @param action the action
+ * @since 1.8
*/
- @Override
- public boolean containsKey(Object key) {
- int hash = myHashingStrategy.computeHashCode((K)key); // throws NullPointerException if key null
- return segmentFor(hash).containsKey((K)key, hash);
+ public <U> void forEach(long parallelismThreshold,
+ BiFun<? super K, ? super V, ? extends U> transformer,
+ Action<? super U> action) {
+ if (transformer == null || action == null) {
+ throw new NullPointerException();
+ }
+ new ForEachTransformedMappingTask<K, V, U>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ transformer, action).invoke();
}
/**
- * Returns <tt>true</tt> if this map maps one or more keys to the
- * specified value. Note: This method requires a full internal
- * traversal of the hash table, and so is much slower than
- * method <tt>containsKey</tt>.
+ * Returns a non-null result from applying the given search
+ * function on each (key, value), or null if none. Upon
+ * success, further element processing is suppressed and the
+ * results of any other parallel invocations of the search
+ * function are ignored.
*
- * @param value value whose presence in this map is to be tested.
- * @return <tt>true</tt> if this map maps one or more keys to the
- * specified value.
- * @throws NullPointerException if the value is <tt>null</tt>.
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param searchFunction a function returning a non-null
+ * result on success, else null
+ * @return a non-null result from applying the given search
+ * function on each (key, value), or null if none
+ * @since 1.8
*/
- @Override
- public boolean containsValue(@NotNull Object value) {
- // See explanation of modCount use above
-
- final Segment[] segments = this.segments;
- int[] mc = new int[segments.length];
-
- // Try a few times without locking
- for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) {
- int sum = 0;
- int mcsum = 0;
- for (int i = 0; i < segments.length; ++i) {
- int c = segments[i].count;
- mcsum += mc[i] = segments[i].modCount;
- if (segments[i].containsValue(value)) {
- return true;
- }
- }
- boolean cleanSweep = true;
- if (mcsum != 0) {
- for (int i = 0; i < segments.length; ++i) {
- int c = segments[i].count;
- if (mc[i] != segments[i].modCount) {
- cleanSweep = false;
- break;
- }
- }
- }
- if (cleanSweep) {
- return false;
- }
+ public <U> U search(long parallelismThreshold,
+ BiFun<? super K, ? super V, ? extends U> searchFunction) {
+ if (searchFunction == null) throw new NullPointerException();
+ return new SearchMappingsTask<K, V, U>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ searchFunction, new AtomicReference<U>()).invoke();
+ }
+
+ /**
+ * Returns the result of accumulating the given transformation
+ * of all (key, value) pairs using the given reducer to
+ * combine values, or null if none.
+ *
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element, or null if there is no transformation (in
+ * which case it is not combined)
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating the given transformation
+ * of all (key, value) pairs
+ * @since 1.8
+ */
+ public <U> U reduce(long parallelismThreshold,
+ BiFun<? super K, ? super V, ? extends U> transformer,
+ BiFun<? super U, ? super U, ? extends U> reducer) {
+ if (transformer == null || reducer == null) {
+ throw new NullPointerException();
}
- // Resort to locking all segments
- for (Segment segment : segments) {
- segment.lock();
+ return new MapReduceMappingsTask<K, V, U>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, transformer, reducer).invoke();
+ }
+
+ /**
+ * Returns the result of accumulating the given transformation
+ * of all (key, value) pairs using the given reducer to
+ * combine values, and the given basis as an identity value.
+ *
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element
+ * @param basis the identity (initial default value) for the reduction
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating the given transformation
+ * of all (key, value) pairs
+ * @since 1.8
+ */
+ public double reduceToDouble(long parallelismThreshold,
+ ObjectByObjectToDouble<? super K, ? super V> transformer,
+ double basis,
+ DoubleByDoubleToDouble reducer) {
+ if (transformer == null || reducer == null) {
+ throw new NullPointerException();
}
- boolean found = false;
- try {
- for (Segment segment : segments) {
- if (segment.containsValue(value)) {
- found = true;
- break;
- }
- }
+ return new MapReduceMappingsToDoubleTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, transformer, basis, reducer).invoke();
+ }
+
+ /**
+ * Returns the result of accumulating the given transformation
+ * of all (key, value) pairs using the given reducer to
+ * combine values, and the given basis as an identity value.
+ *
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element
+ * @param basis the identity (initial default value) for the reduction
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating the given transformation
+ * of all (key, value) pairs
+ * @since 1.8
+ */
+ public long reduceToLong(long parallelismThreshold,
+ ObjectByObjectToLong<? super K, ? super V> transformer,
+ long basis,
+ LongByLongToLong reducer) {
+ if (transformer == null || reducer == null) {
+ throw new NullPointerException();
}
- finally {
- for (Segment segment : segments) {
- segment.unlock();
- }
+ return new MapReduceMappingsToLongTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, transformer, basis, reducer).invoke();
+ }
+
+ /**
+ * Returns the result of accumulating the given transformation
+ * of all (key, value) pairs using the given reducer to
+ * combine values, and the given basis as an identity value.
+ *
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element
+ * @param basis the identity (initial default value) for the reduction
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating the given transformation
+ * of all (key, value) pairs
+ * @since 1.8
+ */
+ public int reduceToInt(long parallelismThreshold,
+ ObjectByObjectToInt<? super K, ? super V> transformer,
+ int basis,
+ IntByIntToInt reducer) {
+ if (transformer == null || reducer == null) {
+ throw new NullPointerException();
}
- return found;
+ return new MapReduceMappingsToIntTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, transformer, basis, reducer).invoke();
}
/**
- * Legacy method testing if some key maps into the specified value
- * in this table. This method is identical in functionality to
- * {@link #containsValue}, and exists solely to ensure
- * full compatibility with class {@link java.util.Hashtable},
- * which supported this method prior to introduction of the
- * Java Collections framework.
+ * Performs the given action for each key.
*
- * @param value a value to search for.
- * @return <tt>true</tt> if and only if some key maps to the
- * <tt>value</tt> argument in this table as
- * determined by the <tt>equals</tt> method;
- * <tt>false</tt> otherwise.
- * @throws NullPointerException if the value is <tt>null</tt>.
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param action the action
+ * @since 1.8
*/
- public boolean contains(Object value) {
- return containsValue(value);
+ public void forEachKey(long parallelismThreshold,
+ Action<? super K> action) {
+ if (action == null) throw new NullPointerException();
+ new ForEachKeyTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ action).invoke();
}
/**
- * Maps the specified <tt>key</tt> to the specified
- * <tt>value</tt> in this table. Neither the key nor the
- * value can be <tt>null</tt>.
- * <p/>
- * <p> The value can be retrieved by calling the <tt>get</tt> method
- * with a key that is equal to the original key.
+ * Performs the given action for each non-null transformation
+ * of each key.
*
- * @param key the table key.
- * @param value the value.
- * @return the previous value of the specified key in this table,
- * or <tt>null</tt> if it did not have one.
- * @throws NullPointerException if the key or value is
- * <tt>null</tt>.
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element, or null if there is no transformation (in
+ * which case the action is not applied)
+ * @param action the action
+ * @since 1.8
*/
- @Override
- public V put(K key, @NotNull V value) {
- int hash = myHashingStrategy.computeHashCode(key);
- return segmentFor(hash).put(key, hash, value, false);
- }
-
- /**
- * If the specified key is not already associated
- * with a value, associate it with the given value.
- * This is equivalent to
- * <pre>
- * if (!map.containsKey(key))
- * return map.put(key, value);
- * else
- * return map.get(key);
- * </pre>
- * Except that the action is performed atomically.
- *
- * @param key key with which the specified value is to be associated.
- * @param value value to be associated with the specified key.
- * @return previous value associated with specified key, or <tt>null</tt>
- * if there was no mapping for key.
- * @throws NullPointerException if the specified key or value is
- * <tt>null</tt>.
+ public <U> void forEachKey(long parallelismThreshold,
+ Fun<? super K, ? extends U> transformer,
+ Action<? super U> action) {
+ if (transformer == null || action == null) {
+ throw new NullPointerException();
+ }
+ new ForEachTransformedKeyTask<K, V, U>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ transformer, action).invoke();
+ }
+
+ /**
+ * Returns a non-null result from applying the given search
+ * function on each key, or null if none. Upon success,
+ * further element processing is suppressed and the results of
+ * any other parallel invocations of the search function are
+ * ignored.
+ *
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param searchFunction a function returning a non-null
+ * result on success, else null
+ * @return a non-null result from applying the given search
+ * function on each key, or null if none
+ * @since 1.8
*/
- @Override
- public V putIfAbsent(@NotNull K key, @NotNull V value) {
- int hash = myHashingStrategy.computeHashCode(key);
- return segmentFor(hash).put(key, hash, value, true);
+ public <U> U searchKeys(long parallelismThreshold,
+ Fun<? super K, ? extends U> searchFunction) {
+ if (searchFunction == null) throw new NullPointerException();
+ return new SearchKeysTask<K, V, U>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ searchFunction, new AtomicReference<U>()).invoke();
}
+ /**
+ * Returns the result of accumulating all keys using the given
+ * reducer to combine values, or null if none.
+ *
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating all keys using the given
+ * reducer to combine values, or null if none
+ * @since 1.8
+ */
+ public K reduceKeys(long parallelismThreshold,
+ BiFun<? super K, ? super K, ? extends K> reducer) {
+ if (reducer == null) throw new NullPointerException();
+ return new ReduceKeysTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, reducer).invoke();
+ }
/**
- * Copies all of the mappings from the specified map to this one.
- * <p/>
- * These mappings replace any mappings that this map had for any of the
- * keys currently in the specified Map.
+ * Returns the result of accumulating the given transformation
+ * of all keys using the given reducer to combine values, or
+ * null if none.
*
- * @param t Mappings to be stored in this map.
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element, or null if there is no transformation (in
+ * which case it is not combined)
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating the given transformation
+ * of all keys
+ * @since 1.8
*/
- @Override
- public void putAll(@NotNull Map<? extends K, ? extends V> t) {
- for (
- Iterator<? extends Entry<? extends K, ? extends V>> it = (Iterator<? extends Entry<? extends K, ? extends V>>)t.entrySet().iterator();
- it.hasNext(); ) {
- Entry<? extends K, ? extends V> e = it.next();
- put(e.getKey(), e.getValue());
+ public <U> U reduceKeys(long parallelismThreshold,
+ Fun<? super K, ? extends U> transformer,
+ BiFun<? super U, ? super U, ? extends U> reducer) {
+ if (transformer == null || reducer == null) {
+ throw new NullPointerException();
}
+ return new MapReduceKeysTask<K, V, U>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, transformer, reducer).invoke();
}
/**
- * Removes the key (and its corresponding value) from this
- * table. This method does nothing if the key is not in the table.
+ * Returns the result of accumulating the given transformation
+ * of all keys using the given reducer to combine values, and
+ * the given basis as an identity value.
*
- * @param key the key that needs to be removed.
- * @return the value to which the key had been mapped in this table,
- * or <tt>null</tt> if the key did not have a mapping.
- * @throws NullPointerException if the key is
- * <tt>null</tt>.
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element
+ * @param basis the identity (initial default value) for the reduction
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating the given transformation
+ * of all keys
+ * @since 1.8
*/
- @Override
- public V remove(Object key) {
- int hash = myHashingStrategy.computeHashCode((K)key);
- return segmentFor(hash).remove((K)key, hash, null);
+ public double reduceKeysToDouble(long parallelismThreshold,
+ ObjectToDouble<? super K> transformer,
+ double basis,
+ DoubleByDoubleToDouble reducer) {
+ if (transformer == null || reducer == null) {
+ throw new NullPointerException();
+ }
+ return new MapReduceKeysToDoubleTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, transformer, basis, reducer).invoke();
}
/**
- * Remove entry for key only if currently mapped to given value.
- * Acts as
- * <pre>
- * if (map.get(key).equals(value)) {
- * map.remove(key);
- * return true;
- * } else return false;
- * </pre>
- * except that the action is performed atomically.
+ * Returns the result of accumulating the given transformation
+ * of all keys using the given reducer to combine values, and
+ * the given basis as an identity value.
*
- * @param key key with which the specified value is associated.
- * @param value value associated with the specified key.
- * @return true if the value was removed
- * @throws NullPointerException if the specified key is
- * <tt>null</tt>.
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element
+ * @param basis the identity (initial default value) for the reduction
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating the given transformation
+ * of all keys
+ * @since 1.8
*/
- @Override
- public boolean remove(@NotNull Object key, Object value) {
- int hash = myHashingStrategy.computeHashCode((K)key);
- return remove((K)key, hash, (V)value);
+ public long reduceKeysToLong(long parallelismThreshold,
+ ObjectToLong<? super K> transformer,
+ long basis,
+ LongByLongToLong reducer) {
+ if (transformer == null || reducer == null) {
+ throw new NullPointerException();
+ }
+ return new MapReduceKeysToLongTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, transformer, basis, reducer).invoke();
}
- public boolean remove(@NotNull K key, int hash, V value) {
- return segmentFor(hash).remove(key, hash, value) != null;
+ /**
+ * Returns the result of accumulating the given transformation
+ * of all keys using the given reducer to combine values, and
+ * the given basis as an identity value.
+ *
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element
+ * @param basis the identity (initial default value) for the reduction
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating the given transformation
+ * of all keys
+ * @since 1.8
+ */
+ public int reduceKeysToInt(long parallelismThreshold,
+ ObjectToInt<? super K> transformer,
+ int basis,
+ IntByIntToInt reducer) {
+ if (transformer == null || reducer == null) {
+ throw new NullPointerException();
+ }
+ return new MapReduceKeysToIntTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, transformer, basis, reducer).invoke();
}
/**
- * Replace entry for key only if currently mapped to given value.
- * Acts as
- * <pre>
- * if (map.get(key).equals(oldValue)) {
- * map.put(key, newValue);
- * return true;
- * } else return false;
- * </pre>
- * except that the action is performed atomically.
+ * Performs the given action for each value.
*
- * @param key key with which the specified value is associated.
- * @param oldValue value expected to be associated with the specified key.
- * @param newValue value to be associated with the specified key.
- * @return true if the value was replaced
- * @throws NullPointerException if the specified key or values are
- * <tt>null</tt>.
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param action the action
+ * @since 1.8
*/
- @Override
- public boolean replace(@NotNull K key, @NotNull V oldValue, @NotNull V newValue) {
- int hash = myHashingStrategy.computeHashCode(key);
- return segmentFor(hash).replace(key, hash, oldValue, newValue);
+ public void forEachValue(long parallelismThreshold,
+ Action<? super V> action) {
+ if (action == null) {
+ throw new NullPointerException();
+ }
+ new ForEachValueTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ action).invoke();
}
/**
- * Replace entry for key only if currently mapped to some value.
- * Acts as
- * <pre>
- * if ((map.containsKey(key)) {
- * return map.put(key, value);
- * } else return null;
- * </pre>
- * except that the action is performed atomically.
+ * Performs the given action for each non-null transformation
+ * of each value.
*
- * @param key key with which the specified value is associated.
- * @param value value to be associated with the specified key.
- * @return previous value associated with specified key, or <tt>null</tt>
- * if there was no mapping for key.
- * @throws NullPointerException if the specified key or value is
- * <tt>null</tt>.
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element, or null if there is no transformation (in
+ * which case the action is not applied)
+ * @param action the action
+ * @since 1.8
*/
- @Override
- public V replace(@NotNull K key, @NotNull V value) {
- int hash = myHashingStrategy.computeHashCode(key);
- return segmentFor(hash).replace(key, hash, value);
+ public <U> void forEachValue(long parallelismThreshold,
+ Fun<? super V, ? extends U> transformer,
+ Action<? super U> action) {
+ if (transformer == null || action == null) {
+ throw new NullPointerException();
+ }
+ new ForEachTransformedValueTask<K, V, U>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ transformer, action).invoke();
}
+ /**
+ * Returns a non-null result from applying the given search
+ * function on each value, or null if none. Upon success,
+ * further element processing is suppressed and the results of
+ * any other parallel invocations of the search function are
+ * ignored.
+ *
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param searchFunction a function returning a non-null
+ * result on success, else null
+ * @return a non-null result from applying the given search
+ * function on each value, or null if none
+ * @since 1.8
+ */
+ public <U> U searchValues(long parallelismThreshold,
+ Fun<? super V, ? extends U> searchFunction) {
+ if (searchFunction == null) throw new NullPointerException();
+ return new SearchValuesTask<K, V, U>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ searchFunction, new AtomicReference<U>()).invoke();
+ }
/**
- * Removes all mappings from this map.
+ * Returns the result of accumulating all values using the
+ * given reducer to combine values, or null if none.
+ *
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating all values
+ * @since 1.8
*/
- @Override
- public void clear() {
- for (Segment segment : segments) segment.clear();
+ public V reduceValues(long parallelismThreshold,
+ BiFun<? super V, ? super V, ? extends V> reducer) {
+ if (reducer == null) throw new NullPointerException();
+ return new ReduceValuesTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, reducer).invoke();
}
/**
- * Returns a set view of the keys contained in this map. The set is
- * backed by the map, so changes to the map are reflected in the set, and
- * vice-versa. The set supports element removal, which removes the
- * corresponding mapping from this map, via the <tt>Iterator.remove</tt>,
- * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
- * <tt>clear</tt> operations. It does not support the <tt>add</tt> or
- * <tt>addAll</tt> operations.
- * The view's returned <tt>iterator</tt> is a "weakly consistent" iterator that
- * will never throw {@link java.util.ConcurrentModificationException},
- * and guarantees to traverse elements as they existed upon
- * construction of the iterator, and may (but is not guaranteed to)
- * reflect any modifications subsequent to construction.
+ * Returns the result of accumulating the given transformation
+ * of all values using the given reducer to combine values, or
+ * null if none.
*
- * @return a set view of the keys contained in this map.
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element, or null if there is no transformation (in
+ * which case it is not combined)
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating the given transformation
+ * of all values
+ * @since 1.8
*/
- @NotNull
- @Override
- public Set<K> keySet() {
- Set<K> ks = keySet;
- return ks != null ? ks : (keySet = new KeySet());
+ public <U> U reduceValues(long parallelismThreshold,
+ Fun<? super V, ? extends U> transformer,
+ BiFun<? super U, ? super U, ? extends U> reducer) {
+ if (transformer == null || reducer == null) {
+ throw new NullPointerException();
+ }
+ return new MapReduceValuesTask<K, V, U>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, transformer, reducer).invoke();
+ }
+
+ /**
+ * Returns the result of accumulating the given transformation
+ * of all values using the given reducer to combine values,
+ * and the given basis as an identity value.
+ *
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element
+ * @param basis the identity (initial default value) for the reduction
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating the given transformation
+ * of all values
+ * @since 1.8
+ */
+ public double reduceValuesToDouble(long parallelismThreshold,
+ ObjectToDouble<? super V> transformer,
+ double basis,
+ DoubleByDoubleToDouble reducer) {
+ if (transformer == null || reducer == null) {
+ throw new NullPointerException();
+ }
+ return new MapReduceValuesToDoubleTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, transformer, basis, reducer).invoke();
}
+ /**
+ * Returns the result of accumulating the given transformation
+ * of all values using the given reducer to combine values,
+ * and the given basis as an identity value.
+ *
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element
+ * @param basis the identity (initial default value) for the reduction
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating the given transformation
+ * of all values
+ * @since 1.8
+ */
+ public long reduceValuesToLong(long parallelismThreshold,
+ ObjectToLong<? super V> transformer,
+ long basis,
+ LongByLongToLong reducer) {
+ if (transformer == null || reducer == null) {
+ throw new NullPointerException();
+ }
+ return new MapReduceValuesToLongTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, transformer, basis, reducer).invoke();
+ }
/**
- * Returns a collection view of the values contained in this map. The
- * collection is backed by the map, so changes to the map are reflected in
- * the collection, and vice-versa. The collection supports element
- * removal, which removes the corresponding mapping from this map, via the
- * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
- * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
- * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
- * The view's returned <tt>iterator</tt> is a "weakly consistent" iterator that
- * will never throw {@link java.util.ConcurrentModificationException},
- * and guarantees to traverse elements as they existed upon
- * construction of the iterator, and may (but is not guaranteed to)
- * reflect any modifications subsequent to construction.
+ * Returns the result of accumulating the given transformation
+ * of all values using the given reducer to combine values,
+ * and the given basis as an identity value.
*
- * @return a collection view of the values contained in this map.
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element
+ * @param basis the identity (initial default value) for the reduction
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating the given transformation
+ * of all values
+ * @since 1.8
*/
- @NotNull
- @Override
- public Collection<V> values() {
- Collection<V> vs = values;
- return vs == null ? (values = new Values()) : vs;
+ public int reduceValuesToInt(long parallelismThreshold,
+ ObjectToInt<? super V> transformer,
+ int basis,
+ IntByIntToInt reducer) {
+ if (transformer == null || reducer == null) {
+ throw new NullPointerException();
+ }
+ return new MapReduceValuesToIntTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, transformer, basis, reducer).invoke();
}
+ /**
+ * Performs the given action for each entry.
+ *
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param action the action
+ * @since 1.8
+ */
+ public void forEachEntry(long parallelismThreshold,
+ Action<? super Map.Entry<K, V>> action) {
+ if (action == null) throw new NullPointerException();
+ new ForEachEntryTask<K, V>(null, batchFor(parallelismThreshold), 0, 0, table,
+ action).invoke();
+ }
/**
- * Returns a collection view of the mappings contained in this map. Each
- * element in the returned collection is a <tt>Map.Entry</tt>. The
- * collection is backed by the map, so changes to the map are reflected in
- * the collection, and vice-versa. The collection supports element
- * removal, which removes the corresponding mapping from the map, via the
- * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
- * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
- * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
- * The view's returned <tt>iterator</tt> is a "weakly consistent" iterator that
- * will never throw {@link java.util.ConcurrentModificationException},
- * and guarantees to traverse elements as they existed upon
- * construction of the iterator, and may (but is not guaranteed to)
- * reflect any modifications subsequent to construction.
+ * Performs the given action for each non-null transformation
+ * of each entry.
*
- * @return a collection view of the mappings contained in this map.
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element, or null if there is no transformation (in
+ * which case the action is not applied)
+ * @param action the action
+ * @since 1.8
*/
- @NotNull
- @Override
- public Set<Entry<K, V>> entrySet() {
- Set<Entry<K, V>> es = entrySet;
- return es != null ? es : (entrySet = (Set<Entry<K, V>>)(Set)new EntrySet());
+ public <U> void forEachEntry(long parallelismThreshold,
+ Fun<Map.Entry<K, V>, ? extends U> transformer,
+ Action<? super U> action) {
+ if (transformer == null || action == null) {
+ throw new NullPointerException();
+ }
+ new ForEachTransformedEntryTask<K, V, U>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ transformer, action).invoke();
}
+ /**
+ * Returns a non-null result from applying the given search
+ * function on each entry, or null if none. Upon success,
+ * further element processing is suppressed and the results of
+ * any other parallel invocations of the search function are
+ * ignored.
+ *
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param searchFunction a function returning a non-null
+ * result on success, else null
+ * @return a non-null result from applying the given search
+ * function on each entry, or null if none
+ * @since 1.8
+ */
+ public <U> U searchEntries(long parallelismThreshold,
+ Fun<Map.Entry<K, V>, ? extends U> searchFunction) {
+ if (searchFunction == null) throw new NullPointerException();
+ return new SearchEntriesTask<K, V, U>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ searchFunction, new AtomicReference<U>()).invoke();
+ }
/**
- * Returns an enumeration of the keys in this table.
+ * Returns the result of accumulating all entries using the
+ * given reducer to combine values, or null if none.
*
- * @return an enumeration of the keys in this table.
- * @see #keySet
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating all entries
+ * @since 1.8
*/
- public Enumeration<K> keys() {
- return new KeyIterator();
+ public Map.Entry<K, V> reduceEntries(long parallelismThreshold,
+ BiFun<Map.Entry<K, V>, Map.Entry<K, V>, ? extends Map.Entry<K, V>> reducer) {
+ if (reducer == null) throw new NullPointerException();
+ return new ReduceEntriesTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, reducer).invoke();
}
/**
- * Returns an enumeration of the values in this table.
+ * Returns the result of accumulating the given transformation
+ * of all entries using the given reducer to combine values,
+ * or null if none.
*
- * @return an enumeration of the values in this table.
- * @see #values
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element, or null if there is no transformation (in
+ * which case it is not combined)
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating the given transformation
+ * of all entries
+ * @since 1.8
*/
- public Enumeration<V> elements() {
- return new ValueIterator();
+ public <U> U reduceEntries(long parallelismThreshold,
+ Fun<Map.Entry<K, V>, ? extends U> transformer,
+ BiFun<? super U, ? super U, ? extends U> reducer) {
+ if (transformer == null || reducer == null) {
+ throw new NullPointerException();
+ }
+ return new MapReduceEntriesTask<K, V, U>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, transformer, reducer).invoke();
}
- /* ---------------- Iterator Support -------------- */
+ /**
+ * Returns the result of accumulating the given transformation
+ * of all entries using the given reducer to combine values,
+ * and the given basis as an identity value.
+ *
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element
+ * @param basis the identity (initial default value) for the reduction
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating the given transformation
+ * of all entries
+ * @since 1.8
+ */
+ public double reduceEntriesToDouble(long parallelismThreshold,
+ ObjectToDouble<Map.Entry<K, V>> transformer,
+ double basis,
+ DoubleByDoubleToDouble reducer) {
+ if (transformer == null || reducer == null) {
+ throw new NullPointerException();
+ }
+ return new MapReduceEntriesToDoubleTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, transformer, basis, reducer).invoke();
+ }
- private abstract class HashIterator {
- private int nextSegmentIndex;
- private int nextTableIndex;
- private HashEntry[] currentTable;
- private HashEntry<K, V> nextEntry;
- HashEntry<K, V> lastReturned;
+ /**
+ * Returns the result of accumulating the given transformation
+ * of all entries using the given reducer to combine values,
+ * and the given basis as an identity value.
+ *
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element
+ * @param basis the identity (initial default value) for the reduction
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating the given transformation
+ * of all entries
+ * @since 1.8
+ */
+ public long reduceEntriesToLong(long parallelismThreshold,
+ ObjectToLong<Map.Entry<K, V>> transformer,
+ long basis,
+ LongByLongToLong reducer) {
+ if (transformer == null || reducer == null) {
+ throw new NullPointerException();
+ }
+ return new MapReduceEntriesToLongTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, transformer, basis, reducer).invoke();
+ }
- private HashIterator() {
- nextSegmentIndex = segments.length - 1;
- nextTableIndex = -1;
- advance();
+ /**
+ * Returns the result of accumulating the given transformation
+ * of all entries using the given reducer to combine values,
+ * and the given basis as an identity value.
+ *
+ * @param parallelismThreshold the (estimated) number of elements
+ * needed for this operation to be executed in parallel
+ * @param transformer a function returning the transformation
+ * for an element
+ * @param basis the identity (initial default value) for the reduction
+ * @param reducer a commutative associative combining function
+ * @return the result of accumulating the given transformation
+ * of all entries
+ * @since 1.8
+ */
+ public int reduceEntriesToInt(long parallelismThreshold,
+ ObjectToInt<Map.Entry<K, V>> transformer,
+ int basis,
+ IntByIntToInt reducer) {
+ if (transformer == null || reducer == null) {
+ throw new NullPointerException();
}
+ return new MapReduceEntriesToIntTask<K, V>
+ (null, batchFor(parallelismThreshold), 0, 0, table,
+ null, transformer, basis, reducer).invoke();
+ }
+
+
+ /* ----------------Views -------------- */
- public boolean hasMoreElements() {
- return hasNext();
+ /**
+ * Base class for views.
+ */
+ abstract static class CollectionView<K, V, E>
+ implements Collection<E>, Serializable {
+ private static final long serialVersionUID = 7249069246763182397L;
+ final ConcurrentHashMap<K, V> map;
+
+ CollectionView(ConcurrentHashMap<K, V> map) {
+ this.map = map;
}
- private void advance() {
- if (nextEntry != null && (nextEntry = nextEntry.next) != null) {
- return;
+ /**
+ * Returns the map backing this view.
+ *
+ * @return the map backing this view
+ */
+ public ConcurrentHashMap<K, V> getMap() {
+ return map;
+ }
+
+ /**
+ * Removes all of the elements from this view, by removing all
+ * the mappings from the map backing this view.
+ */
+ @Override
+ public final void clear() {
+ map.clear();
+ }
+
+ @Override
+ public final int size() {
+ return map.size();
+ }
+
+ @Override
+ public final boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ // implementations below rely on concrete classes supplying these
+ // abstract methods
+
+ /**
+ * Returns a "weakly consistent" iterator that will never
+ * throw {@link ConcurrentModificationException}, and
+ * guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not
+ * guaranteed to) reflect any modifications subsequent to
+ * construction.
+ */
+ @NotNull
+ @Override
+ public abstract Iterator<E> iterator();
+
+ @Override
+ public abstract boolean contains(Object o);
+
+ @Override
+ public abstract boolean remove(Object o);
+
+ private static final String oomeMsg = "Required array size too large";
+
+ @NotNull
+ @Override
+ public final Object[] toArray() {
+ long sz = map.mappingCount();
+ if (sz > MAX_ARRAY_SIZE) {
+ throw new OutOfMemoryError(oomeMsg);
}
+ int n = (int)sz;
+ Object[] r = new Object[n];
+ int i = 0;
+ for (E e : this) {
+ if (i == n) {
+ if (n >= MAX_ARRAY_SIZE) {
+ throw new OutOfMemoryError(oomeMsg);
+ }
+ if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) {
+ n = MAX_ARRAY_SIZE;
+ }
+ else {
+ n += (n >>> 1) + 1;
+ }
+ r = Arrays.copyOf(r, n);
+ }
+ r[i++] = e;
+ }
+ return i == n ? r : Arrays.copyOf(r, i);
+ }
- while (nextTableIndex >= 0) {
- if ((nextEntry = (HashEntry<K, V>)currentTable[nextTableIndex--]) != null) {
- return;
+ @NotNull
+ @Override
+ @SuppressWarnings("unchecked")
+ public final <T> T[] toArray(@NotNull T[] a) {
+ long sz = map.mappingCount();
+ if (sz > MAX_ARRAY_SIZE) {
+ throw new OutOfMemoryError(oomeMsg);
+ }
+ int m = (int)sz;
+ T[] r = a.length >= m ? a :
+ (T[])Array
+ .newInstance(a.getClass().getComponentType(), m);
+ int n = r.length;
+ int i = 0;
+ for (E e : this) {
+ if (i == n) {
+ if (n >= MAX_ARRAY_SIZE) {
+ throw new OutOfMemoryError(oomeMsg);
+ }
+ if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1) {
+ n = MAX_ARRAY_SIZE;
+ }
+ else {
+ n += (n >>> 1) + 1;
+ }
+ r = Arrays.copyOf(r, n);
}
+ r[i++] = (T)e;
}
+ if (a == r && i < n) {
+ r[i] = null; // null-terminate
+ return r;
+ }
+ return i == n ? r : Arrays.copyOf(r, i);
+ }
- while (nextSegmentIndex >= 0) {
- Segment seg = segments[nextSegmentIndex--];
- if (seg.count != 0) {
- currentTable = seg.table;
- for (int j = currentTable.length - 1; j >= 0; --j) {
- if ((nextEntry = (HashEntry<K, V>)currentTable[j]) != null) {
- nextTableIndex = j - 1;
- return;
- }
+ /**
+ * Returns a string representation of this collection.
+ * The string representation consists of the string representations
+ * of the collection's elements in the order they are returned by
+ * its iterator, enclosed in square brackets ({@code "[]"}).
+ * Adjacent elements are separated by the characters {@code ", "}
+ * (comma and space). Elements are converted to strings as by
+ * {@link String#valueOf(Object)}.
+ *
+ * @return a string representation of this collection
+ */
+ public final String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append('[');
+ Iterator<E> it = iterator();
+ if (it.hasNext()) {
+ for (; ; ) {
+ Object e = it.next();
+ sb.append(e == this ? "(this Collection)" : e);
+ if (!it.hasNext()) {
+ break;
}
+ sb.append(',').append(' ');
}
}
+ return sb.append(']').toString();
}
- public boolean hasNext() {
- return nextEntry != null;
+ @Override
+ public final boolean containsAll(@NotNull Collection<?> c) {
+ if (c != this) {
+ for (Object e : c) {
+ if (e == null || !contains(e)) {
+ return false;
+ }
+ }
+ }
+ return true;
}
- HashEntry<K, V> nextEntry() {
- if (nextEntry == null) {
- throw new NoSuchElementException();
+ @Override
+ public final boolean removeAll(@NotNull Collection<?> c) {
+ boolean modified = false;
+ for (Iterator<E> it = iterator(); it.hasNext(); ) {
+ if (c.contains(it.next())) {
+ it.remove();
+ modified = true;
+ }
}
- lastReturned = nextEntry;
- advance();
- return lastReturned;
+ return modified;
}
- public void remove() {
- if (lastReturned == null) {
- throw new IllegalStateException();
+ @Override
+ public final boolean retainAll(@NotNull Collection<?> c) {
+ boolean modified = false;
+ for (Iterator<E> it = iterator(); it.hasNext(); ) {
+ if (!c.contains(it.next())) {
+ it.remove();
+ modified = true;
+ }
}
- ConcurrentHashMap.this.remove(lastReturned.key);
- lastReturned = null;
+ return modified;
}
}
- private final class KeyIterator extends HashIterator implements Iterator<K>, Enumeration<K> {
+ /**
+ * A view of a ConcurrentHashMapV8 as a {@link Set} of keys, in
+ * which additions may optionally be enabled by mapping to a
+ * common value. This class cannot be directly instantiated.
+ * See {@link #keySet() keySet()},
+ * {@link #keySet(Object) keySet(V)},
+ * {@link #newKeySet() newKeySet()},
+ * {@link #newKeySet(int) newKeySet(int)}.
+ *
+ * @since 1.8
+ */
+ public static class KeySetView<K, V> extends CollectionView<K, V, K>
+ implements Set<K>, Serializable {
+ private static final long serialVersionUID = 7249069246763182397L;
+ private final V value;
+
+ KeySetView(ConcurrentHashMap<K, V> map, V value) { // non-public
+ super(map);
+ this.value = value;
+ }
+
+ /**
+ * Returns the default mapped value for additions,
+ * or {@code null} if additions are not supported.
+ *
+ * @return the default mapped value for additions, or {@code null}
+ * if not supported
+ */
+ public V getMappedValue() {
+ return value;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws NullPointerException if the specified key is null
+ */
+ @Override
+ public boolean contains(Object o) {
+ return map.containsKey(o);
+ }
+
+ /**
+ * Removes the key from this map view, by removing the key (and its
+ * corresponding value) from the backing map. This method does
+ * nothing if the key is not in the map.
+ *
+ * @param o the key to be removed from the backing map
+ * @return {@code true} if the backing map contained the specified key
+ * @throws NullPointerException if the specified key is null
+ */
+ @Override
+ public boolean remove(Object o) {
+ return map.remove(o) != null;
+ }
+
+ /**
+ * @return an iterator over the keys of the backing map
+ */
+ @NotNull
+ @Override
+ public Iterator<K> iterator() {
+ Node<K, V>[] t;
+ ConcurrentHashMap<K, V> m = map;
+ int f = (t = m.table) == null ? 0 : t.length;
+ return new KeyIterator<K, V>(t, f, 0, f, m);
+ }
+
+ /**
+ * Adds the specified key to this set view by mapping the key to
+ * the default mapped value in the backing map, if defined.
+ *
+ * @param e key to be added
+ * @return {@code true} if this set changed as a result of the call
+ * @throws NullPointerException if the specified key is null
+ * @throws UnsupportedOperationException if no default mapped value
+ * for additions was provided
+ */
+ @Override
+ public boolean add(K e) {
+ V v;
+ if ((v = value) == null) {
+ throw new UnsupportedOperationException();
+ }
+ return map.putVal(e, v, true) == null;
+ }
+
+ /**
+ * Adds all of the elements in the specified collection to this set,
+ * as if by calling {@link #add} on each one.
+ *
+ * @param c the elements to be inserted into this set
+ * @return {@code true} if this set changed as a result of the call
+ * @throws NullPointerException if the collection or any of its
+ * elements are {@code null}
+ * @throws UnsupportedOperationException if no default mapped value
+ * for additions was provided
+ */
+ @Override
+ public boolean addAll(@NotNull Collection<? extends K> c) {
+ V v;
+ if ((v = value) == null) {
+ throw new UnsupportedOperationException();
+ }
+ boolean added = false;
+ for (K e : c) {
+ if (map.putVal(e, v, true) == null) {
+ added = true;
+ }
+ }
+ return added;
+ }
+
+ public int hashCode() {
+ int h = 0;
+ for (K e : this) {
+ h += e.hashCode();
+ }
+ return h;
+ }
+
+ public boolean equals(Object o) {
+ Set<?> c;
+ return o instanceof Set &&
+ ((c = (Set<?>)o) == this ||
+ containsAll(c) && c.containsAll(this));
+ }
+
+
+ public void forEach(Action<? super K> action) {
+ if (action == null) throw new NullPointerException();
+ Node<K, V>[] t;
+ if ((t = map.table) != null) {
+ Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
+ for (Node<K, V> p; (p = it.advance()) != null; ) {
+ action.apply(p.key);
+ }
+ }
+ }
+ }
+
+ /**
+ * A view of a ConcurrentHashMapV8 as a {@link Collection} of
+ * values, in which additions are disabled. This class cannot be
+ * directly instantiated. See {@link #values()}.
+ */
+ static final class ValuesView<K, V> extends CollectionView<K, V, V>
+ implements Collection<V>, Serializable {
+ private static final long serialVersionUID = 2249069246763182397L;
+
+ ValuesView(ConcurrentHashMap<K, V> map) {
+ super(map);
+ }
+
+ @Override
+ public final boolean contains(Object o) {
+ return map.containsValue(o);
+ }
+
+ @Override
+ public final boolean remove(Object o) {
+ if (o != null) {
+ for (Iterator<V> it = iterator(); it.hasNext(); ) {
+ if (o.equals(it.next())) {
+ it.remove();
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @NotNull
@Override
- public K next() {
- return super.nextEntry().key;
+ public final Iterator<V> iterator() {
+ ConcurrentHashMap<K, V> m = map;
+ Node<K, V>[] t;
+ int f = (t = m.table) == null ? 0 : t.length;
+ return new ValueIterator<K, V>(t, f, 0, f, m);
}
@Override
- public K nextElement() {
- return super.nextEntry().key;
+ public final boolean add(V e) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final boolean addAll(@NotNull Collection<? extends V> c) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public void forEach(Action<? super V> action) {
+ if (action == null) throw new NullPointerException();
+ Node<K, V>[] t;
+ if ((t = map.table) != null) {
+ Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
+ for (Node<K, V> p; (p = it.advance()) != null; ) {
+ action.apply(p.val);
+ }
+ }
}
}
- private final class ValueIterator extends HashIterator implements Iterator<V>, Enumeration<V> {
+ /**
+ * A view of a ConcurrentHashMapV8 as a {@link Set} of (key, value)
+ * entries. This class cannot be directly instantiated. See
+ * {@link #entrySet()}.
+ */
+ static final class EntrySetView<K, V> extends CollectionView<K, V, Map.Entry<K, V>>
+ implements Set<Map.Entry<K, V>>, Serializable {
+ private static final long serialVersionUID = 2249069246763182397L;
+
+ EntrySetView(ConcurrentHashMap<K, V> map) {
+ super(map);
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ Object k;
+ Object v;
+ Object r;
+ Map.Entry<?, ?> e;
+ return o instanceof Entry &&
+ (k = (e = (Entry<?, ?>)o).getKey()) != null &&
+ (r = map.get(k)) != null &&
+ (v = e.getValue()) != null &&
+ (v == r || v.equals(r));
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ Object k;
+ Object v;
+ Map.Entry<?, ?> e;
+ return o instanceof Entry &&
+ (k = (e = (Entry<?, ?>)o).getKey()) != null &&
+ (v = e.getValue()) != null &&
+ map.remove(k, v);
+ }
+
+ /**
+ * @return an iterator over the entries of the backing map
+ */
+ @NotNull
+ @Override
+ public Iterator<Map.Entry<K, V>> iterator() {
+ ConcurrentHashMap<K, V> m = map;
+ Node<K, V>[] t;
+ int f = (t = m.table) == null ? 0 : t.length;
+ return new EntryIterator<K, V>(t, f, 0, f, m);
+ }
+
@Override
- public V next() {
- return super.nextEntry().value;
+ public boolean add(Entry<K, V> e) {
+ return map.putVal(e.getKey(), e.getValue(), false) == null;
}
@Override
- public V nextElement() {
- return super.nextEntry().value;
+ public boolean addAll(@NotNull Collection<? extends Entry<K, V>> c) {
+ boolean added = false;
+ for (Entry<K, V> e : c) {
+ if (add(e)) {
+ added = true;
+ }
+ }
+ return added;
+ }
+
+ public final int hashCode() {
+ int h = 0;
+ Node<K, V>[] t;
+ if ((t = map.table) != null) {
+ Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
+ for (Node<K, V> p; (p = it.advance()) != null; ) {
+ h += p.hashCode();
+ }
+ }
+ return h;
+ }
+
+ public final boolean equals(Object o) {
+ Set<?> c;
+ return o instanceof Set &&
+ ((c = (Set<?>)o) == this ||
+ containsAll(c) && c.containsAll(this));
+ }
+
+
+ public void forEach(Action<? super Map.Entry<K, V>> action) {
+ if (action == null) throw new NullPointerException();
+ Node<K, V>[] t;
+ if ((t = map.table) != null) {
+ Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
+ for (Node<K, V> p; (p = it.advance()) != null; ) {
+ action.apply(new MapEntry<K, V>(p.key, p.val, map));
+ }
+ }
}
}
+ // -------------------------------------------------------
/**
- * Entry iterator. Exported Entry objects must write-through
- * changes in setValue, even if the nodes have been cloned. So we
- * cannot return internal HashEntry objects. Instead, the iterator
- * itself acts as a forwarding pseudo-entry.
+ * Base class for bulk tasks. Repeats some fields and code from
+ * class Traverser, because we need to subclass CountedCompleter.
+ */
+ abstract static class BulkTask<K, V, R> extends CountedCompleter<R> {
+ Node<K, V>[] tab; // same as Traverser
+ Node<K, V> next;
+ int index;
+ int baseIndex;
+ int baseLimit;
+ final int baseSize;
+ int batch; // split control
+
+ BulkTask(BulkTask<K, V, ?> par, int b, int i, int f, Node<K, V>[] t) {
+ super(par);
+ batch = b;
+ index = baseIndex = i;
+ if ((tab = t) == null) {
+ baseSize = baseLimit = 0;
+ }
+ else if (par == null) {
+ baseSize = baseLimit = t.length;
+ }
+ else {
+ baseLimit = f;
+ baseSize = par.baseSize;
+ }
+ }
+
+ /**
+ * Same as Traverser version
+ */
+ final Node<K, V> advance() {
+ Node<K, V> e;
+ if ((e = next) != null) {
+ e = e.next;
+ }
+ for (; ; ) {
+ if (e != null) {
+ return next = e;
+ }
+ Node<K, V>[] t;
+ int i;
+ int n;
+ if (baseIndex >= baseLimit || (t = tab) == null ||
+ (n = t.length) <= (i = index) || i < 0) {
+ return next = null;
+ }
+ if ((e = tabAt(t, index)) != null && e.hash < 0) {
+ if (e instanceof ForwardingNode) {
+ tab = ((ForwardingNode<K, V>)e).nextTable;
+ e = null;
+ continue;
+ }
+ else if (e instanceof TreeBin) {
+ e = ((TreeBin<K, V>)e).first;
+ }
+ else {
+ e = null;
+ }
+ }
+ if ((index += baseSize) >= n) {
+ index = ++baseIndex; // visit upper slots if present
+ }
+ }
+ }
+ }
+
+ /*
+ * Task classes. Coded in a regular but ugly format/style to
+ * simplify checks that each variant differs in the right way from
+ * others. The null screenings exist because compilers cannot tell
+ * that we've already null-checked task arguments, so we force
+ * simplest hoisted bypass to help avoid convoluted traps.
*/
- private final class EntryIterator extends HashIterator implements Entry<K, V>, Iterator<Entry<K, V>> {
+ @SuppressWarnings("serial")
+ static final class ForEachKeyTask<K, V>
+ extends BulkTask<K, V, Void> {
+ final Action<? super K> action;
+
+ ForEachKeyTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ Action<? super K> action) {
+ super(p, b, i, f, t);
+ this.action = action;
+ }
+
@Override
- public Entry<K, V> next() {
- nextEntry();
- return this;
+ public final void compute() {
+ final Action<? super K> action;
+ if ((action = this.action) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ new ForEachKeyTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ action).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ action.apply(p.key);
+ }
+ propagateCompletion();
+ }
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class ForEachValueTask<K, V>
+ extends BulkTask<K, V, Void> {
+ final Action<? super V> action;
+
+ ForEachValueTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ Action<? super V> action) {
+ super(p, b, i, f, t);
+ this.action = action;
}
@Override
- public K getKey() {
- if (lastReturned == null) {
- throw new IllegalStateException("Entry was removed");
+ public final void compute() {
+ final Action<? super V> action;
+ if ((action = this.action) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ new ForEachValueTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ action).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ action.apply(p.val);
+ }
+ propagateCompletion();
}
- return lastReturned.key;
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class ForEachEntryTask<K, V>
+ extends BulkTask<K, V, Void> {
+ final Action<? super Entry<K, V>> action;
+
+ ForEachEntryTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ Action<? super Entry<K, V>> action) {
+ super(p, b, i, f, t);
+ this.action = action;
}
@Override
- public V getValue() {
- if (lastReturned == null) {
- throw new IllegalStateException("Entry was removed");
+ public final void compute() {
+ final Action<? super Entry<K, V>> action;
+ if ((action = this.action) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ new ForEachEntryTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ action).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ action.apply(p);
+ }
+ propagateCompletion();
}
- return get(lastReturned.key);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class ForEachMappingTask<K, V>
+ extends BulkTask<K, V, Void> {
+ final BiAction<? super K, ? super V> action;
+
+ ForEachMappingTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ BiAction<? super K, ? super V> action) {
+ super(p, b, i, f, t);
+ this.action = action;
}
@Override
- public V setValue(V value) {
- if (lastReturned == null) {
- throw new IllegalStateException("Entry was removed");
+ public final void compute() {
+ final BiAction<? super K, ? super V> action;
+ if ((action = this.action) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ new ForEachMappingTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ action).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ action.apply(p.key, p.val);
+ }
+ propagateCompletion();
}
- return put(lastReturned.key, value);
}
+ }
- public boolean equals(Object o) {
- // If not acting as entry, just use default.
- if (lastReturned == null) {
- return super.equals(o);
+ @SuppressWarnings("serial")
+ static final class ForEachTransformedKeyTask<K, V, U>
+ extends BulkTask<K, V, Void> {
+ final Fun<? super K, ? extends U> transformer;
+ final Action<? super U> action;
+
+ ForEachTransformedKeyTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ Fun<? super K, ? extends U> transformer, Action<? super U> action) {
+ super(p, b, i, f, t);
+ this.transformer = transformer;
+ this.action = action;
+ }
+
+ @Override
+ public final void compute() {
+ final Fun<? super K, ? extends U> transformer;
+ final Action<? super U> action;
+ if ((transformer = this.transformer) != null &&
+ (action = this.action) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ new ForEachTransformedKeyTask<K, V, U>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ transformer, action).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ U u;
+ if ((u = transformer.apply(p.key)) != null) {
+ action.apply(u);
+ }
+ }
+ propagateCompletion();
}
- if (!(o instanceof Entry)) {
- return false;
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class ForEachTransformedValueTask<K, V, U>
+ extends BulkTask<K, V, Void> {
+ final Fun<? super V, ? extends U> transformer;
+ final Action<? super U> action;
+
+ ForEachTransformedValueTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ Fun<? super V, ? extends U> transformer, Action<? super U> action) {
+ super(p, b, i, f, t);
+ this.transformer = transformer;
+ this.action = action;
+ }
+
+ @Override
+ public final void compute() {
+ final Fun<? super V, ? extends U> transformer;
+ final Action<? super U> action;
+ if ((transformer = this.transformer) != null &&
+ (action = this.action) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ new ForEachTransformedValueTask<K, V, U>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ transformer, action).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ U u;
+ if ((u = transformer.apply(p.val)) != null) {
+ action.apply(u);
+ }
+ }
+ propagateCompletion();
}
- Entry e = (Entry)o;
- K o1 = getKey();
- K o2 = (K)e.getKey();
- return (o1 == null ? o2 == null : myHashingStrategy.equals(o1, o2)) && eq(getValue(), e.getValue());
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class ForEachTransformedEntryTask<K, V, U>
+ extends BulkTask<K, V, Void> {
+ final Fun<Map.Entry<K, V>, ? extends U> transformer;
+ final Action<? super U> action;
+
+ ForEachTransformedEntryTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ Fun<Map.Entry<K, V>, ? extends U> transformer, Action<? super U> action) {
+ super(p, b, i, f, t);
+ this.transformer = transformer;
+ this.action = action;
}
- public int hashCode() {
- // If not acting as entry, just use default.
- if (lastReturned == null) {
- return super.hashCode();
+ @Override
+ public final void compute() {
+ final Fun<Map.Entry<K, V>, ? extends U> transformer;
+ final Action<? super U> action;
+ if ((transformer = this.transformer) != null &&
+ (action = this.action) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ new ForEachTransformedEntryTask<K, V, U>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ transformer, action).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ U u;
+ if ((u = transformer.apply(p)) != null) {
+ action.apply(u);
+ }
+ }
+ propagateCompletion();
}
+ }
+ }
- Object k = getKey();
- Object v = getValue();
- return (k == null ? 0 : k.hashCode()) ^
- (v == null ? 0 : v.hashCode());
+ @SuppressWarnings("serial")
+ static final class ForEachTransformedMappingTask<K, V, U>
+ extends BulkTask<K, V, Void> {
+ final BiFun<? super K, ? super V, ? extends U> transformer;
+ final Action<? super U> action;
+
+ ForEachTransformedMappingTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ BiFun<? super K, ? super V, ? extends U> transformer,
+ Action<? super U> action) {
+ super(p, b, i, f, t);
+ this.transformer = transformer;
+ this.action = action;
}
- public String toString() {
- // If not acting as entry, just use default.
- if (lastReturned == null) {
- return super.toString();
+ @Override
+ public final void compute() {
+ final BiFun<? super K, ? super V, ? extends U> transformer;
+ final Action<? super U> action;
+ if ((transformer = this.transformer) != null &&
+ (action = this.action) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ new ForEachTransformedMappingTask<K, V, U>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ transformer, action).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ U u;
+ if ((u = transformer.apply(p.key, p.val)) != null) {
+ action.apply(u);
+ }
+ }
+ propagateCompletion();
}
- else {
- return getKey() + "=" + getValue();
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class SearchKeysTask<K, V, U>
+ extends BulkTask<K, V, U> {
+ final Fun<? super K, ? extends U> searchFunction;
+ final AtomicReference<U> result;
+
+ SearchKeysTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ Fun<? super K, ? extends U> searchFunction,
+ AtomicReference<U> result) {
+ super(p, b, i, f, t);
+ this.searchFunction = searchFunction;
+ this.result = result;
+ }
+
+ @Override
+ public final U getRawResult() {
+ return result.get();
+ }
+
+ @Override
+ public final void compute() {
+ final Fun<? super K, ? extends U> searchFunction;
+ final AtomicReference<U> result;
+ if ((searchFunction = this.searchFunction) != null &&
+ (result = this.result) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ if (result.get() != null) {
+ return;
+ }
+ addToPendingCount(1);
+ new SearchKeysTask<K, V, U>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ searchFunction, result).fork();
+ }
+ while (result.get() == null) {
+ Node<K, V> p;
+ if ((p = advance()) == null) {
+ propagateCompletion();
+ break;
+ }
+ U u;
+ if ((u = searchFunction.apply(p.key)) != null) {
+ if (result.compareAndSet(null, u)) {
+ quietlyCompleteRoot();
+ }
+ break;
+ }
+ }
}
}
+ }
+
+ @SuppressWarnings("serial")
+ static final class SearchValuesTask<K, V, U>
+ extends BulkTask<K, V, U> {
+ final Fun<? super V, ? extends U> searchFunction;
+ final AtomicReference<U> result;
+
+ SearchValuesTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ Fun<? super V, ? extends U> searchFunction,
+ AtomicReference<U> result) {
+ super(p, b, i, f, t);
+ this.searchFunction = searchFunction;
+ this.result = result;
+ }
- private boolean eq(Object o1, Object o2) {
- return o1 == null ? o2 == null : o1.equals(o2);
+ @Override
+ public final U getRawResult() {
+ return result.get();
+ }
+
+ @Override
+ public final void compute() {
+ final Fun<? super V, ? extends U> searchFunction;
+ final AtomicReference<U> result;
+ if ((searchFunction = this.searchFunction) != null &&
+ (result = this.result) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ if (result.get() != null) {
+ return;
+ }
+ addToPendingCount(1);
+ new SearchValuesTask<K, V, U>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ searchFunction, result).fork();
+ }
+ while (result.get() == null) {
+ Node<K, V> p;
+ if ((p = advance()) == null) {
+ propagateCompletion();
+ break;
+ }
+ U u;
+ if ((u = searchFunction.apply(p.val)) != null) {
+ if (result.compareAndSet(null, u)) {
+ quietlyCompleteRoot();
+ }
+ break;
+ }
+ }
+ }
}
}
- private final class KeySet extends AbstractSet<K> {
- @NotNull
+ @SuppressWarnings("serial")
+ static final class SearchEntriesTask<K, V, U>
+ extends BulkTask<K, V, U> {
+ final Fun<Entry<K, V>, ? extends U> searchFunction;
+ final AtomicReference<U> result;
+
+ SearchEntriesTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ Fun<Entry<K, V>, ? extends U> searchFunction,
+ AtomicReference<U> result) {
+ super(p, b, i, f, t);
+ this.searchFunction = searchFunction;
+ this.result = result;
+ }
+
@Override
- public Iterator<K> iterator() {
- return new KeyIterator();
+ public final U getRawResult() {
+ return result.get();
}
@Override
- public int size() {
- return ConcurrentHashMap.this.size();
+ public final void compute() {
+ final Fun<Entry<K, V>, ? extends U> searchFunction;
+ final AtomicReference<U> result;
+ if ((searchFunction = this.searchFunction) != null &&
+ (result = this.result) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ if (result.get() != null) {
+ return;
+ }
+ addToPendingCount(1);
+ new SearchEntriesTask<K, V, U>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ searchFunction, result).fork();
+ }
+ while (result.get() == null) {
+ Node<K, V> p;
+ if ((p = advance()) == null) {
+ propagateCompletion();
+ break;
+ }
+ U u;
+ if ((u = searchFunction.apply(p)) != null) {
+ if (result.compareAndSet(null, u)) {
+ quietlyCompleteRoot();
+ }
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class SearchMappingsTask<K, V, U>
+ extends BulkTask<K, V, U> {
+ final BiFun<? super K, ? super V, ? extends U> searchFunction;
+ final AtomicReference<U> result;
+
+ SearchMappingsTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ BiFun<? super K, ? super V, ? extends U> searchFunction,
+ AtomicReference<U> result) {
+ super(p, b, i, f, t);
+ this.searchFunction = searchFunction;
+ this.result = result;
}
@Override
- public boolean contains(Object o) {
- return containsKey(o);
+ public final U getRawResult() {
+ return result.get();
}
@Override
- public boolean remove(Object o) {
- return ConcurrentHashMap.this.remove(o) != null;
+ public final void compute() {
+ final BiFun<? super K, ? super V, ? extends U> searchFunction;
+ final AtomicReference<U> result;
+ if ((searchFunction = this.searchFunction) != null &&
+ (result = this.result) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ if (result.get() != null) {
+ return;
+ }
+ addToPendingCount(1);
+ new SearchMappingsTask<K, V, U>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ searchFunction, result).fork();
+ }
+ while (result.get() == null) {
+ Node<K, V> p;
+ if ((p = advance()) == null) {
+ propagateCompletion();
+ break;
+ }
+ U u;
+ if ((u = searchFunction.apply(p.key, p.val)) != null) {
+ if (result.compareAndSet(null, u)) {
+ quietlyCompleteRoot();
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class ReduceKeysTask<K, V>
+ extends BulkTask<K, V, K> {
+ final BiFun<? super K, ? super K, ? extends K> reducer;
+ K result;
+ ReduceKeysTask<K, V> rights;
+ ReduceKeysTask<K, V> nextRight;
+
+ ReduceKeysTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ ReduceKeysTask<K, V> nextRight,
+ BiFun<? super K, ? super K, ? extends K> reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.reducer = reducer;
}
@Override
- public void clear() {
- ConcurrentHashMap.this.clear();
+ public final K getRawResult() {
+ return result;
}
- @NotNull
@Override
- public Object[] toArray() {
- Collection<K> c = new ArrayList<K>();
- for (K k : this) {
- c.add(k);
+ public final void compute() {
+ final BiFun<? super K, ? super K, ? extends K> reducer;
+ if ((reducer = this.reducer) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new ReduceKeysTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, reducer)).fork();
+ }
+ K r = null;
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ K u = p.key;
+ r = r == null ? u : u == null ? r : reducer.apply(r, u);
+ }
+ result = r;
+
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") ReduceKeysTask<K, V>
+ t = (ReduceKeysTask<K, V>)c;
+ @SuppressWarnings("unchecked") ReduceKeysTask<K, V> s = t.rights;
+ while (s != null) {
+ K sr;
+ if ((sr = s.result) != null) {
+ K tr;
+ t.result = (tr = t.result) == null ? sr :
+ reducer.apply(tr, sr);
+ }
+ s = t.rights = s.nextRight;
+ }
+ }
}
- return c.toArray();
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class ReduceValuesTask<K, V>
+ extends BulkTask<K, V, V> {
+ final BiFun<? super V, ? super V, ? extends V> reducer;
+ V result;
+ ReduceValuesTask<K, V> rights;
+ ReduceValuesTask<K, V> nextRight;
+
+ ReduceValuesTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ ReduceValuesTask<K, V> nextRight,
+ BiFun<? super V, ? super V, ? extends V> reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.reducer = reducer;
+ }
+
+ @Override
+ public final V getRawResult() {
+ return result;
}
- @NotNull
@Override
- public <T> T[] toArray(@NotNull T[] a) {
- Collection<K> c = new ArrayList<K>();
- for (K k : this) {
- c.add(k);
+ public final void compute() {
+ final BiFun<? super V, ? super V, ? extends V> reducer;
+ if ((reducer = this.reducer) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new ReduceValuesTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, reducer)).fork();
+ }
+ V r = null;
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ V v = p.val;
+ r = r == null ? v : reducer.apply(r, v);
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") ReduceValuesTask<K, V>
+ t = (ReduceValuesTask<K, V>)c;
+ @SuppressWarnings("unchecked") ReduceValuesTask<K, V> s = t.rights;
+ while (s != null) {
+ V sr;
+ if ((sr = s.result) != null) {
+ V tr;
+ t.result = (tr = t.result) == null ? sr :
+ reducer.apply(tr, sr);
+ }
+ s = t.rights = s.nextRight;
+ }
+ }
}
- return c.toArray(a);
}
}
- private final class Values extends AbstractCollection<V> {
- @NotNull
+ @SuppressWarnings("serial")
+ static final class ReduceEntriesTask<K, V>
+ extends BulkTask<K, V, Map.Entry<K, V>> {
+ final BiFun<Map.Entry<K, V>, Map.Entry<K, V>, ? extends Map.Entry<K, V>> reducer;
+ Map.Entry<K, V> result;
+ ReduceEntriesTask<K, V> rights;
+ ReduceEntriesTask<K, V> nextRight;
+
+ ReduceEntriesTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ ReduceEntriesTask<K, V> nextRight,
+ BiFun<Entry<K, V>, Map.Entry<K, V>, ? extends Map.Entry<K, V>> reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.reducer = reducer;
+ }
+
@Override
- public Iterator<V> iterator() {
- return new ValueIterator();
+ public final Map.Entry<K, V> getRawResult() {
+ return result;
}
@Override
- public int size() {
- return ConcurrentHashMap.this.size();
+ public final void compute() {
+ final BiFun<Map.Entry<K, V>, Map.Entry<K, V>, ? extends Map.Entry<K, V>> reducer;
+ if ((reducer = this.reducer) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new ReduceEntriesTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, reducer)).fork();
+ }
+ Map.Entry<K, V> r = null;
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ r = r == null ? p : reducer.apply(r, p);
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") ReduceEntriesTask<K, V>
+ t = (ReduceEntriesTask<K, V>)c;
+ @SuppressWarnings("unchecked") ReduceEntriesTask<K, V> s = t.rights;
+ while (s != null) {
+ Map.Entry<K, V> sr;
+ if ((sr = s.result) != null) {
+ Entry<K, V> tr;
+ t.result = (tr = t.result) == null ? sr :
+ reducer.apply(tr, sr);
+ }
+ s = t.rights = s.nextRight;
+ }
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class MapReduceKeysTask<K, V, U>
+ extends BulkTask<K, V, U> {
+ final Fun<? super K, ? extends U> transformer;
+ final BiFun<? super U, ? super U, ? extends U> reducer;
+ U result;
+ MapReduceKeysTask<K, V, U> rights;
+ MapReduceKeysTask<K, V, U> nextRight;
+
+ MapReduceKeysTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ MapReduceKeysTask<K, V, U> nextRight,
+ Fun<? super K, ? extends U> transformer,
+ BiFun<? super U, ? super U, ? extends U> reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.transformer = transformer;
+ this.reducer = reducer;
}
@Override
- public boolean contains(Object o) {
- return containsValue(o);
+ public final U getRawResult() {
+ return result;
}
@Override
- public void clear() {
- ConcurrentHashMap.this.clear();
+ public final void compute() {
+ final Fun<? super K, ? extends U> transformer;
+ final BiFun<? super U, ? super U, ? extends U> reducer;
+ if ((transformer = this.transformer) != null &&
+ (reducer = this.reducer) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new MapReduceKeysTask<K, V, U>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, transformer, reducer)).fork();
+ }
+ U r = null;
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ U u;
+ if ((u = transformer.apply(p.key)) != null) {
+ r = r == null ? u : reducer.apply(r, u);
+ }
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") MapReduceKeysTask<K, V, U>
+ t = (MapReduceKeysTask<K, V, U>)c;
+ @SuppressWarnings("unchecked") MapReduceKeysTask<K, V, U> s = t.rights;
+ while (s != null) {
+ U sr;
+ if ((sr = s.result) != null) {
+ U tr;
+ t.result = (tr = t.result) == null ? sr :
+ reducer.apply(tr, sr);
+ }
+ s = t.rights = s.nextRight;
+ }
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class MapReduceValuesTask<K, V, U>
+ extends BulkTask<K, V, U> {
+ final Fun<? super V, ? extends U> transformer;
+ final BiFun<? super U, ? super U, ? extends U> reducer;
+ U result;
+ MapReduceValuesTask<K, V, U> rights;
+ MapReduceValuesTask<K, V, U> nextRight;
+
+ MapReduceValuesTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ MapReduceValuesTask<K, V, U> nextRight,
+ Fun<? super V, ? extends U> transformer,
+ BiFun<? super U, ? super U, ? extends U> reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.transformer = transformer;
+ this.reducer = reducer;
}
- @NotNull
@Override
- public Object[] toArray() {
- Collection<V> c = new ArrayList<V>();
- for (V v : this) {
- c.add(v);
+ public final U getRawResult() {
+ return result;
+ }
+
+ @Override
+ public final void compute() {
+ final Fun<? super V, ? extends U> transformer;
+ final BiFun<? super U, ? super U, ? extends U> reducer;
+ if ((transformer = this.transformer) != null &&
+ (reducer = this.reducer) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new MapReduceValuesTask<K, V, U>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, transformer, reducer)).fork();
+ }
+ U r = null;
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ U u;
+ if ((u = transformer.apply(p.val)) != null) {
+ r = r == null ? u : reducer.apply(r, u);
+ }
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") MapReduceValuesTask<K, V, U>
+ t = (MapReduceValuesTask<K, V, U>)c;
+ @SuppressWarnings("unchecked") MapReduceValuesTask<K, V, U> s = t.rights;
+ while (s != null) {
+ U sr;
+ if ((sr = s.result) != null) {
+ U tr;
+ t.result = (tr = t.result) == null ? sr :
+ reducer.apply(tr, sr);
+ }
+ s = t.rights = s.nextRight;
+ }
+ }
}
- return c.toArray();
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class MapReduceEntriesTask<K, V, U>
+ extends BulkTask<K, V, U> {
+ final Fun<Map.Entry<K, V>, ? extends U> transformer;
+ final BiFun<? super U, ? super U, ? extends U> reducer;
+ U result;
+ MapReduceEntriesTask<K, V, U> rights;
+ MapReduceEntriesTask<K, V, U> nextRight;
+
+ MapReduceEntriesTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ MapReduceEntriesTask<K, V, U> nextRight,
+ Fun<Map.Entry<K, V>, ? extends U> transformer,
+ BiFun<? super U, ? super U, ? extends U> reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.transformer = transformer;
+ this.reducer = reducer;
}
- @NotNull
@Override
- public <T> T[] toArray(@NotNull T[] a) {
- Collection<V> c = new ArrayList<V>();
- for (V v : this) {
- c.add(v);
+ public final U getRawResult() {
+ return result;
+ }
+
+ @Override
+ public final void compute() {
+ final Fun<Map.Entry<K, V>, ? extends U> transformer;
+ final BiFun<? super U, ? super U, ? extends U> reducer;
+ if ((transformer = this.transformer) != null &&
+ (reducer = this.reducer) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new MapReduceEntriesTask<K, V, U>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, transformer, reducer)).fork();
+ }
+ U r = null;
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ U u;
+ if ((u = transformer.apply(p)) != null) {
+ r = r == null ? u : reducer.apply(r, u);
+ }
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") MapReduceEntriesTask<K, V, U>
+ t = (MapReduceEntriesTask<K, V, U>)c;
+ @SuppressWarnings("unchecked") MapReduceEntriesTask<K, V, U> s = t.rights;
+ while (s != null) {
+ U sr;
+ if ((sr = s.result) != null) {
+ U tr;
+ t.result = (tr = t.result) == null ? sr :
+ reducer.apply(tr, sr);
+ }
+ s = t.rights = s.nextRight;
+ }
+ }
}
- return c.toArray(a);
}
}
- private final class EntrySet extends AbstractSet<Entry<K, V>> {
- @NotNull
+ @SuppressWarnings("serial")
+ static final class MapReduceMappingsTask<K, V, U>
+ extends BulkTask<K, V, U> {
+ final BiFun<? super K, ? super V, ? extends U> transformer;
+ final BiFun<? super U, ? super U, ? extends U> reducer;
+ U result;
+ MapReduceMappingsTask<K, V, U> rights;
+ MapReduceMappingsTask<K, V, U> nextRight;
+
+ MapReduceMappingsTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ MapReduceMappingsTask<K, V, U> nextRight,
+ BiFun<? super K, ? super V, ? extends U> transformer,
+ BiFun<? super U, ? super U, ? extends U> reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.transformer = transformer;
+ this.reducer = reducer;
+ }
+
@Override
- public Iterator<Entry<K, V>> iterator() {
- return new EntryIterator();
+ public final U getRawResult() {
+ return result;
}
@Override
- public boolean contains(Object o) {
- if (!(o instanceof Entry)) {
- return false;
+ public final void compute() {
+ final BiFun<? super K, ? super V, ? extends U> transformer;
+ final BiFun<? super U, ? super U, ? extends U> reducer;
+ if ((transformer = this.transformer) != null &&
+ (reducer = this.reducer) != null) {
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new MapReduceMappingsTask<K, V, U>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, transformer, reducer)).fork();
+ }
+ U r = null;
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ U u;
+ if ((u = transformer.apply(p.key, p.val)) != null) {
+ r = r == null ? u : reducer.apply(r, u);
+ }
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") MapReduceMappingsTask<K, V, U>
+ t = (MapReduceMappingsTask<K, V, U>)c;
+ @SuppressWarnings("unchecked") MapReduceMappingsTask<K, V, U> s = t.rights;
+ while (s != null) {
+ U sr;
+ if ((sr = s.result) != null) {
+ U tr;
+ t.result = (tr = t.result) == null ? sr :
+ reducer.apply(tr, sr);
+ }
+ s = t.rights = s.nextRight;
+ }
+ }
}
- Entry<K, V> e = (Entry<K, V>)o;
- V v = get(e.getKey());
- return v != null && v.equals(e.getValue());
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class MapReduceKeysToDoubleTask<K, V>
+ extends BulkTask<K, V, Double> {
+ final ObjectToDouble<? super K> transformer;
+ final DoubleByDoubleToDouble reducer;
+ final double basis;
+ double result;
+ MapReduceKeysToDoubleTask<K, V> rights;
+ MapReduceKeysToDoubleTask<K, V> nextRight;
+
+ MapReduceKeysToDoubleTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ MapReduceKeysToDoubleTask<K, V> nextRight,
+ ObjectToDouble<? super K> transformer,
+ double basis,
+ DoubleByDoubleToDouble reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.transformer = transformer;
+ this.basis = basis;
+ this.reducer = reducer;
}
@Override
- public boolean remove(Object o) {
- if (!(o instanceof Entry)) {
- return false;
+ public final Double getRawResult() {
+ return result;
+ }
+
+ @Override
+ public final void compute() {
+ final ObjectToDouble<? super K> transformer;
+ final DoubleByDoubleToDouble reducer;
+ if ((transformer = this.transformer) != null &&
+ (reducer = this.reducer) != null) {
+ double r = basis;
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new MapReduceKeysToDoubleTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, transformer, r, reducer)).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ r = reducer.apply(r, transformer.apply(p.key));
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") MapReduceKeysToDoubleTask<K, V>
+ t = (MapReduceKeysToDoubleTask<K, V>)c;
+ @SuppressWarnings("unchecked") MapReduceKeysToDoubleTask<K, V> s = t.rights;
+ while (s != null) {
+ t.result = reducer.apply(t.result, s.result);
+ s = t.rights = s.nextRight;
+ }
+ }
}
- Entry<K, V> e = (Entry<K, V>)o;
- return ConcurrentHashMap.this.remove(e.getKey(), e.getValue());
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class MapReduceValuesToDoubleTask<K, V>
+ extends BulkTask<K, V, Double> {
+ final ObjectToDouble<? super V> transformer;
+ final DoubleByDoubleToDouble reducer;
+ final double basis;
+ double result;
+ MapReduceValuesToDoubleTask<K, V> rights;
+ MapReduceValuesToDoubleTask<K, V> nextRight;
+
+ MapReduceValuesToDoubleTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ MapReduceValuesToDoubleTask<K, V> nextRight,
+ ObjectToDouble<? super V> transformer,
+ double basis,
+ DoubleByDoubleToDouble reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.transformer = transformer;
+ this.basis = basis;
+ this.reducer = reducer;
}
@Override
- public int size() {
- return ConcurrentHashMap.this.size();
+ public final Double getRawResult() {
+ return result;
}
@Override
- public void clear() {
- ConcurrentHashMap.this.clear();
+ public final void compute() {
+ final ObjectToDouble<? super V> transformer;
+ final DoubleByDoubleToDouble reducer;
+ if ((transformer = this.transformer) != null &&
+ (reducer = this.reducer) != null) {
+ double r = basis;
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new MapReduceValuesToDoubleTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, transformer, r, reducer)).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ r = reducer.apply(r, transformer.apply(p.val));
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") MapReduceValuesToDoubleTask<K, V>
+ t = (MapReduceValuesToDoubleTask<K, V>)c;
+ @SuppressWarnings("unchecked") MapReduceValuesToDoubleTask<K, V> s = t.rights;
+ while (s != null) {
+ t.result = reducer.apply(t.result, s.result);
+ s = t.rights = s.nextRight;
+ }
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class MapReduceEntriesToDoubleTask<K, V>
+ extends BulkTask<K, V, Double> {
+ final ObjectToDouble<Map.Entry<K, V>> transformer;
+ final DoubleByDoubleToDouble reducer;
+ final double basis;
+ double result;
+ MapReduceEntriesToDoubleTask<K, V> rights;
+ MapReduceEntriesToDoubleTask<K, V> nextRight;
+
+ MapReduceEntriesToDoubleTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ MapReduceEntriesToDoubleTask<K, V> nextRight,
+ ObjectToDouble<Map.Entry<K, V>> transformer,
+ double basis,
+ DoubleByDoubleToDouble reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.transformer = transformer;
+ this.basis = basis;
+ this.reducer = reducer;
+ }
+
+ @Override
+ public final Double getRawResult() {
+ return result;
}
- @NotNull
@Override
- public Object[] toArray() {
- // Since we don't ordinarily have distinct Entry objects, we
- // must pack elements using exportable SimpleEntry
- Collection<Entry<K, V>> c = new ArrayList<Entry<K, V>>(size());
- for (Entry<K, V> entry : this) {
- c.add(new SimpleEntry(entry));
+ public final void compute() {
+ final ObjectToDouble<Map.Entry<K, V>> transformer;
+ final DoubleByDoubleToDouble reducer;
+ if ((transformer = this.transformer) != null &&
+ (reducer = this.reducer) != null) {
+ double r = basis;
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new MapReduceEntriesToDoubleTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, transformer, r, reducer)).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ r = reducer.apply(r, transformer.apply(p));
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") MapReduceEntriesToDoubleTask<K, V>
+ t = (MapReduceEntriesToDoubleTask<K, V>)c;
+ @SuppressWarnings("unchecked") MapReduceEntriesToDoubleTask<K, V> s = t.rights;
+ while (s != null) {
+ t.result = reducer.apply(t.result, s.result);
+ s = t.rights = s.nextRight;
+ }
+ }
}
- return c.toArray();
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class MapReduceMappingsToDoubleTask<K, V>
+ extends BulkTask<K, V, Double> {
+ final ObjectByObjectToDouble<? super K, ? super V> transformer;
+ final DoubleByDoubleToDouble reducer;
+ final double basis;
+ double result;
+ MapReduceMappingsToDoubleTask<K, V> rights;
+ MapReduceMappingsToDoubleTask<K, V> nextRight;
+
+ MapReduceMappingsToDoubleTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ MapReduceMappingsToDoubleTask<K, V> nextRight,
+ ObjectByObjectToDouble<? super K, ? super V> transformer,
+ double basis,
+ DoubleByDoubleToDouble reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.transformer = transformer;
+ this.basis = basis;
+ this.reducer = reducer;
+ }
+
+ @Override
+ public final Double getRawResult() {
+ return result;
}
- @NotNull
@Override
- public <T> T[] toArray(@NotNull T[] a) {
- Collection<Entry<K, V>> c = new ArrayList<Entry<K, V>>(size());
- for (Entry<K, V> entry : this) {
- c.add(new SimpleEntry(entry));
+ public final void compute() {
+ final ObjectByObjectToDouble<? super K, ? super V> transformer;
+ final DoubleByDoubleToDouble reducer;
+ if ((transformer = this.transformer) != null &&
+ (reducer = this.reducer) != null) {
+ double r = basis;
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new MapReduceMappingsToDoubleTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, transformer, r, reducer)).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ r = reducer.apply(r, transformer.apply(p.key, p.val));
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") MapReduceMappingsToDoubleTask<K, V>
+ t = (MapReduceMappingsToDoubleTask<K, V>)c;
+ @SuppressWarnings("unchecked") MapReduceMappingsToDoubleTask<K, V> s = t.rights;
+ while (s != null) {
+ t.result = reducer.apply(t.result, s.result);
+ s = t.rights = s.nextRight;
+ }
+ }
}
- return c.toArray(a);
}
}
- /**
- * This duplicates java.util.AbstractMap.SimpleEntry until this class
- * is made accessible.
- */
- final class SimpleEntry implements Entry<K, V> {
- private final K key;
- private V value;
+ @SuppressWarnings("serial")
+ static final class MapReduceKeysToLongTask<K, V>
+ extends BulkTask<K, V, Long> {
+ final ObjectToLong<? super K> transformer;
+ final LongByLongToLong reducer;
+ final long basis;
+ long result;
+ MapReduceKeysToLongTask<K, V> rights;
+ MapReduceKeysToLongTask<K, V> nextRight;
+
+ MapReduceKeysToLongTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ MapReduceKeysToLongTask<K, V> nextRight,
+ ObjectToLong<? super K> transformer,
+ long basis,
+ LongByLongToLong reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.transformer = transformer;
+ this.basis = basis;
+ this.reducer = reducer;
+ }
- public SimpleEntry(K key, V value) {
- this.key = key;
- this.value = value;
+ @Override
+ public final Long getRawResult() {
+ return result;
}
- public SimpleEntry(Entry<K, V> e) {
- key = e.getKey();
- value = e.getValue();
+ @Override
+ public final void compute() {
+ final ObjectToLong<? super K> transformer;
+ final LongByLongToLong reducer;
+ if ((transformer = this.transformer) != null &&
+ (reducer = this.reducer) != null) {
+ long r = basis;
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new MapReduceKeysToLongTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, transformer, r, reducer)).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ r = reducer.apply(r, transformer.apply(p.key));
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") MapReduceKeysToLongTask<K, V>
+ t = (MapReduceKeysToLongTask<K, V>)c;
+ @SuppressWarnings("unchecked") MapReduceKeysToLongTask<K, V> s = t.rights;
+ while (s != null) {
+ t.result = reducer.apply(t.result, s.result);
+ s = t.rights = s.nextRight;
+ }
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class MapReduceValuesToLongTask<K, V>
+ extends BulkTask<K, V, Long> {
+ final ObjectToLong<? super V> transformer;
+ final LongByLongToLong reducer;
+ final long basis;
+ long result;
+ MapReduceValuesToLongTask<K, V> rights;
+ MapReduceValuesToLongTask<K, V> nextRight;
+
+ MapReduceValuesToLongTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ MapReduceValuesToLongTask<K, V> nextRight,
+ ObjectToLong<? super V> transformer,
+ long basis,
+ LongByLongToLong reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.transformer = transformer;
+ this.basis = basis;
+ this.reducer = reducer;
}
@Override
- public K getKey() {
- return key;
+ public final Long getRawResult() {
+ return result;
}
@Override
- public V getValue() {
- return value;
+ public final void compute() {
+ final ObjectToLong<? super V> transformer;
+ final LongByLongToLong reducer;
+ if ((transformer = this.transformer) != null &&
+ (reducer = this.reducer) != null) {
+ long r = basis;
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new MapReduceValuesToLongTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, transformer, r, reducer)).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ r = reducer.apply(r, transformer.apply(p.val));
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") MapReduceValuesToLongTask<K, V>
+ t = (MapReduceValuesToLongTask<K, V>)c;
+ @SuppressWarnings("unchecked") MapReduceValuesToLongTask<K, V> s = t.rights;
+ while (s != null) {
+ t.result = reducer.apply(t.result, s.result);
+ s = t.rights = s.nextRight;
+ }
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class MapReduceEntriesToLongTask<K, V>
+ extends BulkTask<K, V, Long> {
+ final ObjectToLong<Map.Entry<K, V>> transformer;
+ final LongByLongToLong reducer;
+ final long basis;
+ long result;
+ MapReduceEntriesToLongTask<K, V> rights;
+ MapReduceEntriesToLongTask<K, V> nextRight;
+
+ MapReduceEntriesToLongTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ MapReduceEntriesToLongTask<K, V> nextRight,
+ ObjectToLong<Map.Entry<K, V>> transformer,
+ long basis,
+ LongByLongToLong reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.transformer = transformer;
+ this.basis = basis;
+ this.reducer = reducer;
}
@Override
- public V setValue(V value) {
- V oldValue = this.value;
- this.value = value;
- return oldValue;
+ public final Long getRawResult() {
+ return result;
}
- public boolean equals(Object o) {
- if (!(o instanceof Entry)) {
- return false;
+ @Override
+ public final void compute() {
+ final ObjectToLong<Map.Entry<K, V>> transformer;
+ final LongByLongToLong reducer;
+ if ((transformer = this.transformer) != null &&
+ (reducer = this.reducer) != null) {
+ long r = basis;
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new MapReduceEntriesToLongTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, transformer, r, reducer)).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ r = reducer.apply(r, transformer.apply(p));
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") MapReduceEntriesToLongTask<K, V>
+ t = (MapReduceEntriesToLongTask<K, V>)c;
+ @SuppressWarnings("unchecked") MapReduceEntriesToLongTask<K, V> s = t.rights;
+ while (s != null) {
+ t.result = reducer.apply(t.result, s.result);
+ s = t.rights = s.nextRight;
+ }
+ }
}
- Entry e = (Entry)o;
- K o2 = (K)e.getKey();
- return (key == null ? o2 == null : myHashingStrategy.equals(key, o2)) && eq(value, e.getValue());
}
+ }
- public int hashCode() {
- return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode());
+ @SuppressWarnings("serial")
+ static final class MapReduceMappingsToLongTask<K, V>
+ extends BulkTask<K, V, Long> {
+ final ObjectByObjectToLong<? super K, ? super V> transformer;
+ final LongByLongToLong reducer;
+ final long basis;
+ long result;
+ MapReduceMappingsToLongTask<K, V> rights;
+ MapReduceMappingsToLongTask<K, V> nextRight;
+
+ MapReduceMappingsToLongTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ MapReduceMappingsToLongTask<K, V> nextRight,
+ ObjectByObjectToLong<? super K, ? super V> transformer,
+ long basis,
+ LongByLongToLong reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.transformer = transformer;
+ this.basis = basis;
+ this.reducer = reducer;
}
- public String toString() {
- return key + "=" + value;
+ @Override
+ public final Long getRawResult() {
+ return result;
}
- boolean eq(Object o1, Object o2) {
- return o1 == null ? o2 == null : o1.equals(o2);
+ @Override
+ public final void compute() {
+ final ObjectByObjectToLong<? super K, ? super V> transformer;
+ final LongByLongToLong reducer;
+ if ((transformer = this.transformer) != null &&
+ (reducer = this.reducer) != null) {
+ long r = basis;
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new MapReduceMappingsToLongTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, transformer, r, reducer)).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ r = reducer.apply(r, transformer.apply(p.key, p.val));
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") MapReduceMappingsToLongTask<K, V>
+ t = (MapReduceMappingsToLongTask<K, V>)c;
+ @SuppressWarnings("unchecked") MapReduceMappingsToLongTask<K, V> s = t.rights;
+ while (s != null) {
+ t.result = reducer.apply(t.result, s.result);
+ s = t.rights = s.nextRight;
+ }
+ }
+ }
}
}
- /* ---------------- Serialization Support -------------- */
+ @SuppressWarnings("serial")
+ static final class MapReduceKeysToIntTask<K, V>
+ extends BulkTask<K, V, Integer> {
+ final ObjectToInt<? super K> transformer;
+ final IntByIntToInt reducer;
+ final int basis;
+ int result;
+ MapReduceKeysToIntTask<K, V> rights;
+ MapReduceKeysToIntTask<K, V> nextRight;
+
+ MapReduceKeysToIntTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ MapReduceKeysToIntTask<K, V> nextRight,
+ ObjectToInt<? super K> transformer,
+ int basis,
+ IntByIntToInt reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.transformer = transformer;
+ this.basis = basis;
+ this.reducer = reducer;
+ }
- /**
- * Save the state of the <tt>ConcurrentHashMap</tt>
- * instance to a stream (i.e.,
- * serialize it).
- *
- * @param s the stream
- * @serialData the key (Object) and value (Object)
- * for each key-value mapping, followed by a null pair.
- * The key-value mappings are emitted in no particular order.
- */
- private void writeObject(ObjectOutputStream s) throws IOException {
- s.defaultWriteObject();
+ @Override
+ public final Integer getRawResult() {
+ return result;
+ }
- for (Segment seg : segments) {
- seg.lock();
- try {
- HashEntry[] tab = seg.table;
- for (HashEntry tabEntry : tab) {
- HashEntry<K, V> entry = (HashEntry<K, V>)tabEntry;
- for (HashEntry<K, V> e = entry; e != null; e = e.next) {
- s.writeObject(e.key);
- s.writeObject(e.value);
+ @Override
+ public final void compute() {
+ final ObjectToInt<? super K> transformer;
+ final IntByIntToInt reducer;
+ if ((transformer = this.transformer) != null &&
+ (reducer = this.reducer) != null) {
+ int r = basis;
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new MapReduceKeysToIntTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, transformer, r, reducer)).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ r = reducer.apply(r, transformer.apply(p.key));
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") MapReduceKeysToIntTask<K, V>
+ t = (MapReduceKeysToIntTask<K, V>)c;
+ @SuppressWarnings("unchecked") MapReduceKeysToIntTask<K, V> s = t.rights;
+ while (s != null) {
+ t.result = reducer.apply(t.result, s.result);
+ s = t.rights = s.nextRight;
}
}
}
- finally {
- seg.unlock();
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class MapReduceValuesToIntTask<K, V>
+ extends BulkTask<K, V, Integer> {
+ final ObjectToInt<? super V> transformer;
+ final IntByIntToInt reducer;
+ final int basis;
+ int result;
+ MapReduceValuesToIntTask<K, V> rights;
+ MapReduceValuesToIntTask<K, V> nextRight;
+
+ MapReduceValuesToIntTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ MapReduceValuesToIntTask<K, V> nextRight,
+ ObjectToInt<? super V> transformer,
+ int basis,
+ IntByIntToInt reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.transformer = transformer;
+ this.basis = basis;
+ this.reducer = reducer;
+ }
+
+ @Override
+ public final Integer getRawResult() {
+ return result;
+ }
+
+ @Override
+ public final void compute() {
+ final ObjectToInt<? super V> transformer;
+ final IntByIntToInt reducer;
+ if ((transformer = this.transformer) != null &&
+ (reducer = this.reducer) != null) {
+ int r = basis;
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new MapReduceValuesToIntTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, transformer, r, reducer)).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ r = reducer.apply(r, transformer.apply(p.val));
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") MapReduceValuesToIntTask<K, V>
+ t = (MapReduceValuesToIntTask<K, V>)c;
+ @SuppressWarnings("unchecked") MapReduceValuesToIntTask<K, V> s = t.rights;
+ while (s != null) {
+ t.result = reducer.apply(t.result, s.result);
+ s = t.rights = s.nextRight;
+ }
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class MapReduceEntriesToIntTask<K, V>
+ extends BulkTask<K, V, Integer> {
+ final ObjectToInt<Map.Entry<K, V>> transformer;
+ final IntByIntToInt reducer;
+ final int basis;
+ int result;
+ MapReduceEntriesToIntTask<K, V> rights;
+ MapReduceEntriesToIntTask<K, V> nextRight;
+
+ MapReduceEntriesToIntTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ MapReduceEntriesToIntTask<K, V> nextRight,
+ ObjectToInt<Map.Entry<K, V>> transformer,
+ int basis,
+ IntByIntToInt reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.transformer = transformer;
+ this.basis = basis;
+ this.reducer = reducer;
+ }
+
+ @Override
+ public final Integer getRawResult() {
+ return result;
+ }
+
+ @Override
+ public final void compute() {
+ final ObjectToInt<Map.Entry<K, V>> transformer;
+ final IntByIntToInt reducer;
+ if ((transformer = this.transformer) != null &&
+ (reducer = this.reducer) != null) {
+ int r = basis;
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new MapReduceEntriesToIntTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, transformer, r, reducer)).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ r = reducer.apply(r, transformer.apply(p));
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") MapReduceEntriesToIntTask<K, V>
+ t = (MapReduceEntriesToIntTask<K, V>)c;
+ @SuppressWarnings("unchecked") MapReduceEntriesToIntTask<K, V> s = t.rights;
+ while (s != null) {
+ t.result = reducer.apply(t.result, s.result);
+ s = t.rights = s.nextRight;
+ }
+ }
}
}
- s.writeObject(null);
- s.writeObject(null);
+ }
+
+ @SuppressWarnings("serial")
+ static final class MapReduceMappingsToIntTask<K, V>
+ extends BulkTask<K, V, Integer> {
+ final ObjectByObjectToInt<? super K, ? super V> transformer;
+ final IntByIntToInt reducer;
+ final int basis;
+ int result;
+ MapReduceMappingsToIntTask<K, V> rights;
+ MapReduceMappingsToIntTask<K, V> nextRight;
+
+ MapReduceMappingsToIntTask
+ (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
+ MapReduceMappingsToIntTask<K, V> nextRight,
+ ObjectByObjectToInt<? super K, ? super V> transformer,
+ int basis,
+ IntByIntToInt reducer) {
+ super(p, b, i, f, t);
+ this.nextRight = nextRight;
+ this.transformer = transformer;
+ this.basis = basis;
+ this.reducer = reducer;
+ }
+
+ @Override
+ public final Integer getRawResult() {
+ return result;
+ }
+
+ @Override
+ public final void compute() {
+ final ObjectByObjectToInt<? super K, ? super V> transformer;
+ final IntByIntToInt reducer;
+ if ((transformer = this.transformer) != null &&
+ (reducer = this.reducer) != null) {
+ int r = basis;
+ for (int i = baseIndex, f, h; batch > 0 &&
+ (h = (f = baseLimit) + i >>> 1) > i; ) {
+ addToPendingCount(1);
+ (rights = new MapReduceMappingsToIntTask<K, V>
+ (this, batch >>>= 1, baseLimit = h, f, tab,
+ rights, transformer, r, reducer)).fork();
+ }
+ for (Node<K, V> p; (p = advance()) != null; ) {
+ r = reducer.apply(r, transformer.apply(p.key, p.val));
+ }
+ result = r;
+ for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ @SuppressWarnings("unchecked") MapReduceMappingsToIntTask<K, V>
+ t = (MapReduceMappingsToIntTask<K, V>)c;
+ @SuppressWarnings("unchecked") MapReduceMappingsToIntTask<K, V> s = t.rights;
+ while (s != null) {
+ t.result = reducer.apply(t.result, s.result);
+ s = t.rights = s.nextRight;
+ }
+ }
+ }
+ }
+ }
+
+ /* ---------------- Counters -------------- */
+
+ // Adapted from LongAdder and Striped64.
+ // See their internal docs for explanation.
+
+ // A padded cell for distributing counts
+ static final class CounterCell {
+ volatile long p0;
+ volatile long p1;
+ volatile long p2;
+ volatile long p3;
+ volatile long p4;
+ volatile long p5;
+ volatile long p6;
+ volatile long value;
+ volatile long q0;
+ volatile long q1;
+ volatile long q2;
+ volatile long q3;
+ volatile long q4;
+ volatile long q5;
+ volatile long q6;
+
+ CounterCell(long x) {
+ value = x;
+ }
}
/**
- * Reconstitute the <tt>ConcurrentHashMap</tt>
- * instance from a stream (i.e.,
- * deserialize it).
- *
- * @param s the stream
+ * Holder for the thread-local hash code determining which
+ * CounterCell to use. The code is initialized via the
+ * counterHashCodeGenerator, but may be moved upon collisions.
*/
- private void readObject(ObjectInputStream s)
- throws IOException, ClassNotFoundException {
- s.defaultReadObject();
+ static final class CounterHashCode {
+ int code;
+ }
+
+ /**
+ * Generates initial value for per-thread CounterHashCodes.
+ */
+ static final AtomicInteger counterHashCodeGenerator = new AtomicInteger();
- // Initialize each segment to be minimally sized, and let grow.
- for (Segment segment : segments) {
- segment.setTable(new HashEntry[1]);
+ /**
+ * Increment for counterHashCodeGenerator. See class ThreadLocal
+ * for explanation.
+ */
+ static final int SEED_INCREMENT = 0x61c88647;
+
+ /**
+ * Per-thread counter hash codes. Shared across all instances.
+ */
+ static final ThreadLocal<CounterHashCode> threadCounterHashCode =
+ new ThreadLocal<CounterHashCode>();
+
+
+ final long sumCount() {
+ CounterCell[] as = counterCells;
+ long sum = baseCount;
+ if (as != null) {
+ for (CounterCell a : as) {
+ if (a != null) {
+ sum += a.value;
+ }
+ }
}
+ return sum;
+ }
- // Read the keys and values, and put the mappings in the table
- while (true) {
- K key = (K)s.readObject();
- V value = (V)s.readObject();
- if (key == null) {
- break;
+ // See LongAdder version for explanation
+ private void fullAddCount(long x, CounterHashCode hc,
+ boolean wasUncontended) {
+ int h;
+ if (hc == null) {
+ hc = new CounterHashCode();
+ int s = counterHashCodeGenerator.addAndGet(SEED_INCREMENT);
+ h = hc.code = s == 0 ? 1 : s; // Avoid zero
+ threadCounterHashCode.set(hc);
+ }
+ else {
+ h = hc.code;
+ }
+ boolean collide = false; // True if last slot nonempty
+ for (; ; ) {
+ CounterCell[] as;
+ int n;
+ long v;
+ if ((as = counterCells) != null && (n = as.length) > 0) {
+ CounterCell a;
+ if ((a = as[n - 1 & h]) == null) {
+ if (cellsBusy == 0) { // Try to attach new Cell
+ CounterCell r = new CounterCell(x); // Optimistic create
+ if (cellsBusy == 0 &&
+ U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+ boolean created = false;
+ try { // Recheck under lock
+ CounterCell[] rs;
+ int m;
+ int j;
+ if ((rs = counterCells) != null &&
+ (m = rs.length) > 0 &&
+ rs[j = m - 1 & h] == null) {
+ rs[j] = r;
+ created = true;
+ }
+ }
+ finally {
+ cellsBusy = 0;
+ }
+ if (created) {
+ break;
+ }
+ continue; // Slot is now non-empty
+ }
+ }
+ collide = false;
+ }
+ else if (!wasUncontended) // CAS already known to fail
+ {
+ wasUncontended = true; // Continue after rehash
+ }
+ else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x)) {
+ break;
+ }
+ else if (counterCells != as || n >= NCPU) {
+ collide = false; // At max size or stale
+ }
+ else if (!collide) {
+ collide = true;
+ }
+ else if (cellsBusy == 0 &&
+ U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+ try {
+ if (counterCells == as) {// Expand table unless stale
+ CounterCell[] rs = new CounterCell[n << 1];
+ for (int i = 0; i < n; ++i) {
+ rs[i] = as[i];
+ }
+ counterCells = rs;
+ }
+ }
+ finally {
+ cellsBusy = 0;
+ }
+ collide = false;
+ continue; // Retry with expanded table
+ }
+ h ^= h << 13; // Rehash
+ h ^= h >>> 17;
+ h ^= h << 5;
}
- put(key, value);
+ else if (cellsBusy == 0 && counterCells == as &&
+ U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+ boolean init = false;
+ try { // Initialize table
+ if (counterCells == as) {
+ CounterCell[] rs = new CounterCell[2];
+ rs[h & 1] = new CounterCell(x);
+ counterCells = rs;
+ init = true;
+ }
+ }
+ finally {
+ cellsBusy = 0;
+ }
+ if (init) {
+ break;
+ }
+ }
+ else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x)) {
+ break; // Fall back on using base
+ }
+ }
+ hc.code = h; // Record index for next time
+ }
+
+ // Unsafe mechanics
+ private static final Unsafe U;
+ private static final long SIZECTL;
+ private static final long TRANSFERINDEX;
+ private static final long TRANSFERORIGIN;
+ private static final long BASECOUNT;
+ private static final long CELLSBUSY;
+ private static final long CELLVALUE;
+ private static final long ABASE;
+ private static final int ASHIFT;
+
+ static {
+ try {
+ U = getUnsafe();
+ Class<?> k = ConcurrentHashMap.class;
+ SIZECTL = U.objectFieldOffset
+ (k.getDeclaredField("sizeCtl"));
+ TRANSFERINDEX = U.objectFieldOffset
+ (k.getDeclaredField("transferIndex"));
+ TRANSFERORIGIN = U.objectFieldOffset
+ (k.getDeclaredField("transferOrigin"));
+ BASECOUNT = U.objectFieldOffset
+ (k.getDeclaredField("baseCount"));
+ CELLSBUSY = U.objectFieldOffset
+ (k.getDeclaredField("cellsBusy"));
+ Class<?> ck = CounterCell.class;
+ CELLVALUE = U.objectFieldOffset
+ (ck.getDeclaredField("value"));
+ Class<?> ak = Node[].class;
+ ABASE = U.arrayBaseOffset(ak);
+ int scale = U.arrayIndexScale(ak);
+ if ((scale & scale - 1) != 0) {
+ throw new Error("data type scale not a power of two");
+ }
+ ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+ }
+ catch (Exception e) {
+ throw new Error(e);
+ }
+ }
+
+ /**
+ * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package.
+ * Replace with a simple call to Unsafe.getUnsafe when integrating
+ * into a jdk.
+ *
+ * @return a sun.misc.Unsafe
+ */
+ private static Unsafe getUnsafe() {
+ try {
+ return Unsafe.getUnsafe();
+ }
+ catch (SecurityException tryReflectionInstead) {
+ }
+ try {
+ return AccessController.doPrivileged
+ (new PrivilegedExceptionAction<Unsafe>() {
+ @Override
+ public Unsafe run() throws Exception {
+ Class<Unsafe> k = Unsafe.class;
+ for (Field f : k.getDeclaredFields()) {
+ f.setAccessible(true);
+ Object x = f.get(null);
+ if (k.isInstance(x)) {
+ return k.cast(x);
+ }
+ }
+ throw new NoSuchFieldError("the Unsafe");
+ }
+ });
+ }
+ catch (PrivilegedActionException e) {
+ throw new RuntimeException("Could not initialize intrinsics",
+ e.getCause());
}
}
+ ////////////////////// IJ specific
@Override
public int computeHashCode(final K object) {
- int h = object.hashCode();
- h += ~(h << 9);
- h ^= h >>> 14;
- h += h << 4;
- h ^= h >>> 10;
- return h;
+ return object == null ? 0 : object.hashCode();
}
@Override
@@ -1527,4 +7182,10 @@ public class ConcurrentHashMap<K, V> extends AbstractMap<K, V> implements Concur
public V cacheOrGet(final K key, final V value) {
return ConcurrencyUtil.cacheOrGet(this, key, value);
}
+
+ private int hash(K key) {
+ return spread(myHashingStrategy.computeHashCode(key));
+ }
+ public static final float DEFAULT_LOAD_FACTOR = LOAD_FACTOR;
+ public static final int DEFAULT_INITIAL_CAPACITY = DEFAULT_CAPACITY;
}
diff --git a/platform/util/src/com/intellij/util/containers/Convertor.java b/platform/util/src/com/intellij/util/containers/Convertor.java
index b51b4910024a..4020143b0f68 100644
--- a/platform/util/src/com/intellij/util/containers/Convertor.java
+++ b/platform/util/src/com/intellij/util/containers/Convertor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -19,6 +19,7 @@ public interface Convertor<Src, Dst> {
IntoSelf SELF = new IntoSelf();
class IntoSelf<Src> implements Convertor<Src, Src> {
+ @Override
public Src convert(Src o) {
return o;
}
diff --git a/platform/util/src/com/intellij/util/io/SafeFileOutputStream.java b/platform/util/src/com/intellij/util/io/SafeFileOutputStream.java
index 145bc08b0a62..da71335d4d81 100644
--- a/platform/util/src/com/intellij/util/io/SafeFileOutputStream.java
+++ b/platform/util/src/com/intellij/util/io/SafeFileOutputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2011 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.
@@ -114,8 +114,6 @@ public class SafeFileOutputStream extends OutputStream {
myTargetFile, myBackDoorFile.getName()));
}
- final int permissions = myPreserveAttributes ? FileSystemUtil.getPermissions(myTargetFile) : -1;
-
final File oldFile = new File(myTargetFile.getParent(), myTargetFile.getName() + EXTENSION_OLD);
try {
FileUtil.rename(myTargetFile, oldFile);
@@ -135,8 +133,8 @@ public class SafeFileOutputStream extends OutputStream {
myTargetFile, oldFile.getName(), myBackDoorFile.getName()));
}
- if (permissions != -1) {
- FileSystemUtil.setPermissions(myTargetFile, permissions);
+ if (myPreserveAttributes) {
+ FileSystemUtil.clonePermissions(oldFile.getPath(), myTargetFile.getPath());
}
if (!FileUtil.delete(oldFile)) {
diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java
index d0ab6777c6ca..58bd959d73a9 100644
--- a/platform/util/src/com/intellij/util/ui/UIUtil.java
+++ b/platform/util/src/com/intellij/util/ui/UIUtil.java
@@ -932,12 +932,12 @@ public class UIUtil {
}
public static Icon getTreeSelectedCollapsedIcon() {
- return isUnderAquaBasedLookAndFeel() || isUnderNimbusLookAndFeel() || isUnderGTKLookAndFeel() || isUnderDarcula()
+ return isUnderAquaBasedLookAndFeel() || isUnderNimbusLookAndFeel() || isUnderGTKLookAndFeel() || isUnderDarcula() || isUnderIntelliJLaF()
? AllIcons.Mac.Tree_white_right_arrow : getTreeCollapsedIcon();
}
public static Icon getTreeSelectedExpandedIcon() {
- return isUnderAquaBasedLookAndFeel() || isUnderNimbusLookAndFeel() || isUnderGTKLookAndFeel() || isUnderDarcula()
+ return isUnderAquaBasedLookAndFeel() || isUnderNimbusLookAndFeel() || isUnderGTKLookAndFeel() || isUnderDarcula() || isUnderIntelliJLaF()
? AllIcons.Mac.Tree_white_down_arrow : getTreeExpandedIcon();
}
@@ -1027,6 +1027,11 @@ public class UIUtil {
}
@SuppressWarnings({"HardCodedStringLiteral"})
+ public static boolean isUnderIntelliJLaF() {
+ return UIManager.getLookAndFeel().getName().contains("IntelliJ");
+ }
+
+ @SuppressWarnings({"HardCodedStringLiteral"})
public static boolean isUnderGTKLookAndFeel() {
return UIManager.getLookAndFeel().getName().contains("GTK");
}
diff --git a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java
index 05693bdfb267..d64fb51700bc 100644
--- a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java
+++ b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java
@@ -251,7 +251,7 @@ public class WideSelectionTreeUI extends BasicTreeUI {
final boolean hasBeenExpanded,
final boolean isLeaf) {
if (!shouldPaintLines()) return;
- if (!UIUtil.isUnderAquaBasedLookAndFeel() && !UIUtil.isUnderDarcula()) {
+ if (!UIUtil.isUnderAquaBasedLookAndFeel() && !UIUtil.isUnderDarcula() && !UIUtil.isUnderIntelliJLaF()) {
if (UIUtil.isUnderAlloyIDEALookAndFeel()) {
invertLineColor = tree.getSelectionModel().isRowSelected(row) && tree.hasFocus();
}
@@ -271,7 +271,7 @@ public class WideSelectionTreeUI extends BasicTreeUI {
@Override
protected void paintVerticalPartOfLeg(final Graphics g, final Rectangle clipBounds, final Insets insets, final TreePath path) {
- if (!UIUtil.isUnderAquaBasedLookAndFeel() && !UIUtil.isUnderDarcula() && shouldPaintLines()) {
+ if (!UIUtil.isUnderAquaBasedLookAndFeel() && !UIUtil.isUnderDarcula() && !UIUtil.isUnderIntelliJLaF() && shouldPaintLines()) {
invertLineColor = UIUtil.isUnderAlloyIDEALookAndFeel() && tree.hasFocus() && tree.getSelectionModel().isPathSelected(path);
super.paintVerticalPartOfLeg(g, clipBounds, insets, path);
invertLineColor = false;
@@ -353,7 +353,7 @@ public class WideSelectionTreeUI extends BasicTreeUI {
}
}
else {
- if (selected && (UIUtil.isUnderAquaBasedLookAndFeel() || UIUtil.isUnderDarcula())) {
+ if (selected && (UIUtil.isUnderAquaBasedLookAndFeel() || UIUtil.isUnderDarcula() || UIUtil.isUnderIntelliJLaF())) {
Color bg = UIUtil.getTreeSelectionBackground(tree.hasFocus());
if (myWideSelectionCondition.value(row)) {
@@ -377,7 +377,7 @@ public class WideSelectionTreeUI extends BasicTreeUI {
@Override
public void paint(Graphics g, JComponent c) {
- if (myWideSelection && !UIUtil.isUnderAquaBasedLookAndFeel() && !UIUtil.isUnderDarcula()) {
+ if (myWideSelection && !UIUtil.isUnderAquaBasedLookAndFeel() && !UIUtil.isUnderDarcula() && !UIUtil.isUnderIntelliJLaF()) {
paintSelectedRows(g, ((JTree)c));
}
if (myWideSelection) {
diff --git a/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesNio2ReadingTest.java b/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesNio2ReadingTest.java
index a732c3408060..6d00daf2412b 100644
--- a/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesNio2ReadingTest.java
+++ b/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesNio2ReadingTest.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.
@@ -43,7 +43,7 @@ public class FileAttributesNio2ReadingTest extends FileAttributesReadingTest {
System.setProperty(FORCE_USE_NIO_2_KEY, "true");
FileSystemUtil.resetMediator();
- assertEquals("NIO2", FileSystemUtil.getMediatorName());
+ assertEquals("Nio2", FileSystemUtil.getMediatorName());
}
@AfterClass
diff --git a/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java b/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java
index 798ad4317c37..c56771bbe182 100644
--- a/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java
+++ b/platform/util/testSrc/com/intellij/openapi/util/io/FileAttributesReadingTest.java
@@ -19,6 +19,7 @@ import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.win32.FileInfo;
import com.intellij.openapi.util.io.win32.IdeaWin32;
import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.SystemProperties;
import com.intellij.util.TimeoutUtil;
import org.jetbrains.annotations.NotNull;
import org.junit.After;
@@ -151,7 +152,7 @@ public class FileAttributesReadingTest {
final FileAttributes attributes = getAttributes(link);
assertEquals(FileAttributes.Type.FILE, attributes.type);
- assertEquals(FileAttributes.SYM_LINK, attributes.flags);
+ assertEquals(FileAttributes.SYM_LINK | FileAttributes.READ_ONLY, attributes.flags);
assertEquals(myTestData.length, attributes.length);
assertTimestampsEqual(file.lastModified(), attributes.lastModified);
assertFalse(attributes.isWritable());
@@ -173,7 +174,7 @@ public class FileAttributesReadingTest {
final FileAttributes attributes = getAttributes(link2);
assertEquals(FileAttributes.Type.FILE, attributes.type);
- assertEquals(FileAttributes.SYM_LINK, attributes.flags);
+ assertEquals(FileAttributes.SYM_LINK | FileAttributes.READ_ONLY, attributes.flags);
assertEquals(myTestData.length, attributes.length);
assertTimestampsEqual(file.lastModified(), attributes.lastModified);
assertFalse(attributes.isWritable());
@@ -193,7 +194,7 @@ public class FileAttributesReadingTest {
final FileAttributes attributes = getAttributes(link);
assertEquals(FileAttributes.Type.DIRECTORY, attributes.type);
- assertEquals(FileAttributes.SYM_LINK, attributes.flags);
+ assertEquals(SystemInfo.isUnix ? FileAttributes.SYM_LINK | FileAttributes.READ_ONLY : FileAttributes.SYM_LINK, attributes.flags);
assertEquals(file.length(), attributes.length);
assertTimestampsEqual(file.lastModified(), attributes.lastModified);
if (SystemInfo.isUnix) assertFalse(attributes.isWritable());
@@ -412,6 +413,21 @@ public class FileAttributesReadingTest {
assertTrue(attributes.lastModified + " not in " + t1 + ".." + t2, t1 <= attributes.lastModified && attributes.lastModified <= t2);
}
+ @Test
+ public void notOwned() throws Exception {
+ assumeTrue(SystemInfo.isUnix);
+ File userHome = new File(SystemProperties.getUserHome());
+
+ FileAttributes homeAttributes = getAttributes(userHome);
+ assertTrue(homeAttributes.isDirectory());
+ assertTrue(homeAttributes.isWritable());
+
+ FileAttributes parentAttributes = getAttributes(userHome.getParentFile());
+ assertTrue(parentAttributes.isDirectory());
+ assertFalse(parentAttributes.isWritable());
+ }
+
+
@NotNull
private static FileAttributes getAttributes(@NotNull final File file) {
return getAttributes(file, true);
diff --git a/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilFindFileTest.java b/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilFindFileTest.java
deleted file mode 100644
index 934f78a5881b..000000000000
--- a/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilFindFileTest.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2000-2012 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.util.io;
-
-import com.intellij.openapi.util.text.StringUtil;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import java.io.File;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-/**
- * @author lene
- * @since 29.03.11
- */
-public class FileUtilFindFileTest {
- private static File myTempFile;
- private static File myFirstFile;
- private static File mySecondFile;
-
- @BeforeClass
- public static void setUp() throws Exception {
- myTempFile = FileUtil.createTempDirectory("tEF", "",false); //NON-NLS
- myFirstFile = new File(myTempFile, "first");
- mySecondFile = new File(myTempFile, "second"); //NON-NLS
- assertTrue(myFirstFile.createNewFile());
- assertTrue(mySecondFile.createNewFile());
- }
-
- @AfterClass
- public static void tearDown() throws Exception {
- FileUtil.delete(myTempFile);
- }
-
- @Test
- public void nonExistingFileInNonExistentDirectory() throws Exception {
- String path = FileUtil.findFileInProvidedPath("123", "zero");//NON-NLS
- assertTrue(StringUtil.isEmpty(path));
- }
-
- @Test
- public void nonExistingFileInDirectory() throws Exception {
- String path = FileUtil.findFileInProvidedPath(myTempFile.getAbsolutePath(), "zero");//NON-NLS
- assertTrue(StringUtil.isEmpty(path));
- }
-
- @Test
- public void nonExistingFile() throws Exception {
- String path =
- FileUtil.findFileInProvidedPath(myFirstFile.getAbsolutePath() + "123", myFirstFile.getName() + "123");
- assertTrue(StringUtil.isEmpty(path));
- }
-
- @Test
- public void existingFileInDirectory() throws Exception {
- String path = FileUtil.findFileInProvidedPath(myTempFile.getAbsolutePath(), "first");
- assertEquals(path, myFirstFile.getAbsolutePath());
- }
-
- @Test
- public void existingFile() throws Exception {
- String path = FileUtil.findFileInProvidedPath(myFirstFile.getAbsolutePath(), "first");
- assertEquals(path, myFirstFile.getAbsolutePath());
- }
-
- @Test
- public void twoFilesOrderInDirectory() throws Exception {
- String path = FileUtil.findFileInProvidedPath(myTempFile.getAbsolutePath(), "first", "second"); //NON-NLS
- assertEquals(path, myFirstFile.getAbsolutePath());
- }
-
- @Test
- public void twoFilesOrderInDirectory2() throws Exception {
- String path = FileUtil.findFileInProvidedPath(myTempFile.getAbsolutePath(), "second", "first"); //NON-NLS
- assertEquals(path, mySecondFile.getAbsolutePath());
- }
-
- @Test
- public void twoFilesOrder() throws Exception {
- String path = FileUtil.findFileInProvidedPath(myFirstFile.getAbsolutePath(), "first", "second");//NON-NLS
- assertEquals(path, myFirstFile.getAbsolutePath());
- }
-
- @Test
- public void twoFilesOrder2() throws Exception {
- String path = FileUtil.findFileInProvidedPath(myFirstFile.getAbsolutePath(), "second", "first"); //NON-NLS
- assertEquals(path, myFirstFile.getAbsolutePath());
- }
-}
diff --git a/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilHeavyTest.java b/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilHeavyTest.java
index 9486270b0c52..0f667ad43f94 100644
--- a/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilHeavyTest.java
+++ b/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilHeavyTest.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.
@@ -15,10 +15,11 @@
*/
package com.intellij.openapi.util.io;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Processor;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
import org.junit.Test;
import java.io.File;
@@ -26,69 +27,86 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
+import static org.junit.Assert.*;
+import static org.junit.Assume.assumeTrue;
+
/**
- * Created with IntelliJ IDEA.
- * User: Irina.Chernushina
- * Date: 11/22/12
- * Time: 11:41 AM
+ * @author Irina.Chernushina, lene
*/
public class FileUtilHeavyTest {
- private File myTempDirectory;
-
- @Before
- public void setUp() throws Exception {
- myTempDirectory = FileUtil.createTempDirectory(getClass().getSimpleName() + ".", ".tmp");
+ private static File myTempDirectory;
+ private static File myVisitorTestDirectory;
+ private static File myFindTestDirectory;
+ private static File myFindTestFirstFile;
+ private static File myFindTestSecondFile;
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ myTempDirectory = FileUtil.createTempDirectory("FileUtilHeavyTest.", ".tmp");
+
+ myVisitorTestDirectory = IoTestUtil.createTestDir(myTempDirectory, "visitor_test_dir");
+ File dir1 = IoTestUtil.createTestDir(myVisitorTestDirectory, "dir1");
+ IoTestUtil.createTestFile(dir1, "1");
+ IoTestUtil.createTestFile(dir1, "2");
+ File dir2 = IoTestUtil.createTestDir(myVisitorTestDirectory, "dir2");
+ IoTestUtil.createTestFile(dir2, "1");
+ IoTestUtil.createTestFile(dir2, "2");
+ File dir21 = IoTestUtil.createTestDir(dir2, "inner");
+ IoTestUtil.createTestFile(dir21, "1");
+ IoTestUtil.createTestFile(dir21, "2");
+
+ myFindTestDirectory = IoTestUtil.createTestDir(myTempDirectory, "find_file_test_dir");
+ myFindTestFirstFile = IoTestUtil.createTestFile(myFindTestDirectory, "first");
+ myFindTestSecondFile = IoTestUtil.createTestFile(myFindTestDirectory, "second");
}
- @After
- public void tearDown() throws Exception {
+ @AfterClass
+ public static void tearDown() {
if (myTempDirectory != null) {
FileUtil.delete(myTempDirectory);
}
}
@Test
- public void testSimpleRecursiveIteration() throws Exception {
- final Tree tree = new Tree(myTempDirectory);
+ public void testProcessSimple() {
final Map<String, Integer> result = new HashMap<String, Integer>();
- FileUtil.processFilesRecursively(myTempDirectory, new Processor<File>() {
+ FileUtil.processFilesRecursively(myVisitorTestDirectory, new Processor<File>() {
@Override
public boolean process(File file) {
- final Integer integer = result.get(file.getName());
+ Integer integer = result.get(file.getName());
result.put(file.getName(), integer == null ? 1 : (integer + 1));
return true;
}
});
- Assert.assertEquals(6, result.size());
- Assert.assertEquals(1, result.get(myTempDirectory.getName()).intValue());
- Assert.assertEquals(3, result.get("1").intValue());
- Assert.assertEquals(3, result.get("2").intValue());
- Assert.assertEquals(1, result.get("dir1").intValue());
+ assertEquals(6, result.size());
+ assertEquals(1, result.get(myVisitorTestDirectory.getName()).intValue());
+ assertEquals(3, result.get("1").intValue());
+ assertEquals(3, result.get("2").intValue());
+ assertEquals(1, result.get("dir1").intValue());
}
@Test
- public void testStops() throws Exception {
- final Tree tree = new Tree(myTempDirectory);
+ public void testProcessStops() {
final int[] cnt = new int[]{0};
- FileUtil.processFilesRecursively(myTempDirectory, new Processor<File>() {
+ FileUtil.processFilesRecursively(myVisitorTestDirectory, new Processor<File>() {
@Override
public boolean process(File file) {
- ++ cnt[0];
+ ++cnt[0];
return false;
}
});
- Assert.assertEquals(1, cnt[0]);
+
+ assertEquals(1, cnt[0]);
}
@Test
- public void testDirectoryFilter() throws Exception {
- final Tree tree = new Tree(myTempDirectory);
+ public void testProcessDirectoryFilter() {
final Map<String, Integer> result = new HashMap<String, Integer>();
- FileUtil.processFilesRecursively(myTempDirectory, new Processor<File>() {
+ FileUtil.processFilesRecursively(myVisitorTestDirectory, new Processor<File>() {
@Override
public boolean process(File file) {
- final Integer integer = result.get(file.getName());
+ Integer integer = result.get(file.getName());
result.put(file.getName(), integer == null ? 1 : (integer + 1));
return true;
}
@@ -98,54 +116,115 @@ public class FileUtilHeavyTest {
return ! "dir2".equals(file.getName());
}
});
- Assert.assertEquals(5, result.size());
- Assert.assertEquals(1, result.get(myTempDirectory.getName()).intValue());
- Assert.assertEquals(1, result.get("1").intValue());
- Assert.assertEquals(1, result.get("2").intValue());
- Assert.assertEquals(1, result.get("dir1").intValue());
- Assert.assertEquals(1, result.get("dir2").intValue());
- Assert.assertNull(result.get("dir21"));
+
+ assertEquals(5, result.size());
+ assertEquals(1, result.get(myVisitorTestDirectory.getName()).intValue());
+ assertEquals(1, result.get("1").intValue());
+ assertEquals(1, result.get("2").intValue());
+ assertEquals(1, result.get("dir1").intValue());
+ assertEquals(1, result.get("dir2").intValue());
+ assertNull(result.get("dir21"));
}
- private static class Tree {
- private final File dir1;
- private final File file11;
- private final File file12;
+ @Test
+ public void nonExistingFileInNonExistentDirectory() {
+ String path = FileUtil.findFileInProvidedPath("123", "zero");
+ assertTrue(StringUtil.isEmpty(path));
+ }
- private final File dir2;
- private final File file21;
- private final File file22;
+ @Test
+ public void nonExistingFileInDirectory() {
+ String path = FileUtil.findFileInProvidedPath(myFindTestDirectory.getAbsolutePath(), "zero");
+ assertTrue(StringUtil.isEmpty(path));
+ }
- private final File dir21;
- private final File file211;
- private final File file212;
+ @Test
+ public void nonExistingFile() {
+ String path = FileUtil.findFileInProvidedPath(myFindTestFirstFile.getAbsolutePath() + "123", myFindTestFirstFile.getName() + "123");
+ assertTrue(StringUtil.isEmpty(path));
+ }
- private Tree(final File root) throws IOException {
- dir1 = new File(root, "dir1");
- dir2 = new File(root, "dir2");
- dir21 = new File(dir2, "inner");
+ @Test
+ public void existingFileInDirectory() {
+ String path = FileUtil.findFileInProvidedPath(myFindTestDirectory.getAbsolutePath(), "first");
+ assertEquals(path, myFindTestFirstFile.getAbsolutePath());
+ }
+
+ @Test
+ public void existingFile() {
+ String path = FileUtil.findFileInProvidedPath(myFindTestFirstFile.getAbsolutePath(), "first");
+ assertEquals(path, myFindTestFirstFile.getAbsolutePath());
+ }
- Assert.assertTrue(dir1.mkdir());
- Assert.assertTrue(dir2.mkdir());
- Assert.assertTrue(dir21.mkdir());
+ @Test
+ public void twoFilesOrderInDirectory() {
+ String path = FileUtil.findFileInProvidedPath(myFindTestDirectory.getAbsolutePath(), "first", "second");
+ assertEquals(path, myFindTestFirstFile.getAbsolutePath());
+ }
- file11 = new File(dir1, "1");
- file12 = new File(dir1, "2");
+ @Test
+ public void twoFilesOrderInDirectory2() {
+ String path = FileUtil.findFileInProvidedPath(myFindTestDirectory.getAbsolutePath(), "second", "first");
+ assertEquals(path, myFindTestSecondFile.getAbsolutePath());
+ }
- file21 = new File(dir2, "1");
- file22 = new File(dir2, "2");
+ @Test
+ public void twoFilesOrder() {
+ String path = FileUtil.findFileInProvidedPath(myFindTestFirstFile.getAbsolutePath(), "first", "second");
+ assertEquals(path, myFindTestFirstFile.getAbsolutePath());
+ }
- file211 = new File(dir21, "1");
- file212 = new File(dir21, "2");
+ @Test
+ public void twoFilesOrder2() {
+ String path = FileUtil.findFileInProvidedPath(myFindTestFirstFile.getAbsolutePath(), "second", "first");
+ assertEquals(path, myFindTestFirstFile.getAbsolutePath());
+ }
- file11.createNewFile();
- file12.createNewFile();
+ @Test
+ public void testRepeatableOperation() throws IOException {
+ abstract class CountableIOOperation implements FileUtilRt.RepeatableIOOperation<Boolean, IOException> {
+ private int count = 0;
- file21.createNewFile();
- file22.createNewFile();
+ @Override
+ public Boolean execute(boolean lastAttempt) throws IOException {
+ count++;
+ return stop(lastAttempt) ? true : null;
+ }
- file211.createNewFile();
- file212.createNewFile();
+ protected abstract boolean stop(boolean lastAttempt);
}
+
+ CountableIOOperation successful = new CountableIOOperation() {
+ @Override protected boolean stop(boolean lastAttempt) { return true; }
+ };
+ FileUtilRt.doIOOperation(successful);
+ assertEquals(1, successful.count);
+
+ CountableIOOperation failed = new CountableIOOperation() {
+ @Override protected boolean stop(boolean lastAttempt) { return false; }
+ };
+ FileUtilRt.doIOOperation(failed);
+ assertEquals(10, failed.count);
+
+ CountableIOOperation lastShot = new CountableIOOperation() {
+ @Override protected boolean stop(boolean lastAttempt) { return lastAttempt; }
+ };
+ FileUtilRt.doIOOperation(lastShot);
+ assertEquals(10, lastShot.count);
+ }
+
+ @Test
+ public void testSymlinkDeletion() throws Exception {
+ assumeTrue(SystemInfo.isWin7OrNewer || SystemInfo.isUnix);
+
+ File targetDir = IoTestUtil.createTestDir(myTempDirectory, "link_del_test_1");
+ IoTestUtil.createTestFile(targetDir, "file");
+ File linkDir = IoTestUtil.createTestDir(myTempDirectory, "link_del_test_2");
+ IoTestUtil.createTestFile(linkDir, "file");
+ IoTestUtil.createSymLink(targetDir.getPath(), linkDir.getPath() + "/link");
+
+ assertEquals(1, targetDir.list().length);
+ FileUtil.delete(linkDir);
+ assertEquals(1, targetDir.list().length);
}
}
diff --git a/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilTest.java b/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilLightTest.java
index 605dc42d7733..710e0c871d4b 100644
--- a/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilTest.java
+++ b/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilLightTest.java
@@ -22,13 +22,13 @@ import com.intellij.util.ThreeState;
import com.intellij.util.containers.Convertor;
import org.junit.Test;
-import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import static org.junit.Assert.*;
-public class FileUtilTest {
+public class FileUtilLightTest {
private static final char UNIX_SEPARATOR = '/';
private static final char WINDOWS_SEPARATOR = '\\';
@@ -102,62 +102,47 @@ public class FileUtilTest {
@Test
public void testRemoveAncestors() throws Exception {
- final String[] arr = {"/a/b/c", "/a", "/a/b", "/d/e", "/b/c", "/a/d", "/b/c/ttt", "/a/ewq.euq"};
- final String[] expectedResult = {"/a","/b/c","/d/e"};
- @SuppressWarnings("unchecked") final Collection<String> result = FileUtil.removeAncestors(Arrays.asList(arr), Convertor.SELF, PairProcessor.TRUE);
- assertArrayEquals(expectedResult, ArrayUtil.toStringArray(result));
+ List<String> data = Arrays.asList("/a/b/c", "/a", "/a/b", "/d/e", "/b/c", "/a/d", "/b/c/ttt", "/a/ewq.euq");
+ String[] expected = {"/a","/b/c","/d/e"};
+ @SuppressWarnings("unchecked") Collection<String> result = FileUtil.removeAncestors(data, Convertor.SELF, PairProcessor.TRUE);
+ assertArrayEquals(expected, ArrayUtil.toStringArray(result));
}
@Test
public void testCheckImmediateChildren() throws Exception {
- final String root = "/a";
- final String[] arr = {"/a/b/c", "/a", "/a/b", "/d/e", "/b/c", "/a/d", "/a/b/c/d/e"};
- final ThreeState[] expectedResult = {ThreeState.UNSURE, ThreeState.YES, ThreeState.YES, ThreeState.NO, ThreeState.NO, ThreeState.YES, ThreeState.UNSURE};
- final ThreeState[] expectedResult2 = {ThreeState.UNSURE, ThreeState.NO, ThreeState.YES, ThreeState.NO, ThreeState.NO, ThreeState.YES, ThreeState.UNSURE};
-
- for (int i = 0; i < arr.length; i++) {
- String s = arr[i];
- final ThreeState state = FileUtil.isAncestorThreeState(root, s, false);
- assertEquals(String.valueOf(i), expectedResult[i], state);
+ String root = "/a";
+ String[] data = {"/a/b/c", "/a", "/a/b", "/d/e", "/b/c", "/a/d", "/a/b/c/d/e"};
+ ThreeState[] expected1 = {ThreeState.UNSURE, ThreeState.YES, ThreeState.YES, ThreeState.NO, ThreeState.NO, ThreeState.YES, ThreeState.UNSURE};
+ ThreeState[] expected2 = {ThreeState.UNSURE, ThreeState.NO, ThreeState.YES, ThreeState.NO, ThreeState.NO, ThreeState.YES, ThreeState.UNSURE};
+
+ for (int i = 0; i < data.length; i++) {
+ ThreeState state = FileUtil.isAncestorThreeState(root, data[i], false);
+ assertEquals(String.valueOf(i), expected1[i], state);
}
- for (int i = 0; i < arr.length; i++) {
- String s = arr[i];
- final ThreeState state = FileUtil.isAncestorThreeState(root, s, true);
- assertEquals(String.valueOf(i), expectedResult2[i], state);
+ for (int i = 0; i < data.length; i++) {
+ ThreeState state = FileUtil.isAncestorThreeState(root, data[i], true);
+ assertEquals(String.valueOf(i), expected2[i], state);
}
}
@Test
- public void testRepeatableOperation() throws Exception {
- abstract class CountableIOOperation implements FileUtilRt.RepeatableIOOperation<Boolean, IOException> {
- private int count = 0;
-
- @Override
- public Boolean execute(boolean lastAttempt) throws IOException {
- count++;
- return stop(lastAttempt) ? true : null;
- }
-
- protected abstract boolean stop(boolean lastAttempt);
- }
-
- CountableIOOperation successful = new CountableIOOperation() {
- @Override protected boolean stop(boolean lastAttempt) { return true; }
- };
- FileUtilRt.doIOOperation(successful);
- assertEquals(1, successful.count);
-
- CountableIOOperation failed = new CountableIOOperation() {
- @Override protected boolean stop(boolean lastAttempt) { return false; }
- };
- FileUtilRt.doIOOperation(failed);
- assertEquals(10, failed.count);
-
- CountableIOOperation lastShot = new CountableIOOperation() {
- @Override protected boolean stop(boolean lastAttempt) { return lastAttempt; }
- };
- FileUtilRt.doIOOperation(lastShot);
- assertEquals(10, lastShot.count);
+ public void testStartsWith() {
+ assertTrue(FileUtil.startsWith("/usr/local/jeka", "/usr/local/jeka"));
+ assertTrue(FileUtil.startsWith("/usr/local/jeka", "/usr/local/"));
+ assertTrue(FileUtil.startsWith("/usr/local/jeka", "/usr/"));
+ assertTrue(FileUtil.startsWith("/usr/local/jeka", "/usr"));
+ assertTrue(FileUtil.startsWith("/usr/local/jeka", "/"));
+ assertTrue(FileUtil.startsWith("c:/idea", "c:/"));
+ assertTrue(FileUtil.startsWith("c:/idea", "c:"));
+ assertTrue(FileUtil.startsWith("c:/idea", ""));
+ assertTrue(FileUtil.startsWith("c:/idea/x", "C:/IDEA", false));
+
+ assertFalse(FileUtil.startsWith("/usr/local/jeka", "/usr/local/jek"));
+ assertFalse(FileUtil.startsWith("/usr/local/jeka", "/usr/local/aaa"));
+ assertFalse(FileUtil.startsWith("/usr/local/jeka", "/usr/local/jeka/"));
+ assertFalse(FileUtil.startsWith("/usr/local/jeka", "/aaa"));
+ assertFalse(FileUtil.startsWith("c:/idea2", "c:/idea"));
+ assertFalse(FileUtil.startsWith("c:/idea_branches/i18n", "c:/idea"));
}
}
diff --git a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java
index 6cc68d32d0e2..26f556e65e6f 100644
--- a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java
+++ b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java
@@ -83,6 +83,8 @@ public class StringUtilTest extends TestCase {
}
public void testNaturalCompare() {
+ assertEquals(1, StringUtil.naturalCompare("test011", "test10"));
+ assertEquals(1, StringUtil.naturalCompare("test10a", "test010"));
final List<String> strings = new ArrayList<String>(Arrays.asList("Test99", "tes0", "test0", "testing", "test", "test99", "test011", "test1",
"test 3", "test2", "test10a", "test10", "1.2.10.5", "1.2.9.1"));
final Comparator<String> c = new Comparator<String>() {
diff --git a/platform/util/util.iml b/platform/util/util.iml
index ec3dc4104ea7..74255456185d 100644
--- a/platform/util/util.iml
+++ b/platform/util/util.iml
@@ -23,6 +23,7 @@
<orderEntry type="library" name="Guava" level="project" />
<orderEntry type="library" name="CGLIB" level="project" />
<orderEntry type="library" name="asm" level="project" />
+ <orderEntry type="library" exported="" name="ForkJoin" level="project" />
</component>
<component name="copyright">
<Base>
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserNode.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserNode.java
index 9cc98f10ad79..7d4156873d7c 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserNode.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserNode.java
@@ -155,6 +155,7 @@ public class ChangesBrowserNode<T> extends DefaultMutableTreeNode {
ChangesBrowserNode child = (ChangesBrowserNode)enumeration.nextElement();
final Object value = child.getUserObject();
if (clazz.isAssignableFrom(value.getClass())) {
+ //noinspection unchecked
changes.add((T) value);
}
}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesTreeList.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesTreeList.java
index 39ad7fef8ade..8df7b62b159b 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesTreeList.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesTreeList.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.
@@ -42,11 +42,14 @@ import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.ui.treeStructure.actions.CollapseAllAction;
import com.intellij.ui.treeStructure.actions.ExpandAllAction;
+import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Convertor;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
import com.intellij.util.ui.tree.WideSelectionTreeUI;
+import gnu.trove.THashSet;
import gnu.trove.TIntArrayList;
+import gnu.trove.TIntHashSet;
import org.intellij.lang.annotations.JdkConstants;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -114,6 +117,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
myTree.setOpaque(false);
myTree.setCellRenderer(new MyTreeCellRenderer());
new TreeSpeedSearch(myTree, new Convertor<TreePath, String>() {
+ @Override
public String convert(TreePath o) {
ChangesBrowserNode node = (ChangesBrowserNode) o.getLastPathComponent();
return node.getTextPresentation();
@@ -127,6 +131,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
add(myTreeScrollPane = ScrollPaneFactory.createScrollPane(myTree), TREE_CARD);
new ListSpeedSearch(myList) {
+ @Override
protected String getElementText(Object element) {
if (element instanceof Change) {
return ChangesUtil.getFilePath((Change)element).getName();
@@ -140,6 +145,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
new MyToggleSelectionAction().registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0)), this);
if (myShowCheckboxes) {
registerKeyboardAction(new ActionListener() {
+ @Override
public void actionPerformed(ActionEvent e) {
includeSelection();
}
@@ -147,6 +153,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
}, KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
registerKeyboardAction(new ActionListener() {
+ @Override
public void actionPerformed(ActionEvent e) {
excludeSelection();
}
@@ -154,6 +161,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
}
registerKeyboardAction(new ActionListener() {
+ @Override
public void actionPerformed(ActionEvent e) {
myDoubleClickHandler.run();
}
@@ -257,6 +265,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
return myShowFlatten ? myList : myTree;
}
+ @Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
@@ -277,6 +286,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
select(wasSelected);
if (myList.hasFocus() || myTree.hasFocus()) {
SwingUtilities.invokeLater(new Runnable() {
+ @Override
public void run() {
requestFocus();
}
@@ -285,6 +295,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
}
+ @Override
public void requestFocus() {
if (myShowFlatten) {
myList.requestFocus();
@@ -302,12 +313,15 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
final boolean wasEmpty = myList.isEmpty();
final List<T> sortedChanges = new ArrayList<T>(changes);
Collections.sort(sortedChanges, new Comparator<T>() {
+ @Override
public int compare(final T o1, final T o2) {
return TreeModelBuilder.getPathForObject(o1).getName().compareToIgnoreCase(TreeModelBuilder.getPathForObject(o2).getName());
}
});
- final Set<Object> wasSelected = new HashSet<Object>(Arrays.asList(myList.getSelectedValues()));
+ @SuppressWarnings("deprecation")
+ final Set<Object> wasSelected = new THashSet<Object>(Arrays.asList(myList.getSelectedValues()));
+ //noinspection unchecked
myList.setModel(new AbstractListModel() {
@Override
public int getSize() {
@@ -327,6 +341,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
}
myTree.setModel(model);
if (! myAlwaysExpandList && ! wasEmpty) {
+ //noinspection ConstantConditions
state.applyTo(myTree, (DefaultMutableTreeNode) myTree.getModel().getRoot());
final TIntArrayList indices = new TIntArrayList();
@@ -341,6 +356,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
}
final Runnable runnable = new Runnable() {
+ @Override
public void run() {
if (myProject.isDisposed()) return;
TreeUtil.expandAll(myTree);
@@ -363,6 +379,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
while (enumeration.hasMoreElements()) {
ChangesBrowserNode node = (ChangesBrowserNode)enumeration.nextElement();
+ @SuppressWarnings("unchecked")
final CheckboxTree.NodeState state = getNodeStatus(node);
if (node != root && state == CheckboxTree.NodeState.CLEAR) {
myTree.collapsePath(new TreePath(node.getPath()));
@@ -372,6 +389,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
enumeration = root.depthFirstEnumeration();
while (enumeration.hasMoreElements()) {
ChangesBrowserNode node = (ChangesBrowserNode)enumeration.nextElement();
+ @SuppressWarnings("unchecked")
final CheckboxTree.NodeState state = getNodeStatus(node);
if (state == CheckboxTree.NodeState.FULL && node.isLeaf()) {
scrollRow = myTree.getRowForPath(new TreePath(node.getPath()));
@@ -471,18 +489,23 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
if (myShowFlatten) {
ListModel m = myList.getModel();
int size = m.getSize();
- List result = new ArrayList(size);
+ List<T> result = new ArrayList<T>(size);
for (int i = 0; i < size; i++) {
- result.add(m.getElementAt(i));
+ //noinspection unchecked
+ result.add((T)m.getElementAt(i));
}
return result;
}
else {
- final LinkedHashSet result = new LinkedHashSet();
+ final LinkedHashSet<T> result = new LinkedHashSet<T>();
TreeUtil.traverseDepth((ChangesBrowserNode)myTree.getModel().getRoot(), new TreeUtil.Traverse() {
+ @Override
public boolean accept(Object node) {
ChangesBrowserNode changeNode = (ChangesBrowserNode)node;
- if (changeNode.isLeaf()) result.addAll(changeNode.getAllChangesUnder());
+ if (changeNode.isLeaf()) {
+ //noinspection unchecked
+ result.addAll(changeNode.getAllChangesUnder());
+ }
return true;
}
});
@@ -501,37 +524,33 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
@NotNull
public List<T> getSelectedChanges() {
if (myShowFlatten) {
- final Object[] o = myList.getSelectedValues();
final List<T> changes = new ArrayList<T>();
- for (Object anO : o) {
+ //noinspection deprecation
+ for (Object anO : myList.getSelectedValues()) {
+ //noinspection unchecked
changes.add((T)anO);
}
-
return changes;
}
else {
- final List<T> changes = new ArrayList<T>();
- final Set<Integer> checkSet = new HashSet<Integer>();
final TreePath[] paths = myTree.getSelectionPaths();
- if (paths != null) {
+ if (paths == null) {
+ return Collections.emptyList();
+ }
+ else {
+ final List<T> changes = new ArrayList<T>();
+ final TIntHashSet checkSet = new TIntHashSet();
for (TreePath path : paths) {
- final ChangesBrowserNode node = (ChangesBrowserNode)path.getLastPathComponent();
- final List<T> objects = getSelectedObjects(node);
- for (T object : objects) {
- final int hash = object.hashCode();
- if (! checkSet.contains(hash)) {
+ //noinspection unchecked
+ List<T> list = getSelectedObjects((ChangesBrowserNode)path.getLastPathComponent());
+ for (T object : list) {
+ if (!checkSet.add(object.hashCode()) || !changes.contains(object)) {
changes.add(object);
- checkSet.add(hash);
- } else {
- if (! changes.contains(object)) {
- changes.add(object);
- }
}
}
}
+ return changes;
}
-
- return changes;
}
}
@@ -551,7 +570,10 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
}
else {
final TreePath path = myTree.getSelectionPath();
- if (path == null) return null;
+ if (path == null) {
+ return null;
+ }
+ //noinspection unchecked
return getLeadSelectedObject((ChangesBrowserNode<T>)path.getLastPathComponent());
}
}
@@ -561,15 +583,13 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
if (myShowFlatten) {
final int index = myList.getLeadSelectionIndex();
ListModel listModel = myList.getModel();
- if (index < 0 || index >= listModel.getSize()) return null;
//noinspection unchecked
- return (T)listModel.getElementAt(index);
+ return index < 0 || index >= listModel.getSize() ? null : (T)listModel.getElementAt(index);
}
else {
final TreePath path = myTree.getSelectionPath();
- if (path == null) return null;
- final List<T> changes = getSelectedObjects(((ChangesBrowserNode<T>)path.getLastPathComponent()));
- return changes.size() > 0 ? changes.get(0) : null;
+ //noinspection unchecked
+ return path == null ? null : ContainerUtil.getFirstItem(getSelectedObjects(((ChangesBrowserNode<T>)path.getLastPathComponent())));
}
}
@@ -630,18 +650,20 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
public AnAction[] getTreeActions() {
final ToggleShowDirectoriesAction directoriesAction = new ToggleShowDirectoriesAction();
final ExpandAllAction expandAllAction = new ExpandAllAction(myTree) {
+ @Override
public void update(AnActionEvent e) {
e.getPresentation().setVisible(!myShowFlatten);
}
};
final CollapseAllAction collapseAllAction = new CollapseAllAction(myTree) {
+ @Override
public void update(AnActionEvent e) {
e.getPresentation().setVisible(!myShowFlatten);
}
};
final AnAction[] actions = new AnAction[]{directoriesAction, expandAllAction, collapseAllAction};
directoriesAction.registerCustomShortcutSet(
- new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_P, SystemInfo.isMac ? KeyEvent.META_DOWN_MASK : KeyEvent.CTRL_DOWN_MASK)),
+ new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_P, SystemInfo.isMac ? InputEvent.META_DOWN_MASK : InputEvent.CTRL_DOWN_MASK)),
this);
expandAllAction.registerCustomShortcutSet(
new CustomShortcutSet(KeymapManager.getInstance().getActiveKeymap().getShortcuts(IdeActions.ACTION_EXPAND_ALL)),
@@ -685,6 +707,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
setOpaque(false);
}
+ @Override
public Component getTreeCellRendererComponent(JTree tree,
Object value,
boolean selected,
@@ -706,9 +729,8 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
myTextRenderer.setTransparentIconBackground(true);
myTextRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
if (myShowCheckboxes) {
- ChangesBrowserNode node = (ChangesBrowserNode)value;
-
- CheckboxTree.NodeState state = getNodeStatus(node);
+ @SuppressWarnings("unchecked")
+ CheckboxTree.NodeState state = getNodeStatus((ChangesBrowserNode)value);
myCheckBox.setSelected(state != CheckboxTree.NodeState.CLEAR);
myCheckBox.setEnabled(state != CheckboxTree.NodeState.PARTIAL);
revalidate();
@@ -808,9 +830,11 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
add(myTextRenderer, BorderLayout.CENTER);
}
+ @Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
myTextRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (myShowCheckboxes) {
+ //noinspection SuspiciousMethodCalls
myCheckbox.setSelected(myIncludedChanges.contains(value));
return this;
}
@@ -821,6 +845,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
}
private class MyToggleSelectionAction extends AnAction {
+ @Override
public void actionPerformed(AnActionEvent e) {
toggleSelection();
}
@@ -833,10 +858,12 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
AllIcons.Actions.GroupByPackage);
}
+ @Override
public boolean isSelected(AnActionEvent e) {
return (! myProject.isDisposed()) && !PropertiesComponent.getInstance(myProject).isTrueValue(FLATTEN_OPTION_KEY);
}
+ @Override
public void setSelected(AnActionEvent e, boolean state) {
PropertiesComponent.getInstance(myProject).setValue(FLATTEN_OPTION_KEY, String.valueOf(!state));
setShowFlatten(!state);
@@ -848,6 +875,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
super("Select All", "Select all items", AllIcons.Actions.Selectall);
}
+ @Override
public void actionPerformed(final AnActionEvent e) {
if (myShowFlatten) {
final int count = myList.getModel().getSize();
@@ -869,7 +897,9 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
final TreeNode root = (TreeNode) treeModel.getRoot();
final List<TreePath> treeSelection = new ArrayList<TreePath>(changes.size());
TreeUtil.traverse(root, new TreeUtil.Traverse() {
+ @Override
public boolean accept(Object node) {
+ @SuppressWarnings("unchecked")
final T change = (T) ((DefaultMutableTreeNode) node).getUserObject();
if (changes.contains(change)) {
treeSelection.add(new TreePath(((DefaultMutableTreeNode) node).getPath()));
@@ -884,6 +914,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
final int size = model.getSize();
final List<Integer> listSelection = new ArrayList<Integer>(changes.size());
for (int i = 0; i < size; i++) {
+ @SuppressWarnings("unchecked")
final T el = (T) model.getElementAt(i);
if (changes.contains(el)) {
listSelection.add(i);
@@ -925,7 +956,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
private final int myCheckboxWidth;
public MyTree(Project project, int checkboxWidth) {
- super(ChangesBrowserNode.create(ChangesTreeList.this.myProject, ChangesTreeList.ROOT));
+ super(ChangesBrowserNode.create(ChangesTreeList.this.myProject, ROOT));
myProject = project;
myCheckboxWidth = checkboxWidth;
}
@@ -959,12 +990,14 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
return super.getFileColorFor(object);
}
+ @Override
public Dimension getPreferredScrollableViewportSize() {
Dimension size = super.getPreferredScrollableViewportSize();
size = new Dimension(size.width + 10, size.height);
return size;
}
+ @Override
protected void processMouseEvent(MouseEvent e) {
if (e.getID() == MouseEvent.MOUSE_PRESSED) {
if (! myTree.isEnabled()) return;
@@ -981,6 +1014,7 @@ public abstract class ChangesTreeList<T> extends JPanel implements TypeSafeDataP
super.processMouseEvent(e);
}
+ @Override
public int getToggleClickCount() {
return -1;
}
diff --git a/platform/vcs-log/impl/src/META-INF/vcs-log.xml b/platform/vcs-log/impl/src/META-INF/vcs-log.xml
index c686d5a21001..8058a4a919c8 100644
--- a/platform/vcs-log/impl/src/META-INF/vcs-log.xml
+++ b/platform/vcs-log/impl/src/META-INF/vcs-log.xml
@@ -6,6 +6,9 @@
</component>
</project-components>
+ <extensionPoints>
+ <extensionPoint name="logProvider" interface="com.intellij.vcs.log.VcsLogProvider" area="IDEA_PROJECT"/>
+ </extensionPoints>
<extensions defaultExtensionNs="com.intellij">
<applicationService serviceInterface="com.intellij.vcs.log.VcsLogObjectsFactory" serviceImplementation="com.intellij.vcs.log.impl.VcsLogObjectsFactoryImpl" />
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java
index 59dfa172a349..d892acaf0f44 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XDebuggerEvaluateActionHandler.java
@@ -22,6 +22,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
@@ -37,6 +38,7 @@ import org.jetbrains.annotations.Nullable;
* @author nik
*/
public class XDebuggerEvaluateActionHandler extends XDebuggerSuspendedActionHandler {
+ @Override
protected void perform(@NotNull final XDebugSession session, final DataContext dataContext) {
XDebuggerEditorsProvider editorsProvider = session.getDebugProcess().getEditorsProvider();
XStackFrame stackFrame = session.getCurrentStackFrame();
@@ -44,7 +46,6 @@ public class XDebuggerEvaluateActionHandler extends XDebuggerSuspendedActionHand
final XDebuggerEvaluator evaluator = stackFrame.getEvaluator();
if (evaluator == null) return;
- @Nullable Project project = CommonDataKeys.PROJECT.getData(dataContext);
@Nullable Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
String selectedText = editor != null ? editor.getSelectionModel().getSelectedText() : null;
@@ -54,7 +55,7 @@ public class XDebuggerEvaluateActionHandler extends XDebuggerSuspendedActionHand
String text = selectedText;
if (text == null && editor != null) {
- text = getExpressionText(evaluator, project, editor);
+ text = getExpressionText(evaluator, CommonDataKeys.PROJECT.getData(dataContext), editor);
}
if (text == null) {
@@ -63,10 +64,7 @@ public class XDebuggerEvaluateActionHandler extends XDebuggerSuspendedActionHand
text = value.getEvaluationExpression();
}
}
- if (text == null) {
- text = "";
- }
- new XDebuggerEvaluationDialog(session, editorsProvider, evaluator, text, stackFrame.getSourcePosition()).show();
+ new XDebuggerEvaluationDialog(session, editorsProvider, evaluator, StringUtil.notNullize(text), stackFrame.getSourcePosition()).show();
}
@Nullable
@@ -86,6 +84,7 @@ public class XDebuggerEvaluateActionHandler extends XDebuggerSuspendedActionHand
return expressionInfo.second == null ? document.getText(expressionInfo.first) : expressionInfo.second;
}
+ @Override
protected boolean isEnabled(final @NotNull XDebugSession session, final DataContext dataContext) {
if (!super.isEnabled(session, dataContext)) {
return false;
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java
index a9ccf6995936..741b2878e8b2 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java
@@ -29,12 +29,14 @@ import com.intellij.xdebugger.XSourcePosition;
import com.intellij.xdebugger.evaluation.EvaluationMode;
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
+import com.intellij.xdebugger.frame.XStackFrame;
import com.intellij.xdebugger.impl.XDebugSessionImpl;
import com.intellij.xdebugger.impl.actions.XDebuggerActions;
import com.intellij.xdebugger.impl.ui.XDebuggerEditorBase;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreePanel;
import com.intellij.xdebugger.impl.ui.tree.nodes.EvaluatingExpressionRootNode;
+import com.intellij.xdebugger.impl.ui.tree.nodes.XDebuggerTreeNode;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -51,13 +53,12 @@ public class XDebuggerEvaluationDialog extends DialogWrapper {
private final JPanel myResultPanel;
private final XDebuggerTreePanel myTreePanel;
private EvaluationInputComponent myInputComponent;
- private final XDebuggerEvaluator myEvaluator;
private final XDebugSession mySession;
private final XDebuggerEditorsProvider myEditorsProvider;
private EvaluationMode myMode;
private final XSourcePosition mySourcePosition;
private final SwitchModeAction mySwitchModeAction;
- private final XDebugSessionAdapter mySessionListener;
+ private final boolean myIsCodeFragmentEvaluationSupported;
public XDebuggerEvaluationDialog(@NotNull XDebugSession session,
final @NotNull XDebuggerEditorsProvider editorsProvider,
@@ -72,7 +73,7 @@ public class XDebuggerEvaluationDialog extends DialogWrapper {
setOKButtonText(XDebuggerBundle.message("xdebugger.button.evaluate"));
setCancelButtonText(XDebuggerBundle.message("xdebugger.evaluate.dialog.close"));
- mySessionListener = new XDebugSessionAdapter() {
+ mySession.addSessionListener(new XDebugSessionAdapter() {
@Override
public void sessionStopped() {
SwingUtilities.invokeLater(new Runnable() {
@@ -82,15 +83,13 @@ public class XDebuggerEvaluationDialog extends DialogWrapper {
}
});
}
- };
- mySession.addSessionListener(mySessionListener, myDisposable);
+ }, myDisposable);
myTreePanel = new XDebuggerTreePanel(session.getProject(), editorsProvider, myDisposable, sourcePosition, XDebuggerActions.EVALUATE_DIALOG_TREE_POPUP_GROUP,
((XDebugSessionImpl)session).getValueMarkers());
myResultPanel = new JPanel(new BorderLayout());
myResultPanel.add(new JLabel(XDebuggerBundle.message("xdebugger.evaluate.label.result")), BorderLayout.NORTH);
myResultPanel.add(myTreePanel.getMainPanel(), BorderLayout.CENTER);
- myEvaluator = evaluator;
myMainPanel = new JPanel(new BorderLayout());
mySwitchModeAction = new SwitchModeAction();
@@ -109,8 +108,9 @@ public class XDebuggerEvaluationDialog extends DialogWrapper {
}.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.ALT_DOWN_MASK)), getRootPane(), myDisposable);
EvaluationMode mode = EvaluationMode.EXPRESSION;
+ myIsCodeFragmentEvaluationSupported = evaluator.isCodeFragmentEvaluationSupported();
if (text.indexOf('\n') != -1) {
- if (myEvaluator.isCodeFragmentEvaluationSupported()) {
+ if (myIsCodeFragmentEvaluationSupported) {
mode = EvaluationMode.CODE_FRAGMENT;
}
else {
@@ -129,7 +129,7 @@ public class XDebuggerEvaluationDialog extends DialogWrapper {
@NotNull
@Override
protected Action[] createActions() {
- if (myEvaluator.isCodeFragmentEvaluationSupported()) {
+ if (myIsCodeFragmentEvaluationSupported) {
return new Action[]{getOKAction(), mySwitchModeAction, getCancelAction()};
}
return super.createActions();
@@ -186,8 +186,13 @@ public class XDebuggerEvaluationDialog extends DialogWrapper {
private void evaluate() {
final XDebuggerTree tree = myTreePanel.getTree();
- final EvaluatingExpressionRootNode root = new EvaluatingExpressionRootNode(this, tree);
- tree.setRoot(root, false);
+ XDebuggerTreeNode root = tree.getRoot();
+ if (root instanceof EvaluatingExpressionRootNode) {
+ root.clearChildren();
+ }
+ else {
+ tree.setRoot(new EvaluatingExpressionRootNode(this, tree), false);
+ }
myResultPanel.invalidate();
myInputComponent.getInputEditor().selectAll();
}
@@ -206,7 +211,15 @@ public class XDebuggerEvaluationDialog extends DialogWrapper {
final XDebuggerEditorBase inputEditor = myInputComponent.getInputEditor();
inputEditor.saveTextInHistory();
String expression = inputEditor.getText();
- myEvaluator.evaluate(expression, evaluationCallback, null, inputEditor.getMode());
+
+ XStackFrame frame = mySession.getCurrentStackFrame();
+ XDebuggerEvaluator evaluator = frame == null ? null : frame.getEvaluator();
+ if (evaluator == null) {
+ evaluationCallback.errorOccurred(XDebuggerBundle.message("xdebugger.evaluate.stack.frame.has.not.evaluator"));
+ }
+ else {
+ evaluator.evaluate(expression, evaluationCallback, null, inputEditor.getMode());
+ }
}
@Override
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java
index 4a40d8a80c39..4a8011a8f808 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerUIUtil.java
@@ -18,15 +18,21 @@ package com.intellij.xdebugger.impl.ui;
import com.intellij.codeInsight.hint.HintUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.LogicalPosition;
+import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.popup.*;
+import com.intellij.openapi.ui.popup.Balloon;
+import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.ui.popup.JBPopupListener;
+import com.intellij.openapi.ui.popup.LightweightWindowEvent;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.DimensionService;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.ui.AppUIUtil;
+import com.intellij.ui.EditorTextField;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.xdebugger.XDebuggerManager;
@@ -102,12 +108,11 @@ public class DebuggerUIUtil {
}
public static void showValuePopup(@NotNull XFullValueEvaluator text, @NotNull MouseEvent event, @NotNull Project project) {
- final JTextArea textArea = new JTextArea("Evaluating...");
+ EditorTextField textArea = new EditorTextField(EditorFactory.getInstance().createDocument("Evaluating..."), project, FileTypes.PLAIN_TEXT, true);
+ textArea.setBackground(HintUtil.INFORMATION_COLOR);
+
final FullValueEvaluationCallbackImpl callback = new FullValueEvaluationCallbackImpl(textArea);
text.startEvaluation(callback);
- textArea.setEditable(false);
- textArea.setBackground(HintUtil.INFORMATION_COLOR);
- textArea.setLineWrap(false);
final JScrollPane component = ScrollPaneFactory.createScrollPane(textArea);
final Dimension frameSize = WindowManager.getInstance().getFrame(project).getSize();
@@ -119,7 +124,7 @@ public class DebuggerUIUtil {
component.setPreferredSize(size);
component.setBorder(null);
- final JBPopup popup = JBPopupFactory.getInstance().createComponentPopupBuilder(component, null)
+ JBPopupFactory.getInstance().createComponentPopupBuilder(component, null)
.setResizable(true)
.setMovable(true)
.setDimensionServiceKey(project, FULL_VALUE_POPUP_DIMENSION_KEY, false)
@@ -131,10 +136,7 @@ public class DebuggerUIUtil {
return true;
}
})
- .createPopup();
- final Component parentComponent = event.getComponent();
- RelativePoint point = new RelativePoint(parentComponent, new Point(event.getX()-size.width, event.getY()-size.height));
- popup.show(point);
+ .createPopup().show(new RelativePoint(event.getComponent(), new Point(event.getX() - size.width, event.getY() - size.height)));
}
public static void showXBreakpointEditorBalloon(final Project project,
@@ -265,9 +267,9 @@ public class DebuggerUIUtil {
private static class FullValueEvaluationCallbackImpl implements XFullValueEvaluator.XFullValueEvaluationCallback {
private final AtomicBoolean myObsolete = new AtomicBoolean(false);
- private final JTextArea myTextArea;
+ private final EditorTextField myTextArea;
- public FullValueEvaluationCallbackImpl(final JTextArea textArea) {
+ public FullValueEvaluationCallbackImpl(final EditorTextField textArea) {
myTextArea = textArea;
}
@@ -285,7 +287,7 @@ public class DebuggerUIUtil {
if (font != null) {
myTextArea.setFont(font);
}
- myTextArea.setCaretPosition(0);
+ myTextArea.getCaretModel().moveToOffset(0);
}
});
}
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/EvaluatingExpressionRootNode.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/EvaluatingExpressionRootNode.java
index ed35a48195d5..379b07c5426a 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/EvaluatingExpressionRootNode.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/EvaluatingExpressionRootNode.java
@@ -23,39 +23,70 @@ import com.intellij.xdebugger.frame.XValueChildrenList;
import com.intellij.xdebugger.frame.XValueContainer;
import com.intellij.xdebugger.impl.evaluate.XDebuggerEvaluationDialog;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
+import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreeListener;
import org.jetbrains.annotations.NotNull;
+import java.util.List;
+
/**
* @author nik
*/
public class EvaluatingExpressionRootNode extends XValueContainerNode<EvaluatingExpressionRootNode.EvaluatingResultContainer> {
public EvaluatingExpressionRootNode(XDebuggerEvaluationDialog evaluationDialog, final XDebuggerTree tree) {
- super(tree, null, new EvaluatingResultContainer(evaluationDialog));
+ super(tree, null, new EvaluatingResultContainer(evaluationDialog, tree));
setLeaf(false);
}
+ @Override
protected MessageTreeNode createLoadingMessageNode() {
return MessageTreeNode.createEvaluatingMessage(myTree, this);
}
- public static class EvaluatingResultContainer extends XValueContainer {
+ public static class EvaluatingResultContainer extends XValueContainer implements XDebuggerTreeListener {
private final XDebuggerEvaluationDialog myDialog;
+ private XDebuggerTree myTree;
- public EvaluatingResultContainer(final XDebuggerEvaluationDialog dialog) {
+ public EvaluatingResultContainer(final XDebuggerEvaluationDialog dialog, XDebuggerTree tree) {
myDialog = dialog;
+ myTree = tree;
}
+ @Override
public void computeChildren(@NotNull final XCompositeNode node) {
myDialog.startEvaluation(new XEvaluationCallbackBase() {
+ @Override
public void evaluated(@NotNull final XValue result) {
+ myTree.addTreeListener(EvaluatingResultContainer.this);
String name = UIUtil.removeMnemonic(XDebuggerBundle.message("xdebugger.evaluate.result"));
node.addChildren(XValueChildrenList.singleton(name, result), true);
}
+ @Override
public void errorOccurred(@NotNull final String errorMessage) {
node.setErrorMessage(errorMessage);
}
});
}
+
+ @Override
+ public void nodeLoaded(@NotNull RestorableStateNode node, String name) {
+ if (node.getParent() instanceof EvaluatingExpressionRootNode) {
+ if (node.isLeaf()) {
+ myTree.removeTreeListener(this);
+ }
+ else {
+ // cause children computing
+ node.getChildCount();
+ }
+ }
+ }
+
+ @Override
+ public void childrenLoaded(@NotNull XDebuggerTreeNode node, @NotNull List<XValueContainerNode<?>> children, boolean last) {
+ if (node.getParent() instanceof EvaluatingExpressionRootNode) {
+ myTree.removeTreeListener(this);
+ myTree.expandPath(node.getPath());
+ }
+ }
}
}
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/MessageTreeNode.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/MessageTreeNode.java
index 8f128132e732..a70c72bbecef 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/MessageTreeNode.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/MessageTreeNode.java
@@ -108,7 +108,7 @@ public class MessageTreeNode extends XDebuggerTreeNode {
XDebuggerUIConstants.COLLECTING_DATA_HIGHLIGHT_ATTRIBUTES, null);
}
- public static MessageTreeNode createEvaluatingMessage(XDebuggerTree tree, final XDebuggerTreeNode parent) {
+ public static MessageTreeNode createEvaluatingMessage(XDebuggerTree tree, @Nullable XDebuggerTreeNode parent) {
return new MessageTreeNode(tree, parent, XDebuggerUIConstants.EVALUATING_EXPRESSION_MESSAGE,
XDebuggerUIConstants.EVALUATING_EXPRESSION_HIGHLIGHT_ATTRIBUTES, null);
}
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java
index 5ba65e57335f..75f927ee91f1 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueNodeImpl.java
@@ -56,7 +56,7 @@ public class XValueNodeImpl extends XValueContainerNode<XValue> implements XValu
private XValuePresentation myValuePresentation;
//todo[nik] annotate 'name' with @NotNull
- public XValueNodeImpl(XDebuggerTree tree, XDebuggerTreeNode parent, String name, @NotNull XValue value) {
+ public XValueNodeImpl(XDebuggerTree tree, @Nullable XDebuggerTreeNode parent, String name, @NotNull XValue value) {
super(tree, parent, value);
myName = name;
@@ -159,6 +159,7 @@ public class XValueNodeImpl extends XValueContainerNode<XValue> implements XValu
valuePresenter.renderValue(new XValueTextRendererImpl(text));
}
+ @Override
public void markChanged() {
if (myChanged) return;