Repository: spyder-ide/spyder

Issue:
Add "Insert above/below" options for lists in variable explorer
## Problem Description

My team works on Spyder integrating our system as a plugin, and we edit some variables using Variable Explorer(specifically lists). Would be very useful to have the option "insert bellow" when you right click on an item, because the "insert" option, inserts the item in the current position. So if you click in the last item and choose insert, variable explorer inserts it in penultimate position. To have it as the last item, you need to duplicate the last item and edit it(what is not very intuitive).

### What steps reproduce the problem?

1. create any list in the editor, for example: `test_list = [1,2,3,4,5]`
2. Click in Run->Run with "IPython console" and "Variable explorer" active
3. Double-click in test_list variable in "Variable explorer" window.
4. In the opened window, right click on the last item and choose "insert"
5. Type 6 for example and hit enter,
6. Validate that the item is inserted between 4 and 5 items.
7. The final sequence is 1,2,3,4,**6**,5

### What is the expected output? What do you see instead?
I suggest to add the option "insert bellow" when editing lists. How: Changing in collectionseditor.py file, class BaseTableView, setup_menu() method the following:


```
#FROM:
self.insert_action = create_action(self, _("Insert"),
                                           icon=ima.icon('insert'),
                                           triggered=self.insert_item)
#TO:
self.insert_action_above = create_action(self, _("Insert above"),
                                           icon=ima.icon('insert'),
                                           triggered=lambda:self.insert_item(bellow=False))
self.insert_action_bellow = create_action(self, _("Insert bellow"),
                                           icon=ima.icon('insert'),
                                           triggered=lambda:self.insert_item(bellow=True))

#FROM:
 menu_actions = [self.edit_action, self.plot_action, self.hist_action,
                        self.imshow_action, self.save_array_action,
                        self.insert_action, self.remove_action,
                        self.copy_action, self.paste_action,
                        self.view_action,
                        None, self.rename_action, self.duplicate_action,
                        None, resize_action, resize_columns_action]
#TO:
 menu_actions = [self.edit_action, self.plot_action, self.hist_action,
                        self.imshow_action, self.save_array_action,
                        self.insert_action_above, self.insert_action_bellow, self.remove_action,
                        self.copy_action, self.paste_action,
                        self.view_action,
                        None, self.rename_action, self.duplicate_action,
                        None, resize_action, resize_columns_action]

#FROM:
add_actions(self.empty_ws_menu,
                    [self.insert_action, self.paste_action,
                     None, resize_action, resize_columns_action])
#TO:
add_actions(self.empty_ws_menu,
                    [self.insert_action_above, self.insert_action_bellow, self.paste_action,
                     None, resize_action, resize_columns_action])
```

and in insert_item(self) method, change:

```
#FROM:
@Slot()
    def insert_item(self):
#TO:
@Slot()
    def insert_item(self, bellow=True):


#FROM:
        if not index.isValid():
            row = self.source_model.rowCount()
        else:
            row = self.proxy_model.mapToSource(index).row()
#TO:
        if not index.isValid():
            row = self.source_model.rowCount()
        else:
            if bellow:
                row = self.proxy_model.mapToSource(index).row()+1
            else:
                row = self.proxy_model.mapToSource(index).row()
```

### Paste Traceback/Error Below (if applicable)
<!--- Copy from error dialog or View > Panes > Internal Console --->

```python-traceback

PASTE TRACEBACK HERE

```

## Versions
<!--- You can get this information from Help > About Spyder...
or (if Spyder won't launch) the "conda list" command
from the Anaconda Prompt/Terminal/command line. --->

* Spyder version: 4.1.3
* Python version: 3.8.3
* Qt version: 1.9.0
* PyQt version: 5.12.3
* Operating System name/version: 

### Dependencies
<!--- Please go to the menu entry Help > Dependencies,
press the Copy to clipboard button and paste below --->

```
PASTE DEPENDENCIES HERE
```



Discussion:
Thanks for opening this issue @dpturibio! It sounds like a great idea. Would you be interested in opening a pull request with these changes o would you want someone from the team to do it?
Thank you for the prompt reply @juanis2112 , I will open a pull request and link with this issue.

Resolving patch:
diff --git a/spyder/plugins/variableexplorer/widgets/collectionseditor.py b/spyder/plugins/variableexplorer/widgets/collectionseditor.py
--- a/spyder/plugins/variableexplorer/widgets/collectionseditor.py
+++ b/spyder/plugins/variableexplorer/widgets/collectionseditor.py
@@ -542,6 +542,8 @@ def __init__(self, parent):
         self.imshow_action = None
         self.save_array_action = None
         self.insert_action = None
+        self.insert_action_above = None
+        self.insert_action_below = None
         self.remove_action = None
         self.minmax_action = None
         self.rename_action = None
@@ -602,9 +604,21 @@ def setup_menu(self, minmax):
                                                icon=ima.icon('filesave'),
                                                triggered=self.save_array)
         self.save_array_action.setVisible(False)
-        self.insert_action = create_action(self, _("Insert"),
-                                           icon=ima.icon('insert'),
-                                           triggered=self.insert_item)
+        self.insert_action = create_action(
+            self, _("Insert"),
+            icon=ima.icon('insert'),
+            triggered=lambda: self.insert_item(below=False)
+        )
+        self.insert_action_above = create_action(
+            self, _("Insert above"),
+            icon=ima.icon('insert'),
+            triggered=lambda: self.insert_item(below=False)
+        )
+        self.insert_action_below = create_action(
+            self, _("Insert below"),
+            icon=ima.icon('insert'),
+            triggered=lambda: self.insert_item(below=True)
+        )
         self.remove_action = create_action(self, _("Remove"),
                                            icon=ima.icon('editdelete'),
                                            triggered=self.remove_item)
@@ -626,9 +640,10 @@ def setup_menu(self, minmax):
         menu = QMenu(self)
         menu_actions = [self.edit_action, self.plot_action, self.hist_action,
                         self.imshow_action, self.save_array_action,
-                        self.insert_action, self.remove_action,
-                        self.copy_action, self.paste_action,
-                        self.view_action,
+                        self.insert_action,
+                        self.insert_action_above, self.insert_action_below,
+                        self.remove_action, self.copy_action,
+                        self.paste_action, self.view_action,
                         None, self.rename_action, self.duplicate_action,
                         None, resize_action, resize_columns_action]
         if ndarray is not FakeObject:
@@ -636,8 +651,9 @@ def setup_menu(self, minmax):
         add_actions(menu, menu_actions)
         self.empty_ws_menu = QMenu(self)
         add_actions(self.empty_ws_menu,
-                    [self.insert_action, self.paste_action,
-                     None, resize_action, resize_columns_action])
+                    [self.insert_action_above, self.insert_action_below,
+                    self.insert_action, self.paste_action, None, 
+                    resize_action, resize_columns_action])
         return menu
 
     # ------ Remote/local API -------------------------------------------------
@@ -721,8 +737,12 @@ def refresh_plot_entries(self, index):
         else:
             is_array = condition_plot = condition_imshow = is_list \
                      = condition_hist = False
+        is_list_instance = isinstance(self.source_model.get_data(), list)
         self.plot_action.setVisible(condition_plot or is_list)
         self.hist_action.setVisible(condition_hist or is_list)
+        self.insert_action.setVisible(not is_list_instance)
+        self.insert_action_above.setVisible(is_list_instance)
+        self.insert_action_below.setVisible(is_list_instance)
         self.imshow_action.setVisible(condition_imshow)
         self.save_array_action.setVisible(is_array)
 
@@ -932,16 +952,22 @@ def rename_item(self, new_name=None):
         self.copy_item(erase_original=True, new_name=new_name)
 
     @Slot()
-    def insert_item(self):
+    def insert_item(self, below=True):
         """Insert item"""
         index = self.currentIndex()
         if not index.isValid():
             row = self.source_model.rowCount()
         else:
             if self.proxy_model:
-                row = self.proxy_model.mapToSource(index).row()
+                if below:
+                    row = self.proxy_model.mapToSource(index).row() + 1
+                else:
+                    row = self.proxy_model.mapToSource(index).row()
             else:
-                row = index.row()
+                if below:
+                    row = index.row() + 1
+                else:
+                    row = index.row()
         data = self.source_model.get_data()
         if isinstance(data, list):
             key = row
@@ -1247,7 +1273,9 @@ def refresh_menu(self):
                     and not self.readonly
         self.edit_action.setEnabled( condition )
         self.remove_action.setEnabled( condition )
-        self.insert_action.setEnabled( not self.readonly )
+        self.insert_action.setEnabled(not self.readonly)
+        self.insert_action_above.setEnabled(not self.readonly)
+        self.insert_action_below.setEnabled(not self.readonly)
         self.duplicate_action.setEnabled(condition)
         condition_rename = not isinstance(data, (tuple, list, set))
         self.rename_action.setEnabled(condition_rename)


Test patch: