Repository: spyder-ide/spyder

Issue:
Go to line is not working in the outline explorer when clicking on the last item of a file
<!--- **PLEASE READ:** When submitting here, please ensure you've completed the following checklist and checked the boxes to confirm. Issue reports without it may be closed. Thanks! --->

### Issue Report Checklist

* [x] Searched the [issues page](https://github.com/spyder-ide/spyder/issues?q=is%3Aissue) for similar reports
* [x] Read the relevant sections of the [Spyder Troubleshooting Guide](https://github.com/spyder-ide/spyder/wiki/Troubleshooting-Guide-and-FAQ) and followed its advice
* [x] Reproduced the issue after updating with ``conda update spyder`` (or ``pip``, if not using Anaconda)
* [x] Could not reproduce inside ``jupyter qtconsole`` (if console-related)
* [x] Tried basic troubleshooting (if a bug/error)
    * [x] Restarted Spyder
    * [x] Reset preferences with ``spyder --reset``
    * [x] Reinstalled the latest version of [Anaconda](https://www.anaconda.com/download/)
    * [x] Tried the other applicable steps from the Troubleshooting Guide
* [x] Completed the **Problem Description**, **Steps to Reproduce** and **Version** sections below


## Problem Description

When the cursor is below the last item of a file in the Editor, the `Go to cursor` button in the outline explorer toolbar does nothing

### What steps reproduce the problem?

1.  Click in the last item of a file
2.  Click on the `Go to cursor position` in the outline explorer toolbar

![last_item_oe](https://user-images.githubusercontent.com/10170372/44481479-e1578980-a613-11e8-935f-1ef209973427.gif)

### What is the expected output? What do you see instead?

The last item of the outline explorer should be selected.

## 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: Spyder 4.0.0.dev0 
* Python version: Python 3.6.5 64bits
* Qt version: Qt 5.9.3
* PyQt version: PyQt5 5.9.2 
* Operating System name/version: Windows  10

### Dependencies
<!--- Please go to the menu entry Help > Dependencies,
press the Copy to clipboard button and paste below --->

```
pyflakes >=0.6.0  :  1.6.0 (OK)
pycodestyle >=2.3 :  2.3.1 (OK)
pygments >=2.0    :  2.2.0 (OK)
sphinx >=0.6.6    :  1.7.1 (OK)
rope >=0.9.4      :  0.10.7 (OK)
jedi >=0.11.0     :  0.12.1 (OK)
nbconvert >=4.0   :  5.3.1 (OK)
pandas >=0.13.1   :  0.22.0 (OK)
numpy >=1.7       :  1.13.0 (OK)
sympy >=0.7.3     :  1.1.1 (OK)
cython >=0.21     :  0.27.3 (OK)
qtconsole >=4.2.0 :  4.4.0.dev (OK)
IPython >=4.0     :  6.2.1 (OK)
matplotlib >=2.0.0:  2.2.0 (OK)
pylint >=0.25     :  1.8.3 (OK)
```



Discussion:
I'm in the process of writing a PR to fix this.

Resolving patch:
diff --git a/spyder/plugins/outlineexplorer/widgets.py b/spyder/plugins/outlineexplorer/widgets.py
--- a/spyder/plugins/outlineexplorer/widgets.py
+++ b/spyder/plugins/outlineexplorer/widgets.py
@@ -125,6 +125,7 @@ def setup(self):
         self.setToolTip(0, _("Cell starts at line %s") % str(self.line))
 
 def get_item_children(item):
+    """Return a sorted list of all the children items of 'item'."""
     children = [item.child(index) for index in range(item.childCount())]
     for child in children[:]:
         others = get_item_children(child)
@@ -132,12 +133,19 @@ def get_item_children(item):
             children += others
     return sorted(children, key=lambda child: child.line)
 
+
 def item_at_line(root_item, line):
+    """
+    Find and return the item of the outline explorer under which is located
+    the specified 'line' of the editor.
+    """
     previous_item = root_item
     for item in get_item_children(root_item):
         if item.line > line:
             return previous_item
         previous_item = item
+    else:
+        return item
 
 
 def remove_from_tree_cache(tree_cache, line=None, item=None):


Test patch:
diff --git a/spyder/plugins/outlineexplorer/tests/test_widgets.py b/spyder/plugins/outlineexplorer/tests/test_widgets.py
--- a/spyder/plugins/outlineexplorer/tests/test_widgets.py
+++ b/spyder/plugins/outlineexplorer/tests/test_widgets.py
@@ -191,6 +191,8 @@ def test_go_to_cursor_position(outlineexplorer_bot):
     """
     Test that clicking on the 'Go to cursor position' button located in the
     toolbar of the outline explorer is working as expected.
+
+    Regression test for issue #7729.
     """
     outlineexplorer, qtbot = outlineexplorer_bot(TEXT, 'test.py')
 
@@ -201,9 +203,32 @@ def test_go_to_cursor_position(outlineexplorer_bot):
 
     # Click on the 'Go to cursor position' button of the outline explorer's
     # toolbar :
+    assert outlineexplorer.treewidget.currentItem() is None
+    qtbot.mouseClick(outlineexplorer.fromcursor_btn, Qt.LeftButton)
+    assert outlineexplorer.treewidget.currentItem().text(0) == 'method1'
+
+
+def test_go_to_last_item(outlineexplorer_bot):
+    """
+    Test that clicking on the 'Go to cursor position' button located in the
+    toolbar of the outline explorer is working as expected when the cursor
+    is located in the editor under the last item of the outline tree widget.
+
+    Regression test for issue #7744.
+    """
+    outlineexplorer, qtbot = outlineexplorer_bot(TEXT, 'test.py')
+
+    # Move the mouse cursor in the editor to the last line :
+    editor = outlineexplorer.treewidget.current_editor
+    line_count = editor._editor.document().blockCount() - 1
+    editor._editor.go_to_line(line_count)
+    assert editor._editor.get_text_line(line_count) == "            pass"
+
+    # Click on the 'Go to cursor position' button of the outline explorer's
+    # toolbar :
+    assert outlineexplorer.treewidget.currentItem() is None
     qtbot.mouseClick(outlineexplorer.fromcursor_btn, Qt.LeftButton)
-    current_item = outlineexplorer.treewidget.currentItem()
-    assert current_item.text(0) == 'method1'
+    assert outlineexplorer.treewidget.currentItem().text(0) == 'method2'
 
 
 def test_code_cell_grouping(outlineexplorer_bot):