Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
小 白蛋
Intellij Community
Commits
b2a7e273
Commit
b2a7e273
authored
7 years ago
by
Pavel Dolgov
Browse files
Options
Download
Email Patches
Plain Diff
Java: UI for choosing source root when creating unresolved class for Java 9 service (IDEA-183452)
parent
7958911f
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateServiceClassFixBase.java
+49
-7
...sight/daemon/impl/quickfix/CreateServiceClassFixBase.java
java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateServiceImplementationClassFix.java
+106
-35
...on/impl/quickfix/CreateServiceImplementationClassFix.java
java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateServiceInterfaceOrClassFix.java
+117
-14
...aemon/impl/quickfix/CreateServiceInterfaceOrClassFix.java
with
272 additions
and
56 deletions
+272
-56
java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateServiceClassFixBase.java
+
49
-
7
View file @
b2a7e273
...
...
@@ -5,8 +5,12 @@ package com.intellij.codeInsight.daemon.impl.quickfix;
import
com.intellij.codeInsight.CodeInsightUtil
;
import
com.intellij.codeInsight.intention.IntentionAction
;
import
com.intellij.openapi.diagnostic.Logger
;
import
com.intellij.openapi.module.Module
;
import
com.intellij.openapi.project.Project
;
import
com.intellij.openapi.roots.JavaProjectRootsUtil
;
import
com.intellij.openapi.util.text.StringUtil
;
import
com.intellij.openapi.vfs.VirtualFile
;
import
com.intellij.psi.*
;
import
com.intellij.psi.search.GlobalSearchScope
;
import
com.intellij.psi.util.PsiUtil
;
...
...
@@ -14,12 +18,15 @@ import com.intellij.util.IncorrectOperationException;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
import
java.util.StringTokenizer
;
import
java.util.*
;
import
static
com
.
intellij
.
codeInsight
.
daemon
.
impl
.
quickfix
.
CreateFromUsageUtils
.
scheduleFileOrPackageCreationFailedMessageBox
;
/**
* @author Pavel.Dolgov
*/
public
abstract
class
CreateServiceClassFixBase
implements
IntentionAction
{
private
static
final
Logger
LOG
=
Logger
.
getInstance
(
CreateServiceClassFixBase
.
class
);
@Override
public
boolean
startInWriteAction
()
{
...
...
@@ -68,7 +75,10 @@ public abstract class CreateServiceClassFixBase implements IntentionAction {
}
@Nullable
protected
static
PsiClass
createClassInRootImpl
(
@NotNull
String
classFQN
,
@NotNull
PsiDirectory
rootDir
,
@Nullable
String
superClassName
)
{
protected
static
PsiClass
createClassInRoot
(
@NotNull
CreateClassKind
classKind
,
@NotNull
String
classFQN
,
@NotNull
PsiDirectory
rootDir
,
@Nullable
String
superClassName
)
{
PsiDirectory
directory
=
rootDir
;
String
lastName
;
StringTokenizer
st
=
new
StringTokenizer
(
classFQN
,
"."
);
...
...
@@ -82,20 +92,52 @@ public abstract class CreateServiceClassFixBase implements IntentionAction {
directory
=
directory
.
createSubdirectory
(
lastName
);
}
catch
(
IncorrectOperationException
e
)
{
CreateFromUsageUtils
.
scheduleFileOrPackageCreationFailedMessageBox
(
e
,
lastName
,
directory
,
true
);
scheduleFileOrPackageCreationFailedMessageBox
(
e
,
lastName
,
directory
,
true
);
return
null
;
}
}
}
PsiClass
psiClass
=
JavaDirectoryService
.
getInstance
().
createClass
(
directory
,
lastName
);
PsiUtil
.
setModifierProperty
(
psiClass
,
PsiModifier
.
PUBLIC
,
true
);
if
(
superClassName
!=
null
)
{
CreateFromUsageUtils
.
setupSuperClassReference
(
psiClass
,
superClassName
);
PsiClass
psiClass
=
createClass
(
classKind
,
lastName
,
directory
);
if
(
psiClass
!=
null
)
{
PsiUtil
.
setModifierProperty
(
psiClass
,
PsiModifier
.
PUBLIC
,
true
);
if
(
superClassName
!=
null
)
{
CreateFromUsageUtils
.
setupSuperClassReference
(
psiClass
,
superClassName
);
}
}
return
psiClass
;
}
@Nullable
private
static
PsiClass
createClass
(
@NotNull
CreateClassKind
classKind
,
String
name
,
PsiDirectory
directory
)
{
try
{
switch
(
classKind
)
{
case
CLASS:
return
JavaDirectoryService
.
getInstance
().
createClass
(
directory
,
name
);
case
INTERFACE:
return
JavaDirectoryService
.
getInstance
().
createInterface
(
directory
,
name
);
default
:
LOG
.
error
(
"Unsupported kind of service class: "
+
classKind
);
}
}
catch
(
final
IncorrectOperationException
e
)
{
scheduleFileOrPackageCreationFailedMessageBox
(
e
,
name
,
directory
,
false
);
}
return
null
;
}
protected
static
PsiDirectory
[]
getModuleRootDirs
(
Module
module
)
{
List
<
VirtualFile
>
roots
=
new
ArrayList
<>();
JavaProjectRootsUtil
.
collectSuitableDestinationSourceRoots
(
module
,
roots
);
PsiManager
psiManager
=
PsiManager
.
getInstance
(
module
.
getProject
());
return
roots
.
stream
()
.
map
(
psiManager:
:
findDirectory
)
.
filter
(
Objects:
:
nonNull
)
.
sorted
(
Comparator
.
comparing
(
psiDir
->
psiDir
.
getVirtualFile
().
getPresentableUrl
()))
.
toArray
(
PsiDirectory
[]::
new
);
}
protected
static
void
positionCursor
(
@Nullable
PsiClass
psiClass
)
{
if
(
psiClass
!=
null
)
{
CodeInsightUtil
.
positionCursor
(
psiClass
.
getProject
(),
psiClass
.
getContainingFile
(),
psiClass
);
...
...
This diff is collapsed.
Click to expand it.
java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateServiceImplementationClassFix.java
+
106
-
35
View file @
b2a7e273
...
...
@@ -11,21 +11,23 @@ import com.intellij.openapi.module.ModuleManager;
import
com.intellij.openapi.module.ModuleUtilCore
;
import
com.intellij.openapi.module.impl.scopes.ModulesScope
;
import
com.intellij.openapi.project.Project
;
import
com.intellij.openapi.roots.JavaProjectRootsUtil
;
import
com.intellij.openapi.ui.ComboBoxWithWidePopup
;
import
com.intellij.openapi.ui.DialogWrapper
;
import
com.intellij.openapi.ui.panel.JBPanelFactory
;
import
com.intellij.openapi.util.text.StringUtil
;
import
com.intellij.openapi.vfs.VirtualFile
;
import
com.intellij.psi.*
;
import
com.intellij.psi.search.GlobalSearchScope
;
import
com.intellij.ui.ListCellRendererWrapper
;
import
com.intellij.ui.components.JBRadioButton
;
import
com.intellij.util.IncorrectOperationException
;
import
com.intellij.util.ObjectUtils
;
import
org.jetbrains.annotations.Nls
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
import
java
.util.ArrayList
;
import
java
x.swing.*
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.Optional
;
/**
* @author Pavel.Dolgov
...
...
@@ -48,31 +50,25 @@ public class CreateServiceImplementationClassFix extends CreateServiceClassFixBa
if
(
providesStatement
!=
null
&&
providesStatement
.
getImplementationList
()
==
parent
)
{
myImplementationClassName
=
referenceElement
.
getQualifiedName
();
if
(
myImplementationClassName
!=
null
)
{
mySuperClassName
=
getSuperClassName
(
providesStatement
);
if
(
mySuperClassName
!=
null
)
{
Module
module
=
ModuleUtilCore
.
findModuleForFile
(
referenceElement
.
getContainingFile
());
myModuleName
=
module
!=
null
?
module
.
getName
()
:
null
;
PsiJavaCodeReferenceElement
interfaceReference
=
providesStatement
.
getInterfaceReference
();
if
(
interfaceReference
!=
null
)
{
PsiClass
superClass
=
ObjectUtils
.
tryCast
(
interfaceReference
.
resolve
(),
PsiClass
.
class
);
if
(
superClass
!=
null
)
{
mySuperClassName
=
superClass
.
getQualifiedName
();
if
(
mySuperClassName
!=
null
)
{
myModuleName
=
Optional
.
of
(
referenceElement
)
.
map
(
PsiElement:
:
getContainingFile
)
.
map
(
ModuleUtilCore:
:
findModuleForFile
)
.
map
(
Module:
:
getName
)
.
orElse
(
null
);
}
}
}
}
}
}
}
@Nullable
private
static
String
getSuperClassName
(
@NotNull
PsiProvidesStatement
providesStatement
)
{
PsiJavaCodeReferenceElement
interfaceReference
=
providesStatement
.
getInterfaceReference
();
if
(
interfaceReference
!=
null
)
{
if
(
interfaceReference
.
isQualified
())
{
return
interfaceReference
.
getQualifiedName
();
}
PsiClass
superClass
=
ObjectUtils
.
tryCast
(
interfaceReference
.
resolve
(),
PsiClass
.
class
);
if
(
superClass
!=
null
)
{
return
superClass
.
getQualifiedName
();
}
}
return
null
;
}
@Nls
@NotNull
@Override
...
...
@@ -112,15 +108,30 @@ public class CreateServiceImplementationClassFix extends CreateServiceClassFixBa
}
}
List
<
VirtualFile
>
roots
=
new
ArrayList
<>();
JavaProjectRootsUtil
.
collectSuitableDestinationSourceRoots
(
module
,
roots
);
PsiManager
psiManager
=
file
.
getManager
();
roots
.
stream
()
// todo UI for choosing source root similar to AddModuleDependencyFix
.
map
(
psiManager:
:
findDirectory
)
.
filter
(
Objects:
:
nonNull
)
.
findAny
()
.
ifPresent
(
this
::
createClassInRoot
);
PsiDirectory
[]
psiRootDirs
=
getModuleRootDirs
(
module
);
CreateServiceImplementationDialog
dialog
=
new
CreateServiceImplementationDialog
(
project
,
psiRootDirs
,
mySuperClassName
);
if
(
dialog
.
showAndGet
())
{
PsiDirectory
psiRootDir
=
dialog
.
getRootDir
();
if
(
psiRootDir
!=
null
)
{
boolean
isSubclass
=
dialog
.
isSubclass
();
PsiClass
psiClass
=
WriteAction
.
compute
(()
->
createClassInRoot
(
psiRootDir
,
isSubclass
));
positionCursor
(
psiClass
);
}
}
}
}
private
PsiClass
createClassInRoot
(
@NotNull
PsiDirectory
psiRootDir
,
boolean
isSubclass
)
{
Project
project
=
psiRootDir
.
getProject
();
PsiClass
psiImplClass
=
createClassInRoot
(
CreateClassKind
.
CLASS
,
myImplementationClassName
,
psiRootDir
,
isSubclass
?
mySuperClassName
:
null
);
if
(
psiImplClass
!=
null
&&
!
isSubclass
)
{
String
text
=
"public static "
+
mySuperClassName
+
" provider() { return null;}"
;
PsiMethod
method
=
JavaPsiFacade
.
getElementFactory
(
project
).
createMethodFromText
(
text
,
psiImplClass
.
getLBrace
());
psiImplClass
.
addAfter
(
method
,
psiImplClass
.
getLBrace
());
}
return
psiImplClass
;
}
@Nullable
...
...
@@ -136,8 +147,68 @@ public class CreateServiceImplementationClassFix extends CreateServiceClassFixBa
positionCursor
(
psiClass
);
}
private
void
createClassInRoot
(
PsiDirectory
rootDir
)
{
PsiClass
psiClass
=
WriteAction
.
compute
(()
->
createClassInRootImpl
(
myImplementationClassName
,
rootDir
,
mySuperClassName
));
positionCursor
(
psiClass
);
private
static
class
CreateServiceImplementationDialog
extends
DialogWrapper
{
private
final
ComboBoxWithWidePopup
<
PsiDirectory
>
myRootDirCombo
=
new
ComboBoxWithWidePopup
<>();
private
final
JRadioButton
mySubclassButton
=
new
JBRadioButton
();
private
final
JRadioButton
myProviderButton
=
new
JBRadioButton
();
protected
CreateServiceImplementationDialog
(
@Nullable
Project
project
,
@NotNull
PsiDirectory
[]
psiRootDirs
,
@NotNull
String
superClassName
)
{
super
(
project
);
setTitle
(
"Create Service Implementation"
);
mySubclassButton
.
setText
(
"Subclass of '"
+
superClassName
+
"'"
);
mySubclassButton
.
setSelected
(
true
);
myProviderButton
.
setText
(
"With 'provider()' method"
);
ButtonGroup
group
=
new
ButtonGroup
();
group
.
add
(
mySubclassButton
);
group
.
add
(
myProviderButton
);
myRootDirCombo
.
setRenderer
(
new
ListCellRendererWrapper
<
PsiDirectory
>()
{
@Override
public
void
customize
(
JList
list
,
PsiDirectory
psiDir
,
int
index
,
boolean
selected
,
boolean
hasFocus
)
{
setText
(
psiDir
!=
null
?
psiDir
.
getVirtualFile
().
getPresentableUrl
()
:
""
);
}
});
myRootDirCombo
.
setModel
(
new
DefaultComboBoxModel
<>(
psiRootDirs
));
init
();
}
@NotNull
@Override
protected
Action
[]
createActions
()
{
return
new
Action
[]{
getOKAction
(),
getCancelAction
()};
}
@Override
protected
JComponent
createCenterPanel
()
{
return
null
;
}
@Nullable
@Override
protected
JComponent
createNorthPanel
()
{
JPanel
radioButtons
=
JBPanelFactory
.
grid
()
.
add
(
JBPanelFactory
.
panel
(
mySubclassButton
))
.
add
(
JBPanelFactory
.
panel
(
myProviderButton
))
.
createPanel
();
return
JBPanelFactory
.
grid
()
.
add
(
JBPanelFactory
.
panel
(
radioButtons
).
withLabel
(
"Implementation:"
))
.
add
(
JBPanelFactory
.
panel
(
myRootDirCombo
).
withLabel
(
"Source root:"
))
.
createPanel
();
}
@Nullable
public
PsiDirectory
getRootDir
()
{
return
(
PsiDirectory
)
myRootDirCombo
.
getSelectedItem
();
}
public
boolean
isSubclass
()
{
return
mySubclassButton
.
isSelected
();
}
}
}
This diff is collapsed.
Click to expand it.
java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateServiceInterfaceOrClassFix.java
+
117
-
14
View file @
b2a7e273
...
...
@@ -4,19 +4,32 @@
package
com.intellij.codeInsight.daemon.impl.quickfix
;
import
com.intellij.codeInsight.daemon.QuickFixBundle
;
import
com.intellij.ide.actions.TemplateKindCombo
;
import
com.intellij.openapi.application.WriteAction
;
import
com.intellij.openapi.editor.Editor
;
import
com.intellij.openapi.module.Module
;
import
com.intellij.openapi.project.Project
;
import
com.intellij.openapi.roots.ProjectFileIndex
;
import
com.intellij.openapi.ui.ComboBoxWithWidePopup
;
import
com.intellij.openapi.ui.DialogWrapper
;
import
com.intellij.openapi.ui.panel.JBPanelFactory
;
import
com.intellij.openapi.util.text.StringUtil
;
import
com.intellij.psi.*
;
import
com.intellij.psi.search.GlobalSearchScope
;
import
com.intellij.refactoring.util.CommonRefactoringUtil
;
import
com.intellij.ui.ListCellRendererWrapper
;
import
com.intellij.util.ArrayUtil
;
import
com.intellij.util.IncorrectOperationException
;
import
com.intellij.util.PlatformIcons
;
import
one.util.streamex.StreamEx
;
import
org.jetbrains.annotations.Nls
;
import
org.jetbrains.annotations.NotNull
;
import
org.jetbrains.annotations.Nullable
;
import
javax.swing.*
;
import
java.util.Arrays
;
import
java.util.Objects
;
import
java.util.Comparator
;
import
java.util.Map
;
/**
* @author Pavel.Dolgov
...
...
@@ -82,27 +95,117 @@ public class CreateServiceInterfaceOrClassFix extends CreateServiceClassFixBase
while
(
psiPackage
==
null
&&
!
StringUtil
.
isEmpty
(
qualifierText
));
if
(
psiPackage
!=
null
)
{
ProjectFileIndex
index
=
ProjectFileIndex
.
SERVICE
.
getInstance
(
project
);
PsiManager
psiManager
=
PsiManager
.
getInstance
(
project
);
PsiDirectory
[]
directories
=
psiPackage
.
getDirectories
();
Arrays
.
stream
(
directories
)
// todo UI for choosing source root similar to AddModuleDependencyFix
.
map
(
directory
->
index
.
getSourceRootForFile
(
directory
.
getVirtualFile
()))
.
filter
(
Objects:
:
nonNull
)
.
map
(
psiManager:
:
findDirectory
)
.
filter
(
Objects:
:
nonNull
)
.
findAny
()
.
ifPresent
(
this
::
createClassInRoot
);
Map
<
Module
,
PsiDirectory
[]>
psiRootDirs
=
getModuleRootDirs
(
psiPackage
);
if
(!
psiRootDirs
.
isEmpty
())
{
CreateServiceInterfaceDialog
dialog
=
new
CreateServiceInterfaceDialog
(
project
,
psiRootDirs
);
if
(
dialog
.
showAndGet
())
{
PsiClass
psiClass
=
WriteAction
.
compute
(()
->
{
PsiDirectory
rootDir
=
dialog
.
getRootDir
();
if
(
rootDir
!=
null
)
{
return
createClassInRoot
(
dialog
.
getClassKind
(),
myInterfaceName
,
rootDir
,
null
);
}
return
null
;
});
positionCursor
(
psiClass
);
}
}
}
}
@NotNull
private
static
Map
<
Module
,
PsiDirectory
[]>
getModuleRootDirs
(
@NotNull
PsiPackage
psiPackage
)
{
ProjectFileIndex
index
=
ProjectFileIndex
.
SERVICE
.
getInstance
(
psiPackage
.
getProject
());
return
StreamEx
.
of
(
psiPackage
.
getDirectories
())
.
map
(
PsiDirectory:
:
getVirtualFile
)
.
map
(
index:
:
getSourceRootForFile
)
.
nonNull
()
.
map
(
index:
:
getModuleForFile
)
.
nonNull
()
.
distinct
()
.
mapToEntry
(
CreateServiceClassFixBase:
:
getModuleRootDirs
)
.
filterValues
(
dirs
->
!
ArrayUtil
.
isEmpty
(
dirs
))
.
toMap
();
}
private
void
createClassInOuter
(
@NotNull
String
qualifierText
,
@NotNull
PsiClass
outerClass
)
{
String
name
=
myInterfaceName
.
substring
(
qualifierText
.
length
()
+
1
);
PsiClass
psiClass
=
WriteAction
.
compute
(()
->
createClassInOuterImpl
(
name
,
outerClass
,
null
));
positionCursor
(
psiClass
);
}
private
void
createClassInRoot
(
@NotNull
PsiDirectory
rootDir
)
{
PsiClass
psiClass
=
WriteAction
.
compute
(()
->
createClassInRootImpl
(
myInterfaceName
,
rootDir
,
null
));
positionCursor
(
psiClass
);
private
static
class
CreateServiceInterfaceDialog
extends
DialogWrapper
{
private
final
ComboBoxWithWidePopup
<
Module
>
myModuleCombo
=
new
ComboBoxWithWidePopup
<>();
private
final
ComboBoxWithWidePopup
<
PsiDirectory
>
myRootDirCombo
=
new
ComboBoxWithWidePopup
<>();
private
final
TemplateKindCombo
myKindCombo
=
new
TemplateKindCombo
();
protected
CreateServiceInterfaceDialog
(
@Nullable
Project
project
,
@NotNull
Map
<
Module
,
PsiDirectory
[]>
psiRootDirs
)
{
super
(
project
);
setTitle
(
"Create Service Interface or Class"
);
myModuleCombo
.
setRenderer
(
new
ListCellRendererWrapper
<
Module
>()
{
@Override
public
void
customize
(
JList
list
,
Module
module
,
int
index
,
boolean
selected
,
boolean
hasFocus
)
{
setText
(
module
.
getName
());
}
});
myRootDirCombo
.
setRenderer
(
new
ListCellRendererWrapper
<
PsiDirectory
>()
{
@Override
public
void
customize
(
JList
list
,
PsiDirectory
psiDir
,
int
index
,
boolean
selected
,
boolean
hasFocus
)
{
setText
(
psiDir
!=
null
?
psiDir
.
getVirtualFile
().
getPresentableUrl
()
:
""
);
}
});
myModuleCombo
.
addActionListener
(
e
->
updateRootDirsCombo
(
psiRootDirs
));
Module
[]
modules
=
psiRootDirs
.
keySet
().
toArray
(
Module
.
EMPTY_ARRAY
);
Arrays
.
sort
(
modules
,
Comparator
.
comparing
(
Module:
:
getName
));
myModuleCombo
.
setModel
(
new
DefaultComboBoxModel
<>(
modules
));
updateRootDirsCombo
(
psiRootDirs
);
myKindCombo
.
addItem
(
CommonRefactoringUtil
.
capitalize
(
CreateClassKind
.
CLASS
.
getDescription
()),
PlatformIcons
.
CLASS_ICON
,
CreateClassKind
.
CLASS
.
name
());
myKindCombo
.
addItem
(
CommonRefactoringUtil
.
capitalize
(
CreateClassKind
.
INTERFACE
.
getDescription
()),
PlatformIcons
.
INTERFACE_ICON
,
CreateClassKind
.
INTERFACE
.
name
());
init
();
}
private
void
updateRootDirsCombo
(
@NotNull
Map
<
Module
,
PsiDirectory
[]>
psiRootDirs
)
{
Module
module
=
(
Module
)
myModuleCombo
.
getSelectedItem
();
PsiDirectory
[]
moduleRootDirs
=
psiRootDirs
.
getOrDefault
(
module
,
PsiDirectory
.
EMPTY_ARRAY
);
myRootDirCombo
.
setModel
(
new
DefaultComboBoxModel
<>(
moduleRootDirs
));
}
@NotNull
@Override
protected
Action
[]
createActions
()
{
return
new
Action
[]{
getOKAction
(),
getCancelAction
()};
}
@Override
protected
JComponent
createCenterPanel
()
{
return
null
;
}
@Nullable
@Override
protected
JComponent
createNorthPanel
()
{
return
JBPanelFactory
.
grid
()
.
add
(
JBPanelFactory
.
panel
(
myModuleCombo
).
withLabel
(
"Module:"
))
.
add
(
JBPanelFactory
.
panel
(
myRootDirCombo
).
withLabel
(
"Source root:"
))
.
add
(
JBPanelFactory
.
panel
(
myKindCombo
).
withLabel
(
"Kind:"
))
.
createPanel
();
}
@Nullable
public
PsiDirectory
getRootDir
()
{
return
(
PsiDirectory
)
myRootDirCombo
.
getSelectedItem
();
}
@NotNull
public
CreateClassKind
getClassKind
()
{
return
CreateClassKind
.
valueOf
(
myKindCombo
.
getSelectedName
());
}
}
}
This diff is collapsed.
Click to expand it.
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment