Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR: Add a file switcher instance #46

Merged
merged 9 commits into from
May 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from setuptools import find_packages, setup
from spyder_notebook import __version__

REQUIREMENTS = ['spyder>=3', 'notebook>=4.3']
REQUIREMENTS = ['spyder>=3.1.4', 'notebook>=4.3']

setup(
name='spyder-notebook',
Expand Down
52 changes: 40 additions & 12 deletions spyder_notebook/notebookplugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from spyder.utils.qthelpers import (create_action, create_toolbutton,
add_actions)
from spyder.widgets.tabs import Tabs
from spyder.widgets.fileswitcher import FileSwitcher
from spyder.plugins import SpyderPluginWidget

# Local imports
Expand All @@ -47,6 +48,7 @@ def __init__(self, parent):
"""Constructor."""
SpyderPluginWidget.__init__(self, parent)

self.fileswitcher_dlg = None
self.tabwidget = None
self.menu_actions = None

Expand All @@ -60,6 +62,11 @@ def __init__(self, parent):

layout = QVBoxLayout()

filelist_btn = create_toolbutton(self,
icon=ima.icon('filelist'),
tip=_("File list management"),
triggered=self.open_fileswitcher_dlg)

new_notebook_btn = create_toolbutton(self,
icon=ima.icon('project_expanded'),
tip=_('Open a new notebook'),
Expand All @@ -70,7 +77,8 @@ def __init__(self, parent):
menu_btn.setMenu(self.menu)
menu_btn.setPopupMode(menu_btn.InstantPopup)
add_actions(self.menu, self.menu_actions)
corner_widgets = {Qt.TopRightCorner: [new_notebook_btn, menu_btn]}
corner_widgets = {Qt.TopRightCorner: [filelist_btn,
new_notebook_btn, menu_btn]}
self.tabwidget = Tabs(self, menu=self.menu, actions=self.menu_actions,
corner_widgets=corner_widgets)

Expand Down Expand Up @@ -189,24 +197,24 @@ def get_current_client_name(self, short=False):
if short:
return client.get_short_name()
else:
return client.get_name()
return client.get_filename()

def create_new_client(self, name=None, give_focus=True):
def create_new_client(self, filename=None, give_focus=True):
"""Create a new notebook or load a pre-existing one."""
# Generate the notebook name (in case of a new one)
if not name:
if not filename:
nb_name = 'untitled' + str(self.untitled_num) + '.ipynb'
name = osp.join(NOTEBOOK_TMPDIR, nb_name)
filename = osp.join(NOTEBOOK_TMPDIR, nb_name)
nb_contents = nbformat.v4.new_notebook()
nbformat.write(nb_contents, name)
nbformat.write(nb_contents, filename)
self.untitled_num += 1

client = NotebookClient(self, name)
client = NotebookClient(self, filename)
self.add_tab(client)

# Open the notebook with nbopen and get the url we need to render
try:
server_info = nbopen(name)
server_info = nbopen(filename)
except (subprocess.CalledProcessError, NBServerError):
QMessageBox.critical(
self,
Expand Down Expand Up @@ -243,7 +251,7 @@ def save_as(self, name=None):
"""Save notebook as."""
current_client = self.get_current_client()
current_client.save()
original_path = current_client.get_name()
original_path = current_client.get_filename()
if not name:
original_name = osp.basename(original_path)
else:
Expand All @@ -254,7 +262,7 @@ def save_as(self, name=None):
nb_contents = nbformat.read(original_path, as_version=4)
nbformat.write(nb_contents, filename)
self.close_client()
self.create_new_client(name=filename)
self.create_new_client(filename=filename)

def open_notebook(self, filenames=None):
"""Open a notebook from file."""
Expand All @@ -264,15 +272,15 @@ def open_notebook(self, filenames=None):
print(filenames)
if filenames:
for filename in filenames:
self.create_new_client(name=filename)
self.create_new_client(filename=filename)

# ------ Public API (for tabs) --------------------------------------------
def add_tab(self, widget):
"""Add tab."""
self.clients.append(widget)
index = self.tabwidget.addTab(widget, widget.get_short_name())
self.tabwidget.setCurrentIndex(index)
self.tabwidget.setTabToolTip(index, widget.get_name())
self.tabwidget.setTabToolTip(index, widget.get_filename())
if self.dockwidget and not self.ismaximized:
self.dockwidget.setVisible(True)
self.dockwidget.raise_()
Expand All @@ -283,3 +291,23 @@ def move_tab(self, index_from, index_to):
"""Move tab."""
client = self.clients.pop(index_from)
self.clients.insert(index_to, client)

def set_stack_index(self, index):
"""Set the index of the current notebook."""
self.tabwidget.setCurrentIndex(index)

def open_fileswitcher_dlg(self):
"""Open notebook list management dialog box."""
if not self.tabwidget.count():
return
if self.fileswitcher_dlg is not None and \
self.fileswitcher_dlg.is_visible:
self.fileswitcher_dlg.hide()
self.fileswitcher_dlg.is_visible = False
return
self.fileswitcher_dlg = FileSwitcher(self, self.tabwidget,
self.clients)
self.fileswitcher_dlg.sig_goto_file.connect(self.set_stack_index)
self.fileswitcher_dlg.sig_close_file.connect(self.close_client)
self.fileswitcher_dlg.show()
self.fileswitcher_dlg.is_visible = True
39 changes: 39 additions & 0 deletions spyder_notebook/tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,5 +204,44 @@ def test_new_notebook(qtbot):
assert len(notebook.clients) == 1


def test_fileswitcher(qtbot):
"""Test the fileswithcher."""
# Create notebook
notebook = setup_notebook(qtbot)

# Create new notebook
notebook.create_new_client()

# Wait for prompt
nbwidget = notebook.get_current_nbwidget()
qtbot.waitUntil(lambda: prompt_present(nbwidget), timeout=NOTEBOOK_UP)

# Assert that we have two notebooks
assert len(notebook.clients) == 2

# Fileswitcher of the notebook
notebook.open_fileswitcher_dlg()
fileswitcher = notebook.fileswitcher_dlg

# Search for the first untitled0 notebook
fileswitcher.edit.setText("0")

# Assert that we are at the first notebook
assert notebook.tabwidget.currentIndex() == 0
assert notebook.get_current_client().get_short_name() == 'untitled0.ipynb'

# Search for the untitled1 notebook
fileswitcher.edit.setText("1")

# Assert that we are at the first notebook
assert notebook.tabwidget.currentIndex() == 1
assert notebook.get_current_client().get_short_name() == 'untitled1.ipynb'

# Assert that the fileswitcher dialog hides
qtbot.keyPress(fileswitcher.edit, Qt.Key_Enter)
qtbot.waitUntil(lambda: not fileswitcher.isVisible(), timeout=NOTEBOOK_UP)
assert not fileswitcher.isVisible()


if __name__ == "__main__":
pytest.main()
16 changes: 9 additions & 7 deletions spyder_notebook/widgets/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,13 @@ class NotebookClient(QWidget):
render notebooks.
"""

def __init__(self, plugin, name):
def __init__(self, plugin, filename):
"""Constructor."""
super(NotebookClient, self).__init__(plugin)

self.name = name
if os.name == 'nt':
filename = filename.replace('/', '\\')
self.filename = filename

self.file_url = None
self.server_url = None
Expand Down Expand Up @@ -145,7 +147,7 @@ def add_token(self, url):
def register(self, server_info):
"""Register attributes that can be computed with the server info."""
# Path relative to the server directory
self.path = os.path.relpath(self.name,
self.path = os.path.relpath(self.filename,
start=server_info['notebook_dir'])

# Replace backslashes on Windows
Expand Down Expand Up @@ -176,13 +178,13 @@ def load_notebook(self):
"""Load the associated notebook."""
self.go_to(self.file_url)

def get_name(self):
"""Get notebook's name."""
return self.name
def get_filename(self):
"""Get notebook's filename."""
return self.filename

def get_short_name(self):
"""Get a short name for the notebook."""
sname = osp.basename(self.name)
sname = osp.basename(self.filename)
if len(sname) > 15:
sname = sname[:15]
return sname
Expand Down