diff options
author | Vivien Kraus <vivien@planete-kraus.eu> | 2021-10-06 18:06:12 +0200 |
---|---|---|
committer | Vivien Kraus <vivien@planete-kraus.eu> | 2021-10-12 22:27:38 +0200 |
commit | 3ba93ce1fccbc54d4695d55011ce856018c1b2cd (patch) | |
tree | b3668d95661643c55a2d6bf663ab58b5e3889a18 /src | |
parent | f53954f07104237497e9c121bffe0a3814116691 (diff) |
gui: add a primitive browser widget
Diffstat (limited to 'src')
-rw-r--r-- | src/scm/webid-oidc/client/application.scm | 313 | ||||
-rw-r--r-- | src/ui/Makefile.am | 8 | ||||
-rw-r--r-- | src/ui/error-page.glade | 108 | ||||
-rw-r--r-- | src/ui/link-widget.glade | 79 | ||||
-rw-r--r-- | src/ui/loaded-page.glade | 99 | ||||
-rw-r--r-- | src/ui/loading-page.glade | 34 | ||||
-rw-r--r-- | src/ui/new-page.glade | 37 | ||||
-rw-r--r-- | src/ui/updated-page.glade | 121 |
8 files changed, 746 insertions, 53 deletions
diff --git a/src/scm/webid-oidc/client/application.scm b/src/scm/webid-oidc/client/application.scm index 5185cfb..58d1dad 100644 --- a/src/scm/webid-oidc/client/application.scm +++ b/src/scm/webid-oidc/client/application.scm @@ -28,6 +28,7 @@ #:use-module (srfi srfi-9) #:use-module (srfi srfi-19) #:use-module (webid-oidc errors) + #:use-module (webid-oidc http-link) #:use-module ((webid-oidc parameters) #:prefix p:) #:use-module ((webid-oidc stubs) #:prefix stubs:) #:use-module ((webid-oidc oidc-id-token) #:prefix id:) @@ -52,7 +53,15 @@ authorization-uri reason continuation <application-state> - main-account other-accounts client error-messages authorization-prompts running-jobs pages + main-account other-accounts client error-messages authorization-prompts running-jobs page + + <page> + <new-page> + <page-with-uri> uri + <loading-page> + <error-page> code reason-phrase + <loaded-page> etag links content-type content + <updated-page> desired-links desired-content-type desired-content add-account choose-account @@ -60,9 +69,15 @@ set-accounts set-client fold-authorization-prompts - add-page set-page-uri - close-page + edit-page + remove-link + add-link + change-content-type + change-content + discard-updates + commit-updates + delete-page ) #:declarative? #t) @@ -120,10 +135,12 @@ #:init-keywords #:running-jobs #:getter running-jobs #:init-value '()) - (pages - #:init-keyword #:pages - #:getter pages - #:init-value '())) + (page + #:init-keyword #:page + #:getter page + #:init-thunk + (lambda () + (make <new-page>)))) (define-method (equal? (x <application-state>) (y <application-state>)) (and (equal? (main-account x) (main-account y)) @@ -132,7 +149,7 @@ (equal? (error-messages x) (error-messages y)) (equal? (authorization-prompts x) (authorization-prompts y)) (equal? (running-jobs x) (running-jobs y)) - (equal? (pages x) (pages y)))) + (equal? (page x) (page y)))) (define-method (display (state <application-state>) port) (format port "#<<application-state> main-account=~a other-accounts=~a client=~a error-messages=~a authorization-prompts=~a running-jobs=~a>" @@ -351,8 +368,7 @@ with-unresolved-prompt)))) (iter prompts seed state))))))) -(define-class <page> () - (identifier #:init-keyword #:identifier #:getter identifier)) +(define-class <page> ()) (define-method (equal? (x <page>) (y <page>)) (and (equal? (identifier x) (identifier y)))) @@ -372,64 +388,257 @@ (reason-phrase #:init-keyword #:reason-phrase #:getter reason-phrase)) (define-method (equal? (x <error-page>) (y <error-page>)) - (and (equal? (code x) (code y)) + (and (equal? (uri x) (uri y)) + (equal? (code x) (code y)) (equal? (reason-phrase x) (reason-phrase y)))) (define-class <loaded-page> (<page-with-uri>) (etag #:init-keyword #:etag #:getter etag) - (links #:init-keyword #:links #:getter links)) + (links #:init-keyword #:links #:getter links) + (content-type #:init-keyword #:content-type #:getter content-type) + (content #:init-keyword #:content #:getter content)) (define-method (equal? (x <loaded-page>) (y <loaded-page>)) - (and (equal? (etag x) (etag y)) - (equal? (links x) (links y)))) + (and (equal? (uri x) (uri y)) + (equal? (etag x) (etag y)) + (equal? (links x) (links y)) + (equal? (content-type x) (content-type y)) + (equal? (content x) (content y)))) -(define-class <rdf-page> (<loaded-page>) - (triples #:init-keyword #:triples #:getter triples)) +(define-class <updated-page> (<loaded-page>) + (desired-links #:init-keyword #:desired-links #:getter desired-links) + (desired-content-type #:init-keyword #:desired-content-type #:getter desired-content-type) + (desired-content #:init-keyword #:desired-content #:getter desired-content)) + +(define-method (equal? (x <updated-page>) (y <updated-page>)) + (and (equal? (uri x) (uri y)) + (equal? (etag x) (etag y)) + (equal? (links x) (links y)) + (equal? (content-type x) (content-type y)) + (equal? (content x) (content y)) + (equal? (desired-links x) (desired-links y)) + (equal? (desired-content-type x) (desired-content-type y)) + (equal? (desired-content x) (desired-content y)))) + +(define-method (edit-page (page <page>)) + page) + +(define-method (edit-page (page <loaded-page>)) + (make <updated-page> + #:uri (uri page) + #:etag (etag page) + #:links (links page) + #:content-type (content-type page) + #:content (content page) + #:desired-links (links page) + #:desired-content-type (content-type page) + #:desired-content (content page))) + +(define-method (edit-page (page <updated-page>)) + page) + +(define-method (edit-page (state <application-state>)) + (let ((ret (shallow-clone state))) + (slot-set! ret 'page (edit-page (page ret))) + ret)) -(define-method (equal? (x <rdf-page>) (y <rdf-page>)) - (and (equal? (triples x) (triples y)))) +(define-method (remove-link (page <page>) target key value) + (let ((ret (edit-page page))) + (when (is-a? ret <updated-page>) + (let ((filtered + (map (match-lambda + (((? (cute equal? <> target)) attributes ...) + `(,target + ,(filter + (match-lambda + ((the-key . the-value) + (and (equal? the-key key) + (equal? the-value value)))) + attributes))) + (other other)) + (links ret)))) + (slot-set! ret 'desired-links + (filter (match-lambda + (((? uri?) ()) + #f) + (else #t)) + filtered)))) + ret)) -(define-class <non-rdf-page> (<loaded-page>) - (content-type #:init-keyword #:content-type #:getter content-type) - (content #:init-keyword #:content #:getter content)) +(define-method (remove-link (state <application-state>) target key value) + (let ((ret (shallow-clone state))) + (slot-set! ret 'page (remove-link (page ret) target key value)) + ret)) -(define-method (equal? (x <non-rdf-page>) (y <non-rdf-page>)) - (and (equal? (content-type x) (content-type y)) - (equal? (content x) (content y)))) +(define-method (add-link (page <page>) target key value) + (let ((ret (edit-page page))) + (when (is-a? ret <updated-page>) + (slot-set! ret 'desired-links + `((,target (,key . ,value)) + ,@(desired-links page)))) + ret)) + +(define-method (add-link (state <application-state>) target key value) + (let ((ret (shallow-clone state))) + (slot-set! ret 'page (add-link (page ret) (string->uri target) key value)) + ret)) -(define-method (add-page (state <application-state>) (identifier <string>)) +(define-method (set-page-uri (state <application-state>) uri) + (let ((ret (shallow-clone state)) + (new-page (make <loading-page> + #:uri uri))) + (slot-set! ret 'page new-page) + (add-job + ret + (format #f (G_ "Loading ~a...") (uri->string uri)) + (lambda () + (declare-link-header!) + (let ((account (main-account state)) + (client (client state))) + (parameterize ((client:client client)) + (receive (updated-account response response-body) + (client:request account (uri new-page)) + (lambda (previous-state) + (let ((ret (shallow-clone previous-state))) + ;; If the main client hasn’t changed, update it + (when (equal? (main-account previous-state) account) + (slot-set! ret 'main-account updated-account)) + ;; If the page hasn’t changed, update it + (when (equal? (page previous-state) + new-page) + (slot-set! ret 'page + (if (eqv? (response-code response) 200) + (make <loaded-page> + #:uri uri + #:etag + (match (response-etag response) + ((value . #f) value) + (else #f)) + #:links + (response-links response) + #:content-type + (response-content-type response) + #:content + (or (false-if-exception (bytevector->string response-body)) + response-body)) + (make <error-page> + #:uri uri + #:code (response-code response) + #:reason-phrase (response-reason-phrase response))))) + ret))))))))) + +(define-method (change-content-type (state <application-state>) content-type) (let ((ret (shallow-clone state))) - (slot-set! ret 'pages - `(,(make <new-page> #:identifier identifier) - ,@(pages state))) + (slot-set! + ret 'page + (let ((p (edit-page (page ret)))) + (slot-set! p 'desired-content-type content-type) + p)) ret)) -(define-method (set-page-uri (state <application-state>) (id <string>) uri) +(define-method (change-content (state <application-state>) content) (let ((ret (shallow-clone state))) - (slot-set! ret 'pages - (let replace-page ((pages (pages state)) - (untouched-pages '())) - (match pages - (() - (reverse untouched-pages)) - ((hd tl ...) - (let ((replaced - (if (equal? (identifier hd) id) - (make <loading-page> - #:identifier id - #:uri uri) - hd))) - (replace-page - tl - `(,replaced - ,@(untouched-pages)))))))) - ;; TODO: add a job to load the page… + (slot-set! + ret 'page + (let ((p (edit-page (page ret)))) + (slot-set! p 'desired-content content) + p)) ret)) -(define-method (close-page (state <application-state>) (id <string>)) +(define-method (discard-updates (page <page>)) + page) + +(define-method (discard-updates (page <updated-page>)) + (make <loaded-page> + #:uri (uri page) + #:etag (etag page) + #:links (links page) + #:content-type (content-type page) + #:content (content page))) + +(define-method (discard-updates (state <application-state>)) (let ((ret (shallow-clone state))) - (slot-set! ret 'pages - (filter (lambda (page) - (not (equal? (identifier page) id))) - (pages state))) + (slot-set! ret 'page (discard-updates (page state))) ret)) + +(define-method (commit-updates (state <application-state>)) + (let ((loading (shallow-clone state))) + (slot-set! loading 'page + (make <loading-page> + #:uri (uri (page state)))) + (if (is-a? (page state) <updated-page>) + (add-job + loading + (format #f (G_ "Updating ~a (expected ETag ~a)") + (uri->string (uri (page state))) + (etag (page state))) + (lambda () + (let ((account (main-account state)) + (client (client state))) + (parameterize ((client:client client)) + (receive (updated-account response response-body) + (client:request account (uri (page state)) + #:method 'PUT + #:headers `(,@(let ((etag (etag (page state)))) + (if etag + `((if-match . ((,etag . #f)))) + '())) + ,@(map + (lambda (link) + `(link . ,link)) + (desired-links (page state))) + (content-type . (,(desired-content-type (page state))))) + #:body (desired-content (page state))) + (lambda (previous-state) + (let ((ret (shallow-clone previous-state))) + (when (equal? (main-account previous-state) account) + (slot-set! ret 'main-account updated-account)) + (when (equal? (page previous-state) + (page loading)) + (slot-set! ret 'page + (if (eqv? (response-code response) 200) + (make <loaded-page> + #:uri (uri (page state)) + #:etag (match (response-etag response) + ((etag . #f) etag) + (else #f)) + #:links (desired-links (page state)) + #:content-type (desired-content-type (page state)) + #:content (desired-content (page state))) + (make <error-page> + #:uri (uri (page state)) + #:code (response-code response) + #:reason-phrase (response-reason-phrase response))))) + ret))))))) + state))) + +(define-method (delete-page (state <application-state>)) + (if (is-a? (page state) <page-with-uri>) + (add-job + state + (format #f (G_ "Deleting ~a (expected ETag ~a)") + (uri (page state)) + (and (is-a? (page state) <loaded-page>) + (etag (page state)))) + (lambda () + (let ((account (main-account state)) + (client (client state))) + (parameterize ((client:client client)) + (receive (updated-account response response-body) + (client:request account (uri (page state)) + #:method 'DELETE + #:headers `(,@(let ((etag (and (is-a? (page state) <loaded-page>) + (etag (page state))))) + (if etag + `((if-match . (,(etag (page state)) . #f))) + '())))) + (lambda (previous-state) + (let ((ret (shallow-clone previous-state))) + (when (equal? (main-account previous-state) account) + (slot-set! ret 'main-account updated-account)) + (when (equal? (page previous-state) + (page state)) + (slot-set! ret 'page + (make <new-page>))) + ret))))))) + state)) diff --git a/src/ui/Makefile.am b/src/ui/Makefile.am index cbd7b0f..0d04326 100644 --- a/src/ui/Makefile.am +++ b/src/ui/Makefile.am @@ -20,4 +20,10 @@ dist_uipkgdata_DATA = \ %reldir%/account-widget.glade \ %reldir%/accounts-widget.glade \ %reldir%/authorization-prompt.glade \ - %reldir%/main-window.glade + %reldir%/main-window.glade \ + %reldir%/error-page.glade \ + %reldir%/link-widget.glade \ + %reldir%/loaded-page.glade \ + %reldir%/loading-page.glade \ + %reldir%/new-page.glade \ + %reldir%/updated-page.glade diff --git a/src/ui/error-page.glade b/src/ui/error-page.glade new file mode 100644 index 0000000..a3d7a98 --- /dev/null +++ b/src/ui/error-page.glade @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.36.0 --> +<interface> + <requires lib="gtk+" version="3.22"/> + <object class="GtkBox" id="error_page"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkEntry" id="uri_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="input_purpose">url</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">The request failed:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="code"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">404</property> + <attributes> + <attribute name="weight" value="bold"/> + <attribute name="size" value="32768"/> + </attributes> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="reason_phrase"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Not Found</property> + <attributes> + <attribute name="weight" value="bold"/> + <attribute name="size" value="16384"/> + </attributes> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + </object> +</interface> diff --git a/src/ui/link-widget.glade b/src/ui/link-widget.glade new file mode 100644 index 0000000..cce37c4 --- /dev/null +++ b/src/ui/link-widget.glade @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.36.0 --> +<interface> + <requires lib="gtk+" version="3.22"/> + <object class="GtkBox" id="link_widget"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkLinkButton" id="target_iri"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="relief">none</property> + <property name="uri">http://glade.gnome.org</property> + <child> + <object class="GtkLabel" id="target_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">https://example.com</property> + <property name="ellipsize">end</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">rel</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">=</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="relation_type"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">type</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> +</interface> diff --git a/src/ui/loaded-page.glade b/src/ui/loaded-page.glade new file mode 100644 index 0000000..9517d2f --- /dev/null +++ b/src/ui/loaded-page.glade @@ -0,0 +1,99 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.36.0 --> +<interface> + <requires lib="gtk+" version="3.22"/> + <object class="GtkBox" id="loaded_page"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkEntry" id="uri_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="input_purpose">url</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox" id="links_list"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="content_type"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">text/turtle</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="content"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">@prefix rdf: ...</property> + <property name="selectable">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkButton" id="button_delete"> + <property name="label" translatable="yes">Delete</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="button_update"> + <property name="label" translatable="yes">Update…</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">4</property> + </packing> + </child> + </object> +</interface> diff --git a/src/ui/loading-page.glade b/src/ui/loading-page.glade new file mode 100644 index 0000000..203084f --- /dev/null +++ b/src/ui/loading-page.glade @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.36.0 --> +<interface> + <requires lib="gtk+" version="3.22"/> + <object class="GtkBox" id="loading_page"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkEntry" id="uri_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="input_purpose">url</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkSpinner"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="active">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> +</interface> diff --git a/src/ui/new-page.glade b/src/ui/new-page.glade new file mode 100644 index 0000000..b9703ff --- /dev/null +++ b/src/ui/new-page.glade @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.36.0 --> +<interface> + <requires lib="gtk+" version="3.22"/> + <object class="GtkBox" id="new_page"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkEntry" id="uri_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="input_purpose">url</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_start">12</property> + <property name="margin_end">12</property> + <property name="label" translatable="yes">Enter an URI in the URI bar above to start your journey.</property> + <property name="wrap">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> +</interface> diff --git a/src/ui/updated-page.glade b/src/ui/updated-page.glade new file mode 100644 index 0000000..e174c55 --- /dev/null +++ b/src/ui/updated-page.glade @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.36.0 --> +<interface> + <requires lib="gtk+" version="3.22"/> + <object class="GtkTextBuffer" id="content_buffer"/> + <object class="GtkBox" id="updated_page"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Content type:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="content_type_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Content:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkTextView"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="buffer">content_buffer</property> + <property name="monospace">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkButton" id="discard_button"> + <property name="label" translatable="yes">Discard edits</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="update_button"> + <property name="label" translatable="yes">Update</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">4</property> + </packing> + </child> + </object> +</interface> |