mirror of
https://gitlab.gnome.org/jwestman/blueprint-compiler.git
synced 2025-05-04 15:59:08 -04:00
Add support for Adw.AlertDialog
This commit is contained in:
parent
6522421251
commit
ba8b492134
13 changed files with 136 additions and 40 deletions
4
NEWS.md
4
NEWS.md
|
@ -1,3 +1,7 @@
|
||||||
|
# v0.11.0
|
||||||
|
|
||||||
|
- Added support for [Adw.AlertDialog](https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.AlertDialog.html#adwalertdialog-as-gtkbuildable) custom syntax.
|
||||||
|
|
||||||
# v0.10.0
|
# v0.10.0
|
||||||
|
|
||||||
## Added
|
## Added
|
||||||
|
|
|
@ -79,7 +79,12 @@ def get_available_namespaces() -> T.List[T.Tuple[str, str]]:
|
||||||
]
|
]
|
||||||
|
|
||||||
for search_path in search_paths:
|
for search_path in search_paths:
|
||||||
for filename in os.listdir(search_path):
|
try:
|
||||||
|
filenames = os.listdir(search_path)
|
||||||
|
except FileNotFoundError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for filename in filenames:
|
||||||
if filename.endswith(".typelib"):
|
if filename.endswith(".typelib"):
|
||||||
namespace, version = filename.removesuffix(".typelib").rsplit("-", 1)
|
namespace, version = filename.removesuffix(".typelib").rsplit("-", 1)
|
||||||
_available_namespaces.append((namespace, version))
|
_available_namespaces.append((namespace, version))
|
||||||
|
|
|
@ -3,7 +3,7 @@ from .adw_breakpoint import (
|
||||||
AdwBreakpointSetter,
|
AdwBreakpointSetter,
|
||||||
AdwBreakpointSetters,
|
AdwBreakpointSetters,
|
||||||
)
|
)
|
||||||
from .adw_message_dialog import ExtAdwMessageDialog
|
from .adw_response_dialog import ExtAdwResponseDialog
|
||||||
from .attributes import BaseAttribute
|
from .attributes import BaseAttribute
|
||||||
from .binding import Binding
|
from .binding import Binding
|
||||||
from .common import *
|
from .common import *
|
||||||
|
@ -60,7 +60,7 @@ OBJECT_CONTENT_HOOKS.children = [
|
||||||
AdwBreakpointCondition,
|
AdwBreakpointCondition,
|
||||||
AdwBreakpointSetters,
|
AdwBreakpointSetters,
|
||||||
ExtAccessibility,
|
ExtAccessibility,
|
||||||
ExtAdwMessageDialog,
|
ExtAdwResponseDialog,
|
||||||
ExtComboBoxItems,
|
ExtComboBoxItems,
|
||||||
ext_file_filter_mime_types,
|
ext_file_filter_mime_types,
|
||||||
ext_file_filter_patterns,
|
ext_file_filter_patterns,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# adw_message_dialog.py
|
# adw_response_dialog.py
|
||||||
#
|
#
|
||||||
# Copyright 2023 James Westman <james@jwestman.net>
|
# Copyright 2023 James Westman <james@jwestman.net>
|
||||||
#
|
#
|
||||||
|
@ -25,7 +25,7 @@ from .gobject_object import ObjectContent, validate_parent_type
|
||||||
from .values import StringValue
|
from .values import StringValue
|
||||||
|
|
||||||
|
|
||||||
class ExtAdwMessageDialogFlag(AstNode):
|
class ExtAdwResponseDialogFlag(AstNode):
|
||||||
grammar = AnyOf(
|
grammar = AnyOf(
|
||||||
UseExact("flag", "destructive"),
|
UseExact("flag", "destructive"),
|
||||||
UseExact("flag", "suggested"),
|
UseExact("flag", "suggested"),
|
||||||
|
@ -51,12 +51,12 @@ class ExtAdwMessageDialogFlag(AstNode):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ExtAdwMessageDialogResponse(AstNode):
|
class ExtAdwResponseDialogResponse(AstNode):
|
||||||
grammar = [
|
grammar = [
|
||||||
UseIdent("id"),
|
UseIdent("id"),
|
||||||
Match(":").expected(),
|
Match(":").expected(),
|
||||||
to_parse_node(StringValue).expected("a string or translatable string"),
|
to_parse_node(StringValue).expected("a string or translatable string"),
|
||||||
ZeroOrMore(ExtAdwMessageDialogFlag),
|
ZeroOrMore(ExtAdwResponseDialogFlag),
|
||||||
]
|
]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -64,8 +64,8 @@ class ExtAdwMessageDialogResponse(AstNode):
|
||||||
return self.tokens["id"]
|
return self.tokens["id"]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def flags(self) -> T.List[ExtAdwMessageDialogFlag]:
|
def flags(self) -> T.List[ExtAdwResponseDialogFlag]:
|
||||||
return self.children[ExtAdwMessageDialogFlag]
|
return self.children[ExtAdwResponseDialogFlag]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def appearance(self) -> T.Optional[str]:
|
def appearance(self) -> T.Optional[str]:
|
||||||
|
@ -106,16 +106,16 @@ class ExtAdwMessageDialogResponse(AstNode):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ExtAdwMessageDialog(AstNode):
|
class ExtAdwResponseDialog(AstNode):
|
||||||
grammar = [
|
grammar = [
|
||||||
Keyword("responses"),
|
Keyword("responses"),
|
||||||
Match("[").expected(),
|
Match("[").expected(),
|
||||||
Delimited(ExtAdwMessageDialogResponse, ","),
|
Delimited(ExtAdwResponseDialogResponse, ","),
|
||||||
"]",
|
"]",
|
||||||
]
|
]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def responses(self) -> T.List[ExtAdwMessageDialogResponse]:
|
def responses(self) -> T.List[ExtAdwResponseDialogResponse]:
|
||||||
return self.children
|
return self.children
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -128,8 +128,11 @@ class ExtAdwMessageDialog(AstNode):
|
||||||
)
|
)
|
||||||
|
|
||||||
@validate("responses")
|
@validate("responses")
|
||||||
def container_is_message_dialog(self):
|
def container_is_message_dialog_or_alert_dialog(self):
|
||||||
validate_parent_type(self, "Adw", "MessageDialog", "responses")
|
try:
|
||||||
|
validate_parent_type(self, "Adw", "MessageDialog", "responses")
|
||||||
|
except:
|
||||||
|
validate_parent_type(self, "Adw", "AlertDialog", "responses")
|
||||||
|
|
||||||
@validate("responses")
|
@validate("responses")
|
||||||
def unique_in_parent(self):
|
def unique_in_parent(self):
|
||||||
|
@ -141,7 +144,18 @@ class ExtAdwMessageDialog(AstNode):
|
||||||
applies_in_subclass=("Adw", "MessageDialog"),
|
applies_in_subclass=("Adw", "MessageDialog"),
|
||||||
matches=new_statement_patterns,
|
matches=new_statement_patterns,
|
||||||
)
|
)
|
||||||
def style_completer(lsp, ast_node, match_variables):
|
def complete_adw_message_dialog(lsp, ast_node, match_variables):
|
||||||
|
yield Completion(
|
||||||
|
"responses", CompletionItemKind.Keyword, snippet="responses [\n\t$0\n]"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@completer(
|
||||||
|
applies_in=[ObjectContent],
|
||||||
|
applies_in_subclass=("Adw", "AlertDialog"),
|
||||||
|
matches=new_statement_patterns,
|
||||||
|
)
|
||||||
|
def complete_adw_alert_dialog(lsp, ast_node, match_variables):
|
||||||
yield Completion(
|
yield Completion(
|
||||||
"responses", CompletionItemKind.Keyword, snippet="responses [\n\t$0\n]"
|
"responses", CompletionItemKind.Keyword, snippet="responses [\n\t$0\n]"
|
||||||
)
|
)
|
|
@ -337,7 +337,7 @@ class XmlOutput(OutputFormat):
|
||||||
self._emit_attribute("property", "name", prop.name, prop.value, xml)
|
self._emit_attribute("property", "name", prop.name, prop.value, xml)
|
||||||
xml.end_tag()
|
xml.end_tag()
|
||||||
|
|
||||||
elif isinstance(extension, ExtAdwMessageDialog):
|
elif isinstance(extension, ExtAdwResponseDialog):
|
||||||
xml.start_tag("responses")
|
xml.start_tag("responses")
|
||||||
for response in extension.responses:
|
for response in extension.responses:
|
||||||
xml.start_tag(
|
xml.start_tag(
|
||||||
|
|
|
@ -15,7 +15,7 @@ Properties are the main way to set values on objects, but they are limited by th
|
||||||
.. rst-class:: grammar-block
|
.. rst-class:: grammar-block
|
||||||
|
|
||||||
Extension = :ref:`ExtAccessibility<Syntax ExtAccessibility>`
|
Extension = :ref:`ExtAccessibility<Syntax ExtAccessibility>`
|
||||||
| :ref:`ExtAdwMessageDialog<Syntax ExtAdwMessageDialog>`
|
| :ref:`ExtAdwResponseDialog<Syntax ExtAdwResponseDialog>`
|
||||||
| :ref:`ExtAdwBreakpoint<Syntax ExtAdwBreakpoint>`
|
| :ref:`ExtAdwBreakpoint<Syntax ExtAdwBreakpoint>`
|
||||||
| :ref:`ExtComboBoxItems<Syntax ExtComboBoxItems>`
|
| :ref:`ExtComboBoxItems<Syntax ExtComboBoxItems>`
|
||||||
| :ref:`ExtFileFilterMimeTypes<Syntax ExtFileFilter>`
|
| :ref:`ExtFileFilterMimeTypes<Syntax ExtFileFilter>`
|
||||||
|
@ -63,16 +63,16 @@ Defines the condition for a breakpoint and the properties that will be set at th
|
||||||
The `Adw.Breakpoint:condition <https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/property.Breakpoint.condition.html>`_ property has type `Adw.BreakpointCondition <https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/struct.BreakpointCondition.html>`_, which GtkBuilder doesn't know how to parse from a string. Therefore, the ``condition`` syntax is used instead.
|
The `Adw.Breakpoint:condition <https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/property.Breakpoint.condition.html>`_ property has type `Adw.BreakpointCondition <https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/struct.BreakpointCondition.html>`_, which GtkBuilder doesn't know how to parse from a string. Therefore, the ``condition`` syntax is used instead.
|
||||||
|
|
||||||
|
|
||||||
.. _Syntax ExtAdwMessageDialog:
|
.. _Syntax ExtAdwResponseDialog:
|
||||||
|
|
||||||
Adw.MessageDialog Responses
|
Adw.MessageDialog Responses
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
.. rst-class:: grammar-block
|
.. rst-class:: grammar-block
|
||||||
|
|
||||||
ExtAdwMessageDialog = 'responses' '[' (ExtAdwMessageDialogResponse),* ']'
|
ExtAdwResponseDialog = 'responses' '[' (ExtAdwResponseDialogResponse),* ']'
|
||||||
ExtAdwMessageDialogResponse = <id::ref:`IDENT<Syntax IDENT>`> ':' :ref:`StringValue<Syntax StringValue>` ExtAdwMessageDialogFlag*
|
ExtAdwResponseDialogResponse = <id::ref:`IDENT<Syntax IDENT>`> ':' :ref:`StringValue<Syntax StringValue>` ExtAdwResponseDialogFlag*
|
||||||
ExtAdwMessageDialogFlag = 'destructive' | 'suggested' | 'disabled'
|
ExtAdwResponseDialogFlag = 'destructive' | 'suggested' | 'disabled'
|
||||||
|
|
||||||
Valid in `Adw.MessageDialog <https://gnome.pages.gitlab.gnome.org/libadwaita/doc/1-latest/class.MessageDialog.html>`_.
|
Valid in `Adw.MessageDialog <https://gnome.pages.gitlab.gnome.org/libadwaita/doc/1-latest/class.MessageDialog.html>`_.
|
||||||
|
|
||||||
|
@ -92,6 +92,33 @@ The ``responses`` block defines the buttons that will be added to the dialog. Th
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Adw.AlertDialog Responses
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
.. rst-class:: grammar-block
|
||||||
|
|
||||||
|
ExtAdwAlertDialog = 'responses' '[' (ExtAdwAlertDialogResponse),* ']'
|
||||||
|
ExtAdwAlertDialogResponse = <id::ref:`IDENT<Syntax IDENT>`> ':' :ref:`StringValue<Syntax StringValue>` ExtAdwAlertDialogFlag*
|
||||||
|
ExtAdwAlertDialogFlag = 'destructive' | 'suggested' | 'disabled'
|
||||||
|
|
||||||
|
Valid in `Adw.AlertDialog <https://gnome.pages.gitlab.gnome.org/libadwaita/doc/1-latest/class.AlertDialog.html>`_.
|
||||||
|
|
||||||
|
The ``responses`` block defines the buttons that will be added to the dialog. The ``destructive`` or ``suggested`` flag sets the appearance of the button, and the ``disabled`` flag can be used to disable the button.
|
||||||
|
|
||||||
|
.. code-block:: blueprint
|
||||||
|
|
||||||
|
using Adw 1;
|
||||||
|
|
||||||
|
Adw.AlertDialog {
|
||||||
|
responses [
|
||||||
|
cancel: _("Cancel"),
|
||||||
|
delete: _("Delete") destructive,
|
||||||
|
save: "Save" suggested,
|
||||||
|
wipeHardDrive: "Wipe Hard Drive" destructive disabled,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.. _Syntax ExtComboBoxItems:
|
.. _Syntax ExtComboBoxItems:
|
||||||
|
|
||||||
Gtk.ComboBoxText Items
|
Gtk.ComboBoxText Items
|
||||||
|
|
9
tests/sample_errors/adw_alert_dialog_duplicate_flags.blp
Normal file
9
tests/sample_errors/adw_alert_dialog_duplicate_flags.blp
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
using Gtk 4.0;
|
||||||
|
using Adw 1;
|
||||||
|
|
||||||
|
Adw.AlertDialog {
|
||||||
|
responses [
|
||||||
|
cancel: _("Cancel") disabled disabled,
|
||||||
|
ok: _("Ok") destructive suggested,
|
||||||
|
]
|
||||||
|
}
|
2
tests/sample_errors/adw_alert_dialog_duplicate_flags.err
Normal file
2
tests/sample_errors/adw_alert_dialog_duplicate_flags.err
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
6,34,8,Duplicate 'disabled' flag
|
||||||
|
7,29,9,'suggested' and 'destructive' are exclusive
|
10
tests/samples/adw_alertdialog_responses.blp
Normal file
10
tests/samples/adw_alertdialog_responses.blp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using Gtk 4.0;
|
||||||
|
using Adw 1;
|
||||||
|
|
||||||
|
Adw.AlertDialog {
|
||||||
|
responses [
|
||||||
|
cancel: _('Cancel'),
|
||||||
|
discard: _('Discard') destructive,
|
||||||
|
save: 'Save' suggested disabled,
|
||||||
|
]
|
||||||
|
}
|
16
tests/samples/adw_alertdialog_responses.ui
Normal file
16
tests/samples/adw_alertdialog_responses.ui
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
DO NOT EDIT!
|
||||||
|
This file was @generated by blueprint-compiler. Instead, edit the
|
||||||
|
corresponding .blp file and regenerate this file with blueprint-compiler.
|
||||||
|
-->
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk" version="4.0"/>
|
||||||
|
<object class="AdwAlertDialog">
|
||||||
|
<responses>
|
||||||
|
<response id="cancel" translatable="true">Cancel</response>
|
||||||
|
<response id="discard" translatable="true" appearance="destructive">Discard</response>
|
||||||
|
<response id="save" enabled="false" appearance="suggested">Save</response>
|
||||||
|
</responses>
|
||||||
|
</object>
|
||||||
|
</interface>
|
|
@ -44,6 +44,23 @@ class TestSamples(unittest.TestCase):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.maxDiff = None
|
self.maxDiff = None
|
||||||
|
|
||||||
|
self.have_adw_1_4 = False
|
||||||
|
self.have_adw_1_5 = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
import gi
|
||||||
|
|
||||||
|
gi.require_version("Adw", "1")
|
||||||
|
from gi.repository import Adw
|
||||||
|
|
||||||
|
Adw.init()
|
||||||
|
if Adw.MINOR_VERSION >= 4:
|
||||||
|
self.have_adw_1_4 = True
|
||||||
|
if Adw.MINOR_VERSION >= 5:
|
||||||
|
self.have_adw_1_5 = True
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
def assert_ast_doesnt_crash(self, text, tokens, ast):
|
def assert_ast_doesnt_crash(self, text, tokens, ast):
|
||||||
for i in range(len(text)):
|
for i in range(len(text)):
|
||||||
ast.get_docs(i)
|
ast.get_docs(i)
|
||||||
|
@ -147,22 +164,6 @@ class TestSamples(unittest.TestCase):
|
||||||
raise AssertionError()
|
raise AssertionError()
|
||||||
|
|
||||||
def test_samples(self):
|
def test_samples(self):
|
||||||
have_adw = False
|
|
||||||
have_adw_1_4 = False
|
|
||||||
|
|
||||||
try:
|
|
||||||
import gi
|
|
||||||
|
|
||||||
gi.require_version("Adw", "1")
|
|
||||||
from gi.repository import Adw
|
|
||||||
|
|
||||||
have_adw = True
|
|
||||||
Adw.init()
|
|
||||||
if Adw.MINOR_VERSION >= 4:
|
|
||||||
have_adw_1_4 = True
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# list the samples directory
|
# list the samples directory
|
||||||
samples = [
|
samples = [
|
||||||
f.stem
|
f.stem
|
||||||
|
@ -172,6 +173,7 @@ class TestSamples(unittest.TestCase):
|
||||||
samples.sort()
|
samples.sort()
|
||||||
for sample in samples:
|
for sample in samples:
|
||||||
REQUIRE_ADW_1_4 = ["adw_breakpoint"]
|
REQUIRE_ADW_1_4 = ["adw_breakpoint"]
|
||||||
|
REQUIRE_ADW_1_5 = ["adw_alertdialog_responses"]
|
||||||
|
|
||||||
SKIP_RUN = [
|
SKIP_RUN = [
|
||||||
"expr_closure",
|
"expr_closure",
|
||||||
|
@ -189,7 +191,9 @@ class TestSamples(unittest.TestCase):
|
||||||
"unchecked_class",
|
"unchecked_class",
|
||||||
]
|
]
|
||||||
|
|
||||||
if sample in REQUIRE_ADW_1_4 and not have_adw_1_4:
|
if sample in REQUIRE_ADW_1_4 and not self.have_adw_1_4:
|
||||||
|
continue
|
||||||
|
if sample in REQUIRE_ADW_1_5 and not self.have_adw_1_5:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
with self.subTest(sample):
|
with self.subTest(sample):
|
||||||
|
@ -202,8 +206,11 @@ class TestSamples(unittest.TestCase):
|
||||||
sample_errors.sort()
|
sample_errors.sort()
|
||||||
for sample_error in sample_errors:
|
for sample_error in sample_errors:
|
||||||
REQUIRE_ADW_1_4 = ["adw_breakpoint"]
|
REQUIRE_ADW_1_4 = ["adw_breakpoint"]
|
||||||
|
REQUIRE_ADW_1_5 = ["adw_alert_dialog_duplicate_flags"]
|
||||||
|
|
||||||
if sample_error in REQUIRE_ADW_1_4 and not have_adw_1_4:
|
if sample_error in REQUIRE_ADW_1_4 and not self.have_adw_1_4:
|
||||||
|
continue
|
||||||
|
if sample_error in REQUIRE_ADW_1_5 and not self.have_adw_1_5:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
with self.subTest(sample_error):
|
with self.subTest(sample_error):
|
||||||
|
@ -211,6 +218,9 @@ class TestSamples(unittest.TestCase):
|
||||||
|
|
||||||
def test_decompiler(self):
|
def test_decompiler(self):
|
||||||
self.assert_decompile("accessibility_dec")
|
self.assert_decompile("accessibility_dec")
|
||||||
|
if self.have_adw_1_5:
|
||||||
|
self.assert_decompile("adw_alertdialog_responses")
|
||||||
|
self.assert_decompile("adw_messagedialog_responses")
|
||||||
self.assert_decompile("child_type")
|
self.assert_decompile("child_type")
|
||||||
self.assert_decompile("file_filter")
|
self.assert_decompile("file_filter")
|
||||||
self.assert_decompile("flags")
|
self.assert_decompile("flags")
|
||||||
|
@ -220,7 +230,6 @@ class TestSamples(unittest.TestCase):
|
||||||
self.assert_decompile("property")
|
self.assert_decompile("property")
|
||||||
self.assert_decompile("property_binding_dec")
|
self.assert_decompile("property_binding_dec")
|
||||||
self.assert_decompile("placeholder_dec")
|
self.assert_decompile("placeholder_dec")
|
||||||
self.assert_decompile("responses")
|
|
||||||
self.assert_decompile("scale_marks")
|
self.assert_decompile("scale_marks")
|
||||||
self.assert_decompile("signal")
|
self.assert_decompile("signal")
|
||||||
self.assert_decompile("strings_dec")
|
self.assert_decompile("strings_dec")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue