@@ -12,6 +12,7 @@ import com.intellij.execution.runners.ExecutionEnvironment
12
12
import com.intellij.execution.runners.ProgramRunner
13
13
import com.intellij.icons.AllIcons
14
14
import com.intellij.ide.ActivityTracker
15
+ import com.intellij.ide.dnd.*
15
16
import com.intellij.openapi.actionSystem.*
16
17
import com.intellij.openapi.actionSystem.ex.InlineActionsHolder
17
18
import com.intellij.openapi.actionSystem.impl.PresentationFactory
@@ -32,6 +33,7 @@ import com.intellij.openapi.wm.ToolWindowId
32
33
import com.intellij.psi.PsiFile
33
34
import com.intellij.ui.ColorUtil
34
35
import com.intellij.ui.components.JBList
36
+ import com.intellij.ui.popup.ActionPopupStep
35
37
import com.intellij.ui.popup.KeepingPopupOpenAction
36
38
import com.intellij.ui.popup.PopupFactoryImpl
37
39
import com.intellij.ui.popup.WizardPopup
@@ -83,7 +85,7 @@ internal fun createRunConfigurationsActionGroup(project: Project, e: AnActionEve
83
85
HideableDefaultActionGroup (folderName) { shouldBeShown(null , it) }
84
86
}
85
87
val filteringSubActions: (RunnerAndConfigurationSettings , String ) -> AnAction = { configuration, folderName ->
86
- createRunConfigurationWithInlines(runExecutor, debugExecutor, configuration, project, e) { holdingFilter ->
88
+ createRunConfigurationWithInlines(runExecutor, debugExecutor, configuration, project, e, pinned ) { holdingFilter ->
87
89
holdingFilter && ! recents.contains(configuration)
88
90
}.also {
89
91
it.templatePresentation.putClientProperty(Presentation .PROP_VALUE , folderName)
@@ -136,9 +138,15 @@ internal class RunConfigurationsActionGroupPopup(actionGroup: ActionGroup, dataC
136
138
PopupFactoryImpl .ActionGroupPopup (null , actionGroup, dataContext, false , false , true , false ,
137
139
disposeCallback, 30 , null , null , PresentationFactory (), false ) {
138
140
141
+ private val dragRange: IntRange = 0 until RunConfigurationStartHistory .getInstance(project).pinned().size + 1
142
+
139
143
init {
140
- (list as ? JBList <* >)?.setExpandableItemsEnabled(false )
141
- (list as ? JBList <* >)?.dragEnabled = true
144
+ list.setExpandableItemsEnabled(false )
145
+ if (! dragRange.isEmpty()) {
146
+ val dndManager = DnDManager .getInstance()
147
+ dndManager.registerSource(MyDnDSource (), list, this )
148
+ dndManager.registerTarget(MyDnDTarget (), list, this )
149
+ }
142
150
}
143
151
144
152
override fun createPopup (parent : WizardPopup ? , step : PopupStep <* >? , parentValue : Any? ): WizardPopup {
@@ -156,6 +164,63 @@ internal class RunConfigurationsActionGroupPopup(actionGroup: ActionGroup, dataC
156
164
fun shouldBeShowing (action : AnAction , holdingFilter : Boolean ): Boolean {
157
165
return if (action is HideableAction ) return action.shouldBeShown(holdingFilter) else true
158
166
}
167
+
168
+ override fun getList (): JBList <* > {
169
+ return super .getList() as JBList <* >
170
+ }
171
+
172
+ private fun isPossibleToDragItem (index : Int ): Boolean {
173
+ return dragRange.contains(index)
174
+ }
175
+
176
+ private data class DraggedIndex (val from : Int )
177
+
178
+ private inner class MyDnDTarget : DnDTarget {
179
+ override fun update (aEvent : DnDEvent ): Boolean {
180
+ val from = (aEvent.attachedObject as ? DraggedIndex )?.from
181
+ if (from is Int ) {
182
+ val targetIndex: Int = list.locationToIndex(aEvent.point)
183
+ val possible: Boolean = isPossibleToDragItem(targetIndex)
184
+ list.setDropTargetIndex(if (possible && wouldActuallyMove(from, targetIndex)) targetIndex else - 1 )
185
+ aEvent.isDropPossible = possible
186
+ }
187
+ else {
188
+ aEvent.isDropPossible = false
189
+ }
190
+ return false
191
+ }
192
+
193
+ override fun drop (aEvent : DnDEvent ) {
194
+ list.setDropTargetIndex(- 1 )
195
+ val from = (aEvent.attachedObject as ? DraggedIndex )?.from
196
+ if (from is Int ) {
197
+ val targetIndex: Int = list.locationToIndex(aEvent.point)
198
+ if (wouldActuallyMove(from, targetIndex)) {
199
+ (step as ActionPopupStep ).reorderItems(from, targetIndex, 0 )
200
+ RunConfigurationStartHistory .getInstance(project).reorderItems(from, targetIndex)
201
+ listModel.syncModel()
202
+ }
203
+ }
204
+ }
205
+
206
+ private fun wouldActuallyMove (from : Int , targetIndex : Int ) = from != targetIndex && from + 1 != targetIndex
207
+
208
+ override fun cleanUpOnLeave () {
209
+ list.setDropTargetIndex(- 1 )
210
+ }
211
+ }
212
+
213
+ private inner class MyDnDSource : DnDSource {
214
+ override fun canStartDragging (action : DnDAction , dragOrigin : Point ): Boolean {
215
+ return isPossibleToDragItem(list.locationToIndex(dragOrigin))
216
+ }
217
+
218
+ override fun startDragging (action : DnDAction , dragOrigin : Point ): DnDDragStartBean ? {
219
+ val index: Int = list.locationToIndex(dragOrigin)
220
+ if (index < 0 ) return null
221
+ return DnDDragStartBean (DraggedIndex (index))
222
+ }
223
+ }
159
224
}
160
225
161
226
private interface HideableAction {
@@ -460,6 +525,13 @@ class RunConfigurationStartHistory(private val project: Project) : PersistentSta
460
525
_state = State (_state .history, newPinned, _state .allConfigurationsExpanded)
461
526
}
462
527
528
+ fun reorderItems (from : Int , where : Int ) {
529
+ val list = _state .pinned.toMutableList()
530
+ list.add(where, list[from])
531
+ list.removeAt(if (where < from) from + 1 else from)
532
+ _state = State (_state .history, list.toMutableSet(), _state .allConfigurationsExpanded)
533
+ }
534
+
463
535
fun register (setting : RunnerAndConfigurationSettings ) {
464
536
_state = State (_state .history.take(max(5 , _state .pinned.size + recentLimit* 2 )).toMutableList().apply {
465
537
add(0 , Element (setting.uniqueID))
0 commit comments