Repository: spyder-ide/spyder

Issue:
Autosave recovery dialog expands beyond screen instead of using scrollbars with too many items
If I have more autosave files than will fit on my monitor (I have a 1200p one and just had it happen), then the dialog just expands outside of the visible screen (making it impossible to interact with the rest) rather than limiting its size and adding a scroll bar to the file list. Therefore, we should limit the size of the dialog, or the number of list items shown on screen accordingly to comfortably fit on a 720p monitor (or the current size, if practicable) and add a scroll bar widget to show the rest if that is the case. @jitseniesen take note, thanks!


Discussion:
@juanis2112, please take a look at this one. You can use this info as a starting point:

https://stackoverflow.com/questions/6821990/qdialog-with-scrollarea-and-gridlayout

To generate this problem, first you need to go to

    Preferences > Editor > Advanced settings

and change `Autosave interval` to `5` seconds.

Then you need to open 10 or 20 already existing files, make a small change to them and kill Spyder forcefully. To do the last thing, you need to open a different console, run in there this command:

    ps aux | grep bootstrap.py

which should generate something like

    carlos   32398 10.5  1.6 2992380 277308 pts/2  Sl+  20:27   0:07 python bootstrap.py

select the first number from left to right and pass it to the next command

    kill -9 32398

After you do that and open Spyder again, you should see the autosave recovery dialog with all the files you modified and left unsaved.
By the way, the number `32398` above is called the `pid` of a process (I think it stands for `process id`).
And I forgot to tell you that the recovery dialog is placed here:

https://github.com/spyder-ide/spyder/blob/master/spyder/plugins/editor/widgets/recover.py
In fact, I already started working on this about a month ago, but I decided to fix some higher priority stuff first instead of finishing it. If you want, I can show you what I have. I am not sure I can finish it myself before beta3, I want to first fix the autosave bugs when opening  multiple Spyder instances.

On 10 Jun 2019, 19:41, at 19:41, Carlos Cordoba <notifications@github.com> wrote:
>@juanis2112, please take a look at this one. You can use this info as a
>starting point:
>
>https://stackoverflow.com/questions/6821990/qdialog-with-scrollarea-and-gridlayout
>
>To generate this problem, first you need to go to
>
>    Preferences > Editor > Advanced settings
>
>and change `Autosave interval` to `5` seconds.
>
>Then you need to open 10 or 20 already existing files, make a small
>change to them and kill Spyder forcefully. To do the last thing, you
>need to open a different console, run in there this command:
>
>    ps aux | grep bootstrap.py
>
>which should generate something like
>
>carlos   32398 10.5  1.6 2992380 277308 pts/2  Sl+  20:27   0:07 python
>bootstrap.py
>
>select the first number from left to right and pass it to the next
>command
>
>    kill -9 32398
>
>After you do that and open Spyder again, you should see the autosave
>recovery dialog with all the files you modified and left unsaved.
>
>-- 
>You are receiving this because you were mentioned.
>Reply to this email directly or view it on GitHub:
>https://github.com/spyder-ide/spyder/issues/9125#issuecomment-500541061


Sure, thanks @jitseniesen! Would you like to open a WIP PR that @juanis2112 could finish or just post here a patch of what you have?
@juanis2112 Here is a commit of what I have: 910ba168fe4. The idea is to check the size of the dialog window, and if it is too big, replace the table containing filenames with a scroll area which contains that table. I am not sure this is the right approach; it is not clear to me when Qt does the layout for the dialog window and thus when to check the size. I decided to check the size as late as possible (i.e., the first time the window is displayed). I included loads of print statements to find out what's happening; these need of course be removed eventually.

I seem to remember that it basically worked. One problem is that if there are too many files so that the window is too tall, then the current implementation shrinks the height, which leads to a vertical scrollbar being added next to the table. This scrollbar then means that the scroll area is slightly too narrow. Ideally, if the window is too tall, the height should be decreased but the width should be increased with the width of the scrollbar. However, this may not be worth the effort. Hopefully, the recovery dialog is rarely shown, so it seems less of a priority to fine tune its appearance.

I only tested it on Linux, so we should make sure it works on Windows and Mac as well. The easiest way to test is to run the file `recover.py`; this makes a temporary directory with autosave files and displays the recovery dialog window (you can easily adapt this to add more files so that the window expands beyond the screen). It would be good to add automatic tests, but that may be difficult. Maybe we should just add a test which displays the dialog with many files without any asserts - this would make sure that at least the code runs.

Do ask if anything is unclear.
@jitseniesen, what if we use a fixed size for the dialog and a scrollbar? I think that would be the simplest thing to achieve, no? 
Indeed, that's perfectly fine, and much easier.

Resolving patch:
diff --git a/spyder/plugins/editor/utils/autosave.py b/spyder/plugins/editor/utils/autosave.py
--- a/spyder/plugins/editor/utils/autosave.py
+++ b/spyder/plugins/editor/utils/autosave.py
@@ -18,7 +18,7 @@
 from qtpy.QtCore import QTimer
 
 # Local imports
-from spyder.config.base import _, get_conf_path
+from spyder.config.base import _, get_conf_path, running_under_pytest
 from spyder.plugins.editor.widgets.autosaveerror import AutosaveErrorDialog
 from spyder.plugins.editor.widgets.recover import RecoveryDialog
 from spyder.utils.programs import is_spyder_process
@@ -174,7 +174,8 @@ def try_recover_from_autosave(self):
         the pid files.
         """
         files_to_recover, pidfiles = self.get_files_to_recover()
-        dialog = RecoveryDialog(files_to_recover, parent=self.editor)
+        parent = self.editor if running_under_pytest() else self.editor.main
+        dialog = RecoveryDialog(files_to_recover, parent=parent)
         dialog.exec_if_nonempty()
         self.recover_files_to_open = dialog.files_to_open[:]
         for pidfile in pidfiles:
diff --git a/spyder/plugins/editor/widgets/recover.py b/spyder/plugins/editor/widgets/recover.py
--- a/spyder/plugins/editor/widgets/recover.py
+++ b/spyder/plugins/editor/widgets/recover.py
@@ -15,9 +15,9 @@
 # Third party imports
 from qtpy.compat import getsavefilename
 from qtpy.QtCore import Qt
-from qtpy.QtWidgets import (QDialog, QDialogButtonBox, QHBoxLayout, QLabel,
-                            QMessageBox, QPushButton, QTableWidget,
-                            QVBoxLayout, QWidget)
+from qtpy.QtWidgets import (QApplication, QDialog, QDialogButtonBox,
+                            QHBoxLayout, QLabel, QMessageBox, QPushButton,
+                            QTableWidget, QVBoxLayout, QWidget)
 # Local imports
 from spyder.config.base import _, running_under_pytest
 
@@ -99,6 +99,8 @@ def __init__(self, autosave_mapping, parent=None):
         self.add_table()
         self.add_cancel_button()
         self.setWindowTitle(_('Recover from autosave'))
+        self.setFixedSize(670, 400)
+        self.setWindowFlags(Qt.Dialog | Qt.MSWindowsFixedSizeDialogHint)
 
     def gather_data(self, autosave_mapping):
         """
@@ -147,8 +149,8 @@ def add_table(self):
         table.setHorizontalHeaderLabels(labels)
         table.verticalHeader().hide()
 
-        table.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
-        table.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
+        table.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
+        table.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
         table.setSelectionMode(QTableWidget.NoSelection)
 
         # Show horizontal grid lines
@@ -192,12 +194,6 @@ def add_table(self):
         table.resizeRowsToContents()
         table.resizeColumnsToContents()
 
-        # Need to add the "+ 2" because otherwise the table scrolls a tiny
-        # amount; no idea why
-        width = table.horizontalHeader().length() + 2
-        height = (table.verticalHeader().length()
-                  + table.horizontalHeader().height() + 2)
-        table.setFixedSize(width, height)
         self.layout.addWidget(table)
 
     def add_cancel_button(self):
@@ -206,6 +202,13 @@ def add_cancel_button(self):
         button_box.rejected.connect(self.reject)
         self.layout.addWidget(button_box)
 
+    def center(self):
+        """Center the dialog."""
+        screen = QApplication.desktop().screenGeometry(0)
+        x = screen.center().x() - self.width() / 2
+        y = screen.center().y() - self.height() / 2
+        self.move(x, y)
+
     def restore(self, idx):
         orig, autosave = self.data[idx]
         if orig:
@@ -265,6 +268,7 @@ def deactivate(self, idx):
     def exec_if_nonempty(self):
         """Execute dialog window if there is data to show."""
         if self.data:
+            self.center()
             return self.exec_()
         else:
             return QDialog.Accepted


Test patch: