Skip to content

Commit 28ca6bf

Browse files
authored
Merge pull request #117 from yjg30737/Dev
v0.5.5
2 parents 14274de + e7ea5eb commit 28ca6bf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1518
-1117
lines changed

pyqt_openai/aboutDialog.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def setUrl(self, url):
1818
self.__url = url
1919

2020
def mouseReleaseEvent(self, QMouseEvent):
21-
if QMouseEvent.button() == Qt.LeftButton:
21+
if QMouseEvent.button() == Qt.MouseButtons.LeftButton:
2222
QDesktopServices.openUrl(QUrl(self.__url))
2323

2424

@@ -29,7 +29,7 @@ def __init__(self):
2929

3030
def __initUi(self):
3131
self.setWindowTitle(LangClass.TRANSLATIONS['About'])
32-
self.setWindowFlags(Qt.Window | Qt.WindowCloseButtonHint)
32+
self.setWindowFlags(Qt.WindowType.Window | Qt.WindowType.WindowCloseButtonHint)
3333

3434
self.__okBtn = QPushButton(LangClass.TRANSLATIONS['OK'])
3535
self.__okBtn.clicked.connect(self.accept)
@@ -57,9 +57,9 @@ def __initUi(self):
5757
<p>{LangClass.TRANSLATIONS['Powered by qtpy']}</p>
5858
''')
5959

60-
descWidget1.setAlignment(Qt.AlignTop)
61-
descWidget2.setAlignment(Qt.AlignTop)
62-
descWidget3.setAlignment(Qt.AlignTop)
60+
descWidget1.setAlignment(Qt.AlignmentFlag.AlignTop)
61+
descWidget2.setAlignment(Qt.AlignmentFlag.AlignTop)
62+
descWidget3.setAlignment(Qt.AlignmentFlag.AlignTop)
6363

6464
self.__githubLbl = ClickableLabel()
6565
self.__githubLbl.setSvgFile('ico/github.svg')
@@ -73,7 +73,7 @@ def __initUi(self):
7373
lay = QHBoxLayout()
7474
lay.addWidget(self.__githubLbl)
7575
lay.addWidget(self.__discordLbl)
76-
lay.setAlignment(Qt.AlignLeft)
76+
lay.setAlignment(Qt.AlignmentFlag.AlignLeft)
7777
lay.setContentsMargins(0, 0, 0, 0)
7878

7979
linkWidget = QWidget()
@@ -84,7 +84,7 @@ def __initUi(self):
8484
lay.addWidget(descWidget2)
8585
lay.addWidget(descWidget3)
8686
lay.addWidget(linkWidget)
87-
lay.setAlignment(Qt.AlignTop)
87+
lay.setAlignment(Qt.AlignmentFlag.AlignTop)
8888
lay.setContentsMargins(0, 0, 0, 0)
8989

9090
rightWidget = QWidget()
@@ -103,7 +103,7 @@ def __initUi(self):
103103
lay = QHBoxLayout()
104104
lay.addWidget(self.__okBtn)
105105
lay.addWidget(cancelBtn)
106-
lay.setAlignment(Qt.AlignRight)
106+
lay.setAlignment(Qt.AlignmentFlag.AlignRight)
107107
lay.setContentsMargins(0, 0, 0, 0)
108108

109109
okCancelWidget = QWidget()

pyqt_openai/chatNavWidget.py

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
from qtpy.QtCore import Signal, QSortFilterProxyModel, Qt
2+
from qtpy.QtSql import QSqlTableModel, QSqlDatabase, QSqlQuery
3+
from qtpy.QtWidgets import QApplication, QWidget, QVBoxLayout, QMessageBox, QStyledItemDelegate, QTableView, QAbstractItemView, \
4+
QHBoxLayout, \
5+
QLabel, QSpacerItem, QSizePolicy, QFileDialog, QComboBox
6+
7+
# for search feature
8+
from pyqt_openai.pyqt_openai_data import DB
9+
from pyqt_openai.widgets.button import Button
10+
from pyqt_openai.widgets.searchBar import SearchBar
11+
12+
13+
class FilterProxyModel(QSortFilterProxyModel):
14+
def __init__(self):
15+
super().__init__()
16+
self.__searchedText = ''
17+
18+
@property
19+
def searchedText(self):
20+
return self.__searchedText
21+
22+
@searchedText.setter
23+
def searchedText(self, value):
24+
self.__searchedText = value
25+
self.invalidateFilter()
26+
27+
28+
# for align text in every cell to center
29+
class AlignDelegate(QStyledItemDelegate):
30+
def initStyleOption(self, option, index):
31+
super().initStyleOption(option, index)
32+
option.displayAlignment = Qt.AlignmentFlag.AlignCenter
33+
34+
35+
class SqlTableModel(QSqlTableModel):
36+
added = Signal(int, str)
37+
updated = Signal(int, str)
38+
deleted = Signal(list)
39+
addedCol = Signal()
40+
deletedCol = Signal()
41+
42+
def flags(self, index):
43+
if index.column() == self.column_index_by_name('name'):
44+
return Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEditable
45+
return Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable
46+
47+
def column_index_by_name(self, name):
48+
return self.fieldIndex(name)
49+
50+
51+
class ChatNavWidget(QWidget):
52+
added = Signal()
53+
clicked = Signal(int, str)
54+
cleared = Signal()
55+
onImport = Signal(str)
56+
onExport = Signal(list)
57+
58+
def __init__(self, columns, table_nm):
59+
super().__init__()
60+
self.__initVal(columns, table_nm)
61+
self.__initUi()
62+
63+
def __initVal(self, columns, table_nm):
64+
self.__columns = columns
65+
self.__table_nm = table_nm
66+
67+
def __initUi(self):
68+
# Set up the database and table model (you'll need to configure this part based on your database)
69+
self.__imageDb = QSqlDatabase.addDatabase('QSQLITE') # Replace with your database type
70+
self.__imageDb.setDatabaseName('conv.db') # Replace with your database name
71+
self.__imageDb.open()
72+
73+
imageGenerationHistoryLbl = QLabel()
74+
imageGenerationHistoryLbl.setText('History')
75+
76+
self.__addBtn = Button()
77+
self.__delBtn = Button()
78+
self.__importBtn = Button()
79+
self.__saveBtn = Button()
80+
self.__clearBtn = Button()
81+
82+
self.__addBtn.setStyleAndIcon('ico/add.svg')
83+
self.__delBtn.setStyleAndIcon('ico/delete.svg')
84+
self.__importBtn.setStyleAndIcon('ico/import.svg')
85+
self.__saveBtn.setStyleAndIcon('ico/save.svg')
86+
self.__clearBtn.setStyleAndIcon('ico/close.svg')
87+
88+
self.__addBtn.setToolTip('Add')
89+
self.__delBtn.setToolTip('Delete')
90+
self.__importBtn.setToolTip('SQLite DB Import (Working)')
91+
self.__saveBtn.setToolTip('Save')
92+
self.__delBtn.setToolTip('Remove All')
93+
94+
self.__addBtn.clicked.connect(self.add)
95+
self.__delBtn.clicked.connect(self.__delete)
96+
self.__importBtn.clicked.connect(self.__import)
97+
self.__saveBtn.clicked.connect(self.__export)
98+
self.__clearBtn.clicked.connect(self.__clear)
99+
100+
lay = QHBoxLayout()
101+
lay.addWidget(imageGenerationHistoryLbl)
102+
lay.addSpacerItem(QSpacerItem(10, 10, QSizePolicy.Policy.MinimumExpanding))
103+
lay.addWidget(self.__addBtn)
104+
lay.addWidget(self.__delBtn)
105+
lay.addWidget(self.__clearBtn)
106+
lay.addWidget(self.__importBtn)
107+
lay.addWidget(self.__saveBtn)
108+
lay.setContentsMargins(0, 0, 0, 0)
109+
110+
menuSubWidget1 = QWidget()
111+
menuSubWidget1.setLayout(lay)
112+
113+
self.__searchBar = SearchBar()
114+
self.__searchBar.setPlaceHolder('Search...')
115+
self.__searchBar.searched.connect(self.__search)
116+
117+
self.__searchOptionCmbBox = QComboBox()
118+
self.__searchOptionCmbBox.addItems(['Title', 'Content'])
119+
self.__searchOptionCmbBox.setMinimumHeight(self.__searchBar.sizeHint().height())
120+
self.__searchOptionCmbBox.currentIndexChanged.connect(
121+
lambda _: self.__search(self.__searchBar.getSearchBar().text()))
122+
123+
lay = QHBoxLayout()
124+
lay.addWidget(self.__searchBar)
125+
lay.addWidget(self.__searchOptionCmbBox)
126+
lay.setContentsMargins(0, 0, 0, 0)
127+
128+
menuSubWidget2 = QWidget()
129+
menuSubWidget2.setLayout(lay)
130+
131+
lay = QVBoxLayout()
132+
lay.addWidget(menuSubWidget1)
133+
lay.addWidget(menuSubWidget2)
134+
lay.setContentsMargins(0, 0, 0, 0)
135+
136+
menuWidget = QWidget()
137+
menuWidget.setLayout(lay)
138+
139+
self.__model = SqlTableModel(self)
140+
self.__model.setTable(self.__table_nm)
141+
self.__model.beforeUpdate.connect(self.__updated)
142+
143+
for i in range(len(self.__columns)):
144+
self.__model.setHeaderData(i, Qt.Orientation.Horizontal, self.__columns[i])
145+
self.__model.select()
146+
# descending order by insert date
147+
idx = self.__columns.index('insert_dt')
148+
self.__model.sort(idx, Qt.SortOrder.DescendingOrder)
149+
150+
# init the proxy model
151+
self.__proxyModel = FilterProxyModel()
152+
153+
# set the table model as source model to make it enable to feature sort and filter function
154+
self.__proxyModel.setSourceModel(self.__model)
155+
156+
# set up the view
157+
self.__tableView = QTableView()
158+
self.__tableView.setModel(self.__proxyModel)
159+
self.__tableView.setEditTriggers(QTableView.EditTrigger.DoubleClicked | QTableView.EditTrigger.SelectedClicked)
160+
self.__tableView.setSortingEnabled(True)
161+
162+
# align to center
163+
delegate = AlignDelegate()
164+
for i in range(self.__model.columnCount()):
165+
self.__tableView.setItemDelegateForColumn(i, delegate)
166+
167+
# set selection/resize policy
168+
self.__tableView.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
169+
self.__tableView.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
170+
171+
self.__tableView.clicked.connect(self.__clicked)
172+
self.__tableView.activated.connect(self.__clicked)
173+
174+
lay = QVBoxLayout()
175+
lay.addWidget(menuWidget)
176+
lay.addWidget(self.__tableView)
177+
self.setLayout(lay)
178+
179+
self.refreshData()
180+
181+
def add(self, called_from_parent=False):
182+
if called_from_parent:
183+
pass
184+
else:
185+
self.added.emit()
186+
self.__model.select()
187+
188+
def __import(self):
189+
filename = QFileDialog.getOpenFileName(self, 'Import', '', 'SQLite DB files (*.db)')
190+
if filename:
191+
filename = filename[0]
192+
self.onImport.emit(filename)
193+
194+
def __export(self):
195+
self.onExport.emit(self.__getSelectedIds())
196+
197+
def __updated(self, i, r):
198+
# send updated signal
199+
self.__model.updated.emit(r.value('id'), r.value('name'))
200+
201+
def refreshData(self, title=None):
202+
self.__model.select()
203+
# index -1 will be read from all columns
204+
# otherwise it will be read the current column number indicated by combobox
205+
self.__proxyModel.setFilterKeyColumn(-1)
206+
# regular expression can be used
207+
self.__proxyModel.setFilterRegularExpression(title)
208+
209+
def __clicked(self, idx):
210+
# get id of record
211+
id = self.__model.data(self.__proxyModel.mapToSource(idx.siblingAtColumn(0)), role=Qt.ItemDataRole.DisplayRole)
212+
title = self.__model.data(self.__proxyModel.mapToSource(idx.siblingAtColumn(1)), role=Qt.ItemDataRole.DisplayRole)
213+
214+
self.clicked.emit(id, title)
215+
216+
def __getSelectedIds(self):
217+
idx_s = [idx.siblingAtColumn(0) for idx in self.__tableView.selectedIndexes()]
218+
idx_s = list(set(idx_s))
219+
ids = [self.__model.data(idx, role=Qt.ItemDataRole.DisplayRole) for idx in idx_s]
220+
return ids
221+
222+
def __delete(self):
223+
ids = self.__getSelectedIds()
224+
for _id in ids:
225+
DB.deleteConv(_id)
226+
self.__model.select()
227+
self.cleared.emit()
228+
229+
def __clear(self):
230+
'''
231+
Clear all data in the table
232+
'''
233+
# Before clearing, confirm the action
234+
reply = QMessageBox.question(self, 'Confirm', 'Are you sure to clear all data?', QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
235+
if reply == QMessageBox.StandardButton.Yes:
236+
DB.deleteConv()
237+
self.__model.select()
238+
self.cleared.emit()
239+
240+
def __search(self, search_text):
241+
# title
242+
if self.__searchOptionCmbBox.currentText() == 'Title':
243+
self.refreshData(search_text)
244+
# content
245+
elif self.__searchOptionCmbBox.currentText() == 'Content':
246+
if search_text:
247+
convs = DB.selectAllContentOfConv(content_to_select=search_text)
248+
ids = [_[0] for _ in convs]
249+
self.__model.setQuery(QSqlQuery(f"SELECT {','.join(self.__columns)} FROM {self.__table_nm} "
250+
f"WHERE id IN ({','.join(map(str, ids))})"))
251+
else:
252+
self.refreshData()
253+
254+
def isCurrentConvExists(self):
255+
return self.__model.rowCount() > 0 and self.__tableView.currentIndex()
256+
257+
258+
if __name__ == "__main__":
259+
import sys
260+
261+
app = QApplication(sys.argv)
262+
w = ChatNavWidget(['id', 'name', 'update_dt', 'insert_dt'], 'conv_tb')
263+
w.show()
264+
sys.exit(app.exec())

0 commit comments

Comments
 (0)