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

feat: updating demo #34

Merged
merged 28 commits into from
Jul 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
4d3c61f
wip: working on app
tlambert03 Jul 10, 2022
b2825c8
wip
tlambert03 Jul 10, 2022
e15b3bf
feat: just add all the stuff
tlambert03 Jul 11, 2022
debd13f
chore: Merge branch 'main' into demo2
tlambert03 Jul 11, 2022
b922feb
chore: Merge branch 'main' into demo2
tlambert03 Jul 11, 2022
ee3a3ba
chore: Merge branch 'main' into demo2
tlambert03 Jul 11, 2022
3ab22a2
style: [pre-commit.ci] auto fixes [...]
pre-commit-ci[bot] Jul 11, 2022
eada6bd
feat: cache qactions [wip]
tlambert03 Jul 11, 2022
3fc5f8e
test: fix test
tlambert03 Jul 11, 2022
ecdee8b
feat: add findAction and test
tlambert03 Jul 11, 2022
8f3f45d
fix: fix for pyqt
tlambert03 Jul 11, 2022
c969673
chore: Merge branch 'cache-actions' into demo2
tlambert03 Jul 11, 2022
56a7a07
chore: merge
tlambert03 Jul 11, 2022
f9f7eb6
chore: Merge branch 'main' into demo2
tlambert03 Jul 11, 2022
3ad1810
fix: add close method
tlambert03 Jul 11, 2022
1492e99
docs: demo closer
tlambert03 Jul 11, 2022
f817f33
chore: formatting
tlambert03 Jul 11, 2022
0038f6b
fix: working context
tlambert03 Jul 11, 2022
5e41441
style: [pre-commit.ci] auto fixes [...]
pre-commit-ci[bot] Jul 11, 2022
53ab0fb
test: move demo, add test
tlambert03 Jul 12, 2022
9bd0425
fix: lint
tlambert03 Jul 12, 2022
a2a974f
fix: fix fonticon
tlambert03 Jul 13, 2022
0368004
build: fix manifest
tlambert03 Jul 13, 2022
a426fa0
test: fix qapp creation
tlambert03 Jul 13, 2022
4549d65
test: move test
tlambert03 Jul 13, 2022
052016f
test: add fixture to test qapp
tlambert03 Jul 13, 2022
5fd6a62
test: ignore deprecation
tlambert03 Jul 13, 2022
dbce193
test: fix ignore
tlambert03 Jul 13, 2022
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
255 changes: 255 additions & 0 deletions demo/model_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
from typing import List

from fonticon_fa6 import FA6S
from qtpy.QtCore import QFile, QFileInfo, QSaveFile, Qt, QTextStream
from qtpy.QtWidgets import QApplication, QFileDialog, QMessageBox, QTextEdit

from app_model import Application, types
from app_model.backends.qt import QModelMainWindow
from app_model.expressions import create_context


class MainWindow(QModelMainWindow):
def __init__(self, app: Application):
super().__init__(app)

self._cur_file: str = ""
self._text_edit = QTextEdit()
self._text_edit.copyAvailable.connect(self._update_context)

self.setCentralWidget(self._text_edit)
self.setModelMenuBar([MenuId.FILE, MenuId.EDIT, MenuId.HELP])
self.addModelToolBar(MenuId.FILE, exclude={CommandId.SAVE_AS, CommandId.EXIT})
self.addModelToolBar(MenuId.EDIT)
self.statusBar().showMessage("Ready")

self.set_current_file("")

self._ctx = create_context(self)
self._ctx.changed.connect(self._on_context_changed)
self._ctx["copyAvailable"] = False

def _update_context(self, available: bool):
self._ctx["copyAvailable"] = available

def _on_context_changed(self):
self.menuBar().update_from_context(self._ctx)

def set_current_file(self, fileName: str) -> None:
self._cur_file = fileName
self._text_edit.document().setModified(False)
self.setWindowModified(False)

if self._cur_file:
shown_name = QFileInfo(self._cur_file).fileName()
else:
shown_name = "untitled.txt"

self.setWindowTitle(f"{shown_name}[*] - Application")

def save(self):
return self.save_file(self._cur_file) if self._cur_file else self.save_as()

def save_as(self):
fileName, filtr = QFileDialog.getSaveFileName(self)
if fileName:
return self.save_file(fileName)

return False

def save_file(self, fileName):
error = None
QApplication.setOverrideCursor(Qt.WaitCursor)
file = QSaveFile(fileName)
if file.open(QFile.OpenModeFlag.WriteOnly | QFile.OpenModeFlag.Text):
outf = QTextStream(file)
outf << self._text_edit.toPlainText()
if not file.commit():
reason = file.errorString()
error = f"Cannot write file {fileName}:\n{reason}."
else:
reason = file.errorString()
error = f"Cannot open file {fileName}:\n{reason}."
QApplication.restoreOverrideCursor()

if error:
QMessageBox.warning(self, "Application", error)
return False

def maybe_save(self):
if self._text_edit.document().isModified():
ret = QMessageBox.warning(
self,
"Application",
"The document has been modified.\nDo you want to save " "your changes?",
QMessageBox.StandardButton.Save
| QMessageBox.StandardButton.Discard
| QMessageBox.StandardButton.Cancel,
)
if ret == QMessageBox.StandardButton.Save:
return self.save()
elif ret == QMessageBox.StandardButton.Cancel:
return False
return True

def new_file(self):
if self.maybe_save():
self._text_edit.clear()
self.set_current_file("")

def open_file(self):
if self.maybe_save():
fileName, _ = QFileDialog.getOpenFileName(self)
if fileName:
self.load_file(fileName)

def load_file(self, fileName):
file = QFile(fileName)
if not file.open(QFile.OpenModeFlag.ReadOnly | QFile.OpenModeFlag.Text):
reason = file.errorString()
QMessageBox.warning(
self, "Application", f"Cannot read file {fileName}:\n{reason}."
)
return

inf = QTextStream(file)
QApplication.setOverrideCursor(Qt.WaitCursor)
self._text_edit.setPlainText(inf.readAll())
QApplication.restoreOverrideCursor()

self.set_current_file(fileName)
self.statusBar().showMessage("File loaded", 2000)

def about(self):
QMessageBox.about(
self,
"About Application",
"The <b>Application</b> example demonstrates how to write "
"modern GUI applications using Qt, with a menu bar, "
"toolbars, and a status bar.",
)

def cut(self):
self._text_edit.cut()

def copy(self):
self._text_edit.copy()

def paste(self):
self._text_edit.paste()

def close(self):
super().close()


# Actions defined declaratively outside of QMainWindow class ...
# menus and toolbars will be made and added automatically


class MenuId:
FILE = "file"
EDIT = "edit"
HELP = "help"


class CommandId:
SAVE_AS = "save_file_as"
EXIT = "exit"


ACTIONS: List[types.Action] = [
types.Action(
id="new_file",
icon=FA6S.file_circle_plus,
title="New",
keybindings=[types.StandardKeyBinding.New],
status_tip="Create a new file",
menus=[{"id": MenuId.FILE, "group": "1_loadsave"}],
callback=MainWindow.new_file,
),
types.Action(
id="open_file",
icon=FA6S.folder_open,
title="Open...",
keybindings=[types.StandardKeyBinding.Open],
status_tip="Open an existing file",
menus=[{"id": MenuId.FILE, "group": "1_loadsave"}],
callback=MainWindow.open_file,
),
types.Action(
id="save_file",
icon=FA6S.floppy_disk,
title="Save",
keybindings=[types.StandardKeyBinding.Save],
status_tip="Save the document to disk",
menus=[{"id": MenuId.FILE, "group": "1_loadsave"}],
callback=MainWindow.save,
),
types.Action(
id=CommandId.SAVE_AS,
title="Save As...",
keybindings=[types.StandardKeyBinding.SaveAs],
status_tip="Save the document under a new name",
menus=[{"id": MenuId.FILE, "group": "1_loadsave"}],
callback=MainWindow.save_as,
),
types.Action(
id=CommandId.EXIT,
title="Exit",
keybindings=[types.StandardKeyBinding.Quit],
status_tip="Exit the application",
menus=[{"id": MenuId.FILE, "group": "3_launchexit"}],
callback=MainWindow.close,
),
types.Action(
id="cut",
icon=FA6S.scissors,
title="Cut",
keybindings=[types.StandardKeyBinding.Cut],
enablement="copyAvailable",
status_tip="Cut the current selection's contents to the clipboard",
menus=[{"id": MenuId.EDIT}],
callback=MainWindow.cut,
),
types.Action(
id="copy",
icon=FA6S.copy,
title="Copy",
keybindings=[types.StandardKeyBinding.Copy],
enablement="copyAvailable",
status_tip="Copy the current selection's contents to the clipboard",
menus=[{"id": MenuId.EDIT}],
callback=MainWindow.copy,
),
types.Action(
id="paste",
icon=FA6S.paste,
title="Paste",
keybindings=[types.StandardKeyBinding.Paste],
status_tip="Paste the clipboard's contents into the current selection",
menus=[{"id": MenuId.EDIT}],
callback=MainWindow.paste,
),
types.Action(
id="about",
title="About",
status_tip="Show the application's About box",
menus=[{"id": MenuId.HELP}],
callback=MainWindow.about,
),
]


# Main setup

if __name__ == "__main__":
app = Application(name="my_app")
for action in ACTIONS:
app.register_action(action)
qapp = QApplication.instance() or QApplication([])
qapp.setAttribute(Qt.ApplicationAttribute.AA_DontShowIconsInMenus)
main_win = MainWindow(app=app)

app.injection_store.register_provider(lambda: main_win, MainWindow)
main_win.show()
qapp.exec_()
File renamed without changes.
12 changes: 12 additions & 0 deletions demo/multi_file/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import pathlib
import sys

sys.path.append(str(pathlib.Path(__file__).parent.parent))

from multi_file.app import MyApp # noqa: E402
from qtpy.QtWidgets import QApplication # noqa: E402

qapp = QApplication.instance() or QApplication([])
app = MyApp()
app.show()
qapp.exec_()
16 changes: 8 additions & 8 deletions demo_app/actions.py → demo/multi_file/actions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import List

from fonticon_fa5 import FA5S
from fonticon_fa6 import FA6S

from app_model.types import Action, KeyBindingRule, KeyCode, KeyMod, MenuRule

Expand All @@ -11,31 +11,31 @@
Action(
id=CommandId.OPEN,
title="Open",
icon=FA5S.folder_open,
icon=FA6S.folder_open,
callback=functions.open_file,
menus=[MenuRule(id=MenuId.FILE)],
keybindings=[KeyBindingRule(primary=KeyMod.CtrlCmd | KeyCode.KeyO)],
),
Action(
id=CommandId.CLOSE,
title="Close",
icon=FA5S.window_close,
icon=FA6S.window_close,
callback=functions.close,
menus=[MenuRule(id=MenuId.FILE)],
keybindings=[KeyBindingRule(primary=KeyMod.CtrlCmd | KeyCode.KeyW)],
),
Action(
id=CommandId.UNDO,
title="Undo",
icon=FA5S.undo,
icon=FA6S.undo,
callback=functions.undo,
menus=[MenuRule(id=MenuId.EDIT, group="1_undo_redo")],
keybindings=[KeyBindingRule(primary=KeyMod.CtrlCmd | KeyCode.KeyZ)],
),
Action(
id=CommandId.REDO,
title="Redo",
icon=FA5S.redo,
icon=FA6S.rotate_right,
callback=functions.redo,
menus=[MenuRule(id=MenuId.EDIT, group="1_undo_redo")],
keybindings=[
Expand All @@ -45,23 +45,23 @@
Action(
id=CommandId.CUT,
title="Cut",
icon=FA5S.cut,
icon=FA6S.cut,
callback=functions.cut,
menus=[MenuRule(id=MenuId.EDIT, group="3_copypaste")],
keybindings=[KeyBindingRule(primary=KeyMod.CtrlCmd | KeyCode.KeyX)],
),
Action(
id=CommandId.COPY,
title="Copy",
icon=FA5S.copy,
icon=FA6S.copy,
callback=functions.copy,
menus=[MenuRule(id=MenuId.EDIT, group="3_copypaste")],
keybindings=[KeyBindingRule(primary=KeyMod.CtrlCmd | KeyCode.KeyC)],
),
Action(
id=CommandId.PASTE,
title="Paste",
icon=FA5S.paste,
icon=FA6S.paste,
callback=functions.paste,
menus=[MenuRule(id=MenuId.EDIT, group="3_copypaste")],
keybindings=[KeyBindingRule(primary=KeyMod.CtrlCmd | KeyCode.KeyV)],
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading