mirror of
https://gitlab.gnome.org/jwestman/blueprint-compiler.git
synced 2025-05-04 15:59:08 -04:00
fix: allow adding action widgets to GtkInfoBar
This commit is contained in:
parent
d9ef1d4df9
commit
4103ad3e71
9 changed files with 47 additions and 13 deletions
149
blueprintcompiler/language/response_id.py
Normal file
149
blueprintcompiler/language/response_id.py
Normal file
|
@ -0,0 +1,149 @@
|
|||
# response_id.py
|
||||
#
|
||||
# Copyright 2022 Gleb Smirnov <glebsmirnov0708@gmail.com>
|
||||
#
|
||||
# This file is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This file is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
|
||||
import typing as T
|
||||
|
||||
from .common import *
|
||||
|
||||
|
||||
class ResponseId(AstNode):
|
||||
"""Response ID of action widget."""
|
||||
|
||||
ALLOWED_PARENTS: T.List[T.Tuple[str, str]] = [
|
||||
("Gtk", "Dialog"),
|
||||
("Gtk", "InfoBar")
|
||||
]
|
||||
|
||||
grammar = [
|
||||
UseIdent("response"),
|
||||
"=",
|
||||
AnyOf(
|
||||
UseIdent("response_id"),
|
||||
UseNumber("response_id")
|
||||
),
|
||||
Optional([
|
||||
Keyword("default"), UseLiteral("is_default", True)
|
||||
])
|
||||
]
|
||||
|
||||
@validate()
|
||||
def child_type_is_action(self) -> None:
|
||||
"""Check that child type is "action"."""
|
||||
child_type = self.parent.tokens["child_type"]
|
||||
if child_type != "action":
|
||||
raise CompileError(f"Only action widget can have response ID")
|
||||
|
||||
@validate()
|
||||
def parent_has_action_widgets(self) -> None:
|
||||
"""Chech that parent widget has allowed type."""
|
||||
from .gobject_object import Object
|
||||
|
||||
container_type = self.parent_by_type(Object).gir_class
|
||||
gir = self.root.gir
|
||||
|
||||
for namespace, name in ResponseId.ALLOWED_PARENTS:
|
||||
parent_type = gir.get_type(name, namespace)
|
||||
if container_type.assignable_to(parent_type):
|
||||
break
|
||||
else:
|
||||
raise CompileError(
|
||||
f"{container_type.full_name} doesn't have action widgets"
|
||||
)
|
||||
|
||||
@validate()
|
||||
def widget_have_id(self) -> None:
|
||||
"""Check that action widget have ID."""
|
||||
from .gobject_object import Object
|
||||
|
||||
_object = self.parent.children[Object][0]
|
||||
if _object.tokens["id"] is None:
|
||||
raise CompileError(f"Action widget must have ID")
|
||||
|
||||
@validate("response_id")
|
||||
def correct_response_type(self) -> None:
|
||||
"""Validate response type.
|
||||
|
||||
Response type might be GtkResponseType member
|
||||
or positive number.
|
||||
"""
|
||||
gir = self.root.gir
|
||||
response = self.tokens["response_id"]
|
||||
|
||||
if isinstance(response, int):
|
||||
if response < 0:
|
||||
raise CompileError(
|
||||
"Numeric response type can't be negative")
|
||||
elif isinstance(response, float):
|
||||
raise CompileError(
|
||||
"Response type must be GtkResponseType member or integer,"
|
||||
" not float"
|
||||
)
|
||||
else:
|
||||
responses = gir.get_type("ResponseType", "Gtk").members.keys()
|
||||
if response not in responses:
|
||||
raise CompileError(
|
||||
f"Response type \"{response}\" doesn't exist")
|
||||
|
||||
@validate("default")
|
||||
def no_multiple_default(self) -> None:
|
||||
"""Only one action widget in dialog can be default."""
|
||||
from .gtkbuilder_child import Child
|
||||
from .gobject_object import Object
|
||||
|
||||
if not self.tokens["is_default"]:
|
||||
return
|
||||
|
||||
action_widgets = self.parent_by_type(Object).action_widgets
|
||||
for widget in action_widgets:
|
||||
if widget == self:
|
||||
break
|
||||
if widget.tokens["is_default"]:
|
||||
raise CompileError("Default response is already set")
|
||||
|
||||
@property
|
||||
def widget_id(self) -> str:
|
||||
"""Get action widget ID."""
|
||||
from .gobject_object import Object
|
||||
|
||||
_object: Object = self.parent.children[Object][0]
|
||||
return _object.tokens["id"]
|
||||
|
||||
def emit_xml(self, xml: XmlEmitter) -> None:
|
||||
"""Emit nothing.
|
||||
|
||||
Response ID don't have to emit any XML in place,
|
||||
but have to emit action-widget tag in separate
|
||||
place (see `ResponseId.emit_action_widget`)
|
||||
"""
|
||||
|
||||
def emit_action_widget(self, xml: XmlEmitter) -> None:
|
||||
"""Emit action-widget XML.
|
||||
|
||||
Must be called while <action-widgets> tag is open.
|
||||
|
||||
For more details see `GtkDialog` and `GtkInfoBar` docs.
|
||||
"""
|
||||
xml.start_tag(
|
||||
"action-widget",
|
||||
response=self.tokens["response_id"],
|
||||
default=self.tokens["is_default"]
|
||||
)
|
||||
xml.put_text(self.widget_id)
|
||||
xml.end_tag()
|
Loading…
Add table
Add a link
Reference in a new issue