Skip to content

Commit 8124626

Browse files
committed
[ui] StatusBar : Add message UI to keep list of messages
1 parent f2f30fc commit 8124626

File tree

4 files changed

+256
-8
lines changed

4 files changed

+256
-8
lines changed

meshroom/ui/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ def forceUIUpdate(self):
366366

367367
def showMessage(self, message, status=None, duration=5000):
368368
self._messageController.sendMessage(message, status, duration)
369-
369+
370370
def _retrieveThumbnailPath(self, filepath: str) -> str:
371371
"""
372372
Given the path of a project file, load this file and try to retrieve the path to its thumbnail, i.e. its
Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,20 @@
1-
from PySide6.QtCore import QObject, Signal
1+
import json
2+
from PySide6.QtCore import QObject
3+
from datetime import datetime
4+
from meshroom.common import Signal, Slot, Property
5+
6+
7+
class Message:
8+
def __init__(self, msg, status=None):
9+
self.msg = msg
10+
self.status = status or "info"
11+
self.date = datetime.now()
12+
13+
def dateStr(self, fullDate=False):
14+
dateFormat = "%H:%M:%S"
15+
if fullDate:
16+
dateFormat = "%Y-%m-%d %H:%M:%S.%f"
17+
return self.date.strftime(dateFormat)
218

319

420
class MessageController(QObject):
@@ -7,10 +23,46 @@ class MessageController(QObject):
723
"""
824

925
message = Signal(str, str, int)
26+
messagesChanged = Signal() # Signal to notify when messages list changes
1027

1128
def __init__(self, parent):
1229
super().__init__(parent)
30+
self._messages = []
1331

1432
def sendMessage(self, msg, status, duration):
1533
""" Sends a message that will be displayed on the status bar """
1634
self.message.emit(msg, status, duration)
35+
36+
@Slot(str, str)
37+
def storeMessage(self, msg, status):
38+
""" Adds a new message in the stack """
39+
self._messages.append(Message(msg, status or "info"))
40+
self.messagesChanged.emit() # Notify QML that messages have changed
41+
42+
def _getMessagesDict(self, fullDate=False):
43+
""" Get a dict with all stored messages """
44+
messages = []
45+
for msg in self._messages:
46+
messages.append({
47+
"status": msg.status,
48+
"date": msg.dateStr(fullDate),
49+
"text": msg.msg,
50+
})
51+
return messages
52+
53+
def getMessages(self):
54+
""" Get the messages with simple date infos """
55+
return self._getMessagesDict()
56+
57+
@Slot(result=str)
58+
def getMessagesAsString(self):
59+
return json.dumps(self._getMessagesDict(fullDate=True), indent=4)
60+
61+
@Slot()
62+
def clearMessages(self):
63+
""" Clear all stored messages """
64+
self._messages.clear()
65+
self.messagesChanged.emit()
66+
67+
# Property to expose messages to QML
68+
messages = Property("QVariantList", getMessages, notify=messagesChanged)

meshroom/ui/qml/Controls/StatusBar.qml

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,11 @@ RowLayout {
3434
font.pointSize: 8
3535
text: defaultIcon
3636
ToolTip.text: "Open Messages UI"
37-
// TODO : Open messages UI
38-
// onClicked: statusBar.showMessage("NotImplementedError : Cannot open interface", "error", 2000)
39-
enabled: false // TODO: to remove when implemented
40-
ToolTip.visible: false // TODO: to remove when implemented
37+
onClicked: {
38+
var component = Qt.createComponent("StatusMessages.qml")
39+
var window = component.createObject(root)
40+
window.show()
41+
}
4142
Component.onCompleted: {
4243
statusBarButton.contentItem.color = defaultColor
4344
}
@@ -97,14 +98,31 @@ RowLayout {
9798
}
9899
}
99100

100-
function showMessage(msg, status=undefined, duration=root.interval) {
101+
function _showMessage(msg, status=undefined, duration=root.interval) {
101102
statusBar.showMessage(msg, status, duration)
103+
// Add message to the message list
104+
_messageController.storeMessage(msg, status)
105+
}
106+
107+
function showMessage(msg, status=undefined, duration=root.interval) {
108+
// Info
109+
statusBar.showMessage("test info", "info", duration)
110+
_messageController.storeMessage("test info", "info")
111+
// Warning
112+
statusBar.showMessage("test warning", "warning", duration)
113+
_messageController.storeMessage("test warning", "warning")
114+
// Error
115+
statusBar.showMessage("test error", "error", duration)
116+
_messageController.storeMessage("test error", "error")
117+
// Ok
118+
statusBar.showMessage("test ok", "ok", duration)
119+
_messageController.storeMessage("test ok", "ok")
102120
}
103121

104122
Connections {
105123
target: _messageController
106124
function onMessage(message, color, duration) {
107-
showMessage(message, color, duration)
125+
root.showMessage(message, color, duration)
108126
}
109127
}
110128
}
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import QtQuick
2+
import QtQuick.Controls
3+
import QtQuick.Layouts
4+
5+
import MaterialIcons 2.2
6+
import Utils 1.0
7+
8+
ApplicationWindow {
9+
id: root
10+
title: "Messages"
11+
width: 500
12+
height: 400
13+
minimumWidth: 350
14+
minimumHeight: 250
15+
16+
SystemPalette { id: systemPalette }
17+
18+
function getColor(status, mode="unknown") {
19+
var color = systemPalette.text
20+
var alphaValue = 1.0
21+
switch (status) {
22+
case "ok": {
23+
color = Colors.green
24+
break
25+
}
26+
case "warning": {
27+
color = Colors.orange
28+
break
29+
}
30+
case "error": {
31+
color = Colors.red
32+
break
33+
}
34+
}
35+
switch (mode) {
36+
case "background": {
37+
if (status == "info") alphaValue = 0.05
38+
else alphaValue = 0.1
39+
break
40+
}
41+
case "border": {
42+
if (status == "info") alphaValue = 0.2
43+
else alphaValue = 0.3
44+
break
45+
}
46+
}
47+
return Qt.rgba(color.r, color.g, color.b, alphaValue)
48+
}
49+
50+
function getStatusIcon(status) {
51+
switch (status) {
52+
case "ok": return MaterialIcons.check_circle
53+
case "warning": return MaterialIcons.warning
54+
case "error": return MaterialIcons.error
55+
default: return MaterialIcons.info
56+
}
57+
}
58+
59+
header: ToolBar {
60+
61+
background: Rectangle {
62+
implicitWidth: root.width
63+
implicitHeight: 50
64+
color: Qt.darker(systemPalette.base, 1.1)
65+
}
66+
67+
RowLayout {
68+
anchors.fill: parent
69+
70+
Text {
71+
Layout.fillWidth: true
72+
text: "Messages (" + messageListView.count + ")"
73+
font.bold: true
74+
color: Qt.darker(systemPalette.text, 1.2)
75+
}
76+
77+
MaterialToolButton {
78+
ToolTip.text: "Clear the message list"
79+
text: MaterialIcons.clear_all
80+
font.pointSize: 16
81+
palette.base: systemPalette.base
82+
// Text color
83+
Component.onCompleted: {
84+
contentItem.color = Qt.darker(systemPalette.text, 1.2)
85+
}
86+
onClicked: _messageController.clearMessages()
87+
}
88+
89+
MaterialToolButton {
90+
ToolTip.text: "Copy the content as a dict"
91+
text: MaterialIcons.content_copy
92+
font.pointSize: 16
93+
palette.base: systemPalette.base
94+
// Text color
95+
Component.onCompleted: {
96+
contentItem.color = Qt.darker(systemPalette.text, 1.2)
97+
}
98+
onClicked: {
99+
var msgDict = _messageController.getMessagesAsString()
100+
if (msgDict !== '') {
101+
Clipboard.clear()
102+
Clipboard.setText(msgDict)
103+
}
104+
}
105+
}
106+
}
107+
}
108+
109+
Rectangle {
110+
anchors.fill: parent
111+
color: systemPalette.base
112+
113+
ScrollView {
114+
anchors.fill: parent
115+
anchors.margins: 10
116+
117+
ListView {
118+
id: messageListView
119+
model: _messageController.messages
120+
spacing: 5
121+
122+
delegate: Rectangle {
123+
width: messageListView.width
124+
height: messageLayout.implicitHeight + 16
125+
color: root.getColor(modelData.status, "background")
126+
border.color: root.getColor(modelData.status, "border")
127+
border.width: 1
128+
radius: 4
129+
130+
RowLayout {
131+
id: messageLayout
132+
anchors.fill: parent
133+
anchors.margins: 8
134+
spacing: 12
135+
136+
// Icon
137+
Text {
138+
text: root.getStatusIcon(modelData.status)
139+
font.pointSize: 14
140+
color: root.getColor(modelData.status)
141+
Layout.alignment: Qt.AlignVCenter
142+
}
143+
144+
// Text
145+
RowLayout {
146+
Layout.fillWidth: true
147+
spacing: 8
148+
149+
Text {
150+
text: modelData.date
151+
font.pointSize: 8
152+
color: Qt.darker(systemPalette.windowText, 1.5)
153+
Layout.alignment: Qt.AlignLeft
154+
}
155+
156+
Text {
157+
text: modelData.text
158+
wrapMode: Text.WordWrap
159+
Layout.fillWidth: true
160+
color: systemPalette.windowText
161+
font.pointSize: 10
162+
}
163+
}
164+
}
165+
}
166+
167+
// Empty state
168+
Text {
169+
anchors.centerIn: parent
170+
text: "No messages to display"
171+
color: Qt.darker(systemPalette.windowText, 1.5)
172+
font.pointSize: 12
173+
visible: messageListView.count === 0
174+
}
175+
}
176+
}
177+
}
178+
}

0 commit comments

Comments
 (0)