Skip to content

Commit cd4676c

Browse files
committed
New DataLabConnectionDialog widget
1 parent 6c79083 commit cd4676c

10 files changed

Lines changed: 251 additions & 85 deletions

File tree

.vscode/tasks.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@
200200
"clear": true
201201
},
202202
"dependsOrder": "sequence",
203+
"dependsOn": [
204+
"Clean Up"
205+
]
203206
},
204207
]
205208
}

CHANGELOG.md

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,23 @@
11
# DataLab Simple Client Releases #
22

3+
## Version 0.5.0 ##
4+
5+
💥 Changes:
6+
7+
* Remote API (`SimpleRemoteProxy`):
8+
* Added `is_connected` method
9+
10+
* New `widgets` module:
11+
* New `DataLabConnectionDialog` class:
12+
* Ready-to-use dialog box to connect to a DataLab server
13+
* `from cdlclient.widgets import DataLabConnectionDialog`
14+
* See example in `cdlclient/tests/connect_dialog.py`
15+
316
## Version 0.4.0 ##
417

5-
Changes:
18+
💥 Changes:
619

7-
* Remote API:
20+
* Remote API (`SimpleRemoteProxy`):
821
* Added dict-like interface (e.g. `proxy['obj123']`)
922
* Renamed `switch_to_panel` method to `set_current_panel` (compatibility with DataLab 0.9)
1023
* Added `get_current_panel` method
@@ -13,9 +26,9 @@ Changes:
1326

1427
## Version 0.3.0 ##
1528

16-
Changes:
29+
💥 Changes:
1730

18-
* Remote API:
31+
* Remote API (`SimpleRemoteProxy`):
1932
* `get_object` method now takes either object number, UUID or a title
2033
* `get_object_shapes` method now takes either object number, UUID or a title
2134
* Removed deprecated `get_object_from_uuid` and `get_object_from_title` methods
@@ -26,9 +39,9 @@ Changes:
2639

2740
## Version 0.2.0 ##
2841

29-
Changes:
42+
💥 Changes:
3043

31-
* Remote API:
44+
* Remote API (`SimpleRemoteProxy`):
3245
* New `raise_window` method
3346
* New `get_object_shapes` method
3447
* New `get_object` method

cdlclient/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@
1313
.. _DataLab: https://codra-ingenierie-informatique.github.io/DataLab/
1414
"""
1515

16+
# pylint: disable=unused-import
1617
from cdlclient.baseproxy import SimpleBaseProxy
1718
from cdlclient.remote import SimpleRemoteProxy
1819

19-
__version__ = "0.4.0"
20+
__version__ = "0.5.0"
2021
__docurl__ = "https://cdlclient.readthedocs.io/en/latest/"
2122
__homeurl__ = "https://github.com/Codra-Ingenierie-Informatique/DataLabSimpleClient/"
2223
__supporturl__ = "https://github.com/Codra-Ingenierie-Informatique/DataLabSimpleClient/issues/new/choose"

cdlclient/tests/connect_dialog.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# Licensed under the terms of the BSD 3-Clause
4+
# (see cdlclient/LICENSE for details)
5+
6+
"""
7+
DataLab Remote client connection dialog example
8+
"""
9+
10+
# guitest: show
11+
12+
from guidata.qthelpers import qt_app_context
13+
14+
from cdlclient import SimpleRemoteProxy
15+
from cdlclient.widgets import DataLabConnectionDialog
16+
17+
18+
def test_dialog():
19+
"""Test connection dialog"""
20+
proxy = SimpleRemoteProxy()
21+
with qt_app_context():
22+
dlg = DataLabConnectionDialog(proxy.connect)
23+
dlg.exec()
24+
25+
26+
if __name__ == "__main__":
27+
test_dialog()
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# -*- coding: utf-8 -*-
2+
"""Convert PNG image to Python code"""
3+
4+
# guitest: skip
5+
6+
import os
7+
import os.path as osp
8+
9+
from guidata.qthelpers import qt_app_context
10+
from qtpy import QtCore as QC
11+
from qtpy import QtGui as QG
12+
from qtpy import QtWidgets as QW
13+
14+
PKG_PATH = osp.join(osp.dirname(__file__), os.pardir, os.pardir)
15+
RES_PATH = osp.join(PKG_PATH, "resources")
16+
WIDGETS_PATH = osp.join(PKG_PATH, "cdlclient", "widgets")
17+
18+
19+
def convert_png_to_code(filename: str) -> bytes:
20+
"""Convert PNG image to Python code, so that it can be bundled with the
21+
application, without having to load the image from disk."""
22+
image = QG.QImage(filename)
23+
data = QC.QByteArray()
24+
buf = QC.QBuffer(data)
25+
image.save(buf, "PNG")
26+
return data.toBase64().data()
27+
28+
29+
def test_conv(filename: str, destmod: str) -> str:
30+
"""Test image to code conversion"""
31+
with qt_app_context(exec_loop=True):
32+
widget = QW.QWidget()
33+
vlayout = QW.QVBoxLayout()
34+
widget.setLayout(vlayout)
35+
label1 = QW.QLabel()
36+
label1.setPixmap(QG.QPixmap(filename))
37+
label2 = QW.QLabel()
38+
data = convert_png_to_code(filename)
39+
destmod_path = osp.join(WIDGETS_PATH, destmod + ".py")
40+
with open(destmod_path, "wb") as fn:
41+
fn.write("DATA = b'".encode("utf-8"))
42+
fn.write(data)
43+
fn.write("'".encode("utf-8"))
44+
mod = __import__("cdlclient.widgets." + destmod, fromlist=[destmod])
45+
pixmap = QG.QPixmap()
46+
pixmap.loadFromData(QC.QByteArray.fromBase64(mod.DATA))
47+
label2.setPixmap(pixmap)
48+
vlayout.addWidget(label1)
49+
vlayout.addWidget(label2)
50+
widget.show()
51+
52+
53+
if __name__ == "__main__":
54+
test_conv(osp.join(RES_PATH, "DataLab-Banner-200.png"), "datalab_banner")

cdlclient/tests/remoteclient_app.py

Lines changed: 2 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,17 @@
1515
from __future__ import annotations
1616

1717
import functools
18-
from collections.abc import Callable
1918
from contextlib import contextmanager
2019

2120
import numpy as np
2221
from guidata.env import execenv
23-
from guidata.qthelpers import qt_app_context, qt_wait, win32_fix_title_bar_background
24-
from qtpy import QtCore as QC
22+
from guidata.qthelpers import qt_app_context, qt_wait
2523
from qtpy import QtWidgets as QW
2624

2725
from cdlclient import SimpleRemoteProxy
2826
from cdlclient.tests.remoteclient_base import AbstractClientWindow
2927
from cdlclient.tests.remoteclient_unit import multiple_commands
28+
from cdlclient.widgets import DataLabConnectionDialog
3029

3130
APP_NAME = "Remote client test"
3231

@@ -56,80 +55,6 @@ def method_wrapper(*args, **kwargs):
5655
return try_send_command_decorator
5756

5857

59-
class DataLabConnectionThread(QC.QThread):
60-
"""DataLab Connection thread"""
61-
62-
SIG_CONNECTION_OK = QC.Signal()
63-
SIG_CONNECTION_KO = QC.Signal()
64-
65-
def __init__(self, connect_callback: Callable, parent: QC.QObject = None) -> None:
66-
super().__init__(parent)
67-
self.connect_callback = connect_callback
68-
69-
def run(self) -> None:
70-
"""Run thread"""
71-
try:
72-
self.connect_callback()
73-
self.SIG_CONNECTION_OK.emit()
74-
except ConnectionRefusedError:
75-
self.SIG_CONNECTION_KO.emit()
76-
77-
78-
class DataLabConnectionDialog(QW.QDialog):
79-
"""DataLab Connection dialog
80-
81-
Args:
82-
connect_callback: Callback function to connect to DataLab server
83-
parent: Parent widget. Defaults to None.
84-
"""
85-
86-
def __init__(self, connect_callback: Callable, parent: QW.QWidget = None) -> None:
87-
super().__init__(parent)
88-
win32_fix_title_bar_background(self)
89-
self.setWindowTitle("Connection to DataLab")
90-
self.setMinimumWidth(300)
91-
self.host_label = QW.QLabel("Host:")
92-
self.progress_bar = QW.QProgressBar()
93-
self.progress_bar.setRange(0, 0)
94-
self.status_label = QW.QLabel("Waiting for connection...")
95-
layout = QW.QVBoxLayout()
96-
layout.addWidget(self.host_label)
97-
layout.addWidget(self.progress_bar)
98-
layout.addWidget(self.status_label)
99-
self.setLayout(layout)
100-
self.thread = DataLabConnectionThread(connect_callback)
101-
self.thread.SIG_CONNECTION_OK.connect(self.on_connection_successful)
102-
self.thread.SIG_CONNECTION_KO.connect(self.on_connection_failed)
103-
button_box = QW.QDialogButtonBox(QW.QDialogButtonBox.Cancel)
104-
button_box.rejected.connect(self.reject)
105-
layout.addWidget(button_box)
106-
107-
def exec(self) -> int:
108-
"""Execute dialog"""
109-
self.connect_to_server()
110-
return super().exec()
111-
112-
def connect_to_server(self) -> None:
113-
"""Connect to server"""
114-
self.progress_bar.setRange(0, 0)
115-
self.status_label.setText("Connecting to server...")
116-
self.thread.start()
117-
118-
def on_connection_successful(self) -> None:
119-
"""Connection successful"""
120-
self.progress_bar.setRange(0, 1)
121-
self.progress_bar.setValue(1)
122-
self.status_label.setText("Connection successful!")
123-
self.accept()
124-
125-
def on_connection_failed(self) -> None:
126-
"""Connection failed"""
127-
self.progress_bar.setRange(0, 1)
128-
self.progress_bar.setValue(1)
129-
self.status_label.setText("Connection failed.")
130-
self.reject()
131-
132-
13358
class HostWindow(AbstractClientWindow):
13459
"""Test main view"""
13560

@@ -149,7 +74,6 @@ def init_cdl(self):
14974
if self.cdl is None:
15075
self.cdl: SimpleRemoteProxy = SimpleRemoteProxy()
15176
connect_dlg = DataLabConnectionDialog(self.cdl.connect, self)
152-
connect_dlg.host_label.setText("Host: DataLab server")
15377
ok = connect_dlg.exec()
15478
if ok:
15579
self.host.log("✨ Initialized DataLab connection ✨")

cdlclient/widgets/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
DataLab Simple Client Widgets
4+
-----------------------------
5+
6+
This module requires `guidata`_ and `qtpy`_ packages.
7+
8+
.. _guidata: https://pypi.org/project/guidata/
9+
.. _qtpy: https://pypi.org/project/QtPy/
10+
11+
"""
12+
13+
# pylint: disable=unused-import
14+
from cdlclient.widgets.connection import DataLabConnectionDialog

0 commit comments

Comments
 (0)