[gnome-calculator] GCi: new library for Controllers for Widgets using GCalc



commit 08f2c7c44a70572e46ba2827bcc65b1516cdb8db
Author: Daniel Espinosa <esodan gmail com>
Date:   Thu Oct 17 18:35:29 2019 -0500

    GCi: new library for Controllers for Widgets using GCalc
    
    Setups a new library GCi, it will provide
    a set of widgets using GCalc.
    
    Initial new Gci.EntryController, as a controller
    for Gtk.Entry widgets intenting to response
    when an user input a math expression text and
    it is substituded by its evaluation

 doc/meson.build                           |  27 +++++++
 gcalc/meson.build                         |   2 +-
 gci/gci-entry-controller.vala             |  84 ++++++++++++++++++++++
 gci/gci.deps.in                           |   2 +
 gci/gci.pc.in                             |  13 ++++
 gci/meson.build                           | 116 ++++++++++++++++++++++++++++++
 gci/namespace-info.vala.in                |  24 +++++++
 meson.build                               |   1 +
 tests/gci-test-entry-controller.ui        |  59 +++++++++++++++
 tests/meson.build                         |  23 ++++++
 tests/test-entry-controller.gresource.xml |   6 ++
 tests/test-gci-entry-controller.vala      |  74 +++++++++++++++++++
 12 files changed, 430 insertions(+), 1 deletion(-)
---
diff --git a/doc/meson.build b/doc/meson.build
index 8cfb4dae..d1f98d4b 100644
--- a/doc/meson.build
+++ b/doc/meson.build
@@ -28,4 +28,31 @@ if valadoc.found()
                        install_dir : docsdir,
                        depends: libgcalc
                        )
+       gtkdoc_outdir = GCI_CAMEL_CASE_NAME+'-'+GCI_API_VERSION
+       docsdir = join_paths (get_option ('datadir'), 'devhelp','books')
+
+       custom_target ('libgci_valadocs',
+                       input : gci_sources,
+                       output : GCI_CAMEL_CASE_NAME+'-'+GCI_API_VERSION,
+                       command : [valadoc,
+                               '--doclet=devhelp',
+                               '--force',
+                               '--fatal-warnings',
+                               '--package-name='+GCI_CAMEL_CASE_NAME+'-'+GCI_API_VERSION,
+                               '--package-version='+meson.project_version(),
+                               '--vapidir='+gcalc_build_dir,
+                               '--vapidir='+gci_build_dir,
+                               '--pkg=glib-2.0',
+                               '--pkg=gio-2.0',
+                               '--pkg=gee-0.8',
+                               '--vapidir='+vapis_dir,
+                               '--pkg=gcalc-'+API_VERSION,
+                               '--pkg=gtk+-3.0',
+                               '--directory=@OUTDIR@',
+                               '@INPUT@'
+                               ],
+                       install : true,
+                       install_dir : docsdir,
+                       depends: libgcalc
+                       )
 endif
diff --git a/gcalc/meson.build b/gcalc/meson.build
index e0694127..1bb573c9 100644
--- a/gcalc/meson.build
+++ b/gcalc/meson.build
@@ -178,7 +178,7 @@ libgcalc = library(VERSIONED_PROJECT_NAME,
 if not get_option('disable-introspection')
 g_ir_compiler = find_program('g-ir-compiler', required: false)
 if g_ir_compiler.found()
-custom_target('typelib',
+custom_target('gcalc-typelib',
        command: [
                g_ir_compiler,
                '--shared-library', 'lib'+PROJECT_NAME+'-@0@.so'.format (API_VERSION),
diff --git a/gci/gci-entry-controller.vala b/gci/gci-entry-controller.vala
new file mode 100644
index 00000000..3824def2
--- /dev/null
+++ b/gci/gci-entry-controller.vala
@@ -0,0 +1,84 @@
+/* gcalc-entry-controler.vala
+ *
+ * Copyright (C) 2019  Daniel Espinosa <esodan gmail com>
+ *
+ * This library 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 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *      Daniel Espinosa <esodan gmail com>
+ */
+/**
+ * A {@link Gtk.Entry} controler to provide calculator services
+ *
+ * Setup a {@link Gtk.Entry} to response when the user hits the
+ * enter key or click the secondary icon, to evaluate the math
+ * expression and substitude the result as the new content text
+ * of the {@link Gtk.Entry}.
+ *
+ * The math expression should start with the equal sign "=", in
+ * order to execute the math expression evaluation.
+ *
+ * If the expression is not a valid one, like using undefined
+ * variables, the new text is empty.
+ */
+public class GCi.EntryController : Object {
+  Gtk.Entry _entry;
+  public Gtk.Entry entry {
+    get {
+      return _entry;
+    }
+    set {
+      _entry = value;
+      setup ();
+    }
+  }
+  public EntryController.for_entry (Gtk.Entry entry) {
+      this.entry = entry;
+      setup ();
+  }
+  internal void setup () {
+    if (entry == null) {
+      warning (_("No entry was set"));
+    }
+    entry.secondary_icon_name = "accessories-calculator";
+    entry.secondary_icon_activatable = true;
+    entry.secondary_icon_sensitive = true;
+    entry.activate.connect (()=>{
+      if (!entry.text.has_prefix ("=")) {
+        return;
+      }
+      calculate ();
+    });
+    entry.icon_press.connect ((pos, ev)=>{
+      if (!entry.text.has_prefix ("=")) {
+        return;
+      }
+      calculate ();
+    });
+  }
+
+  internal void calculate () {
+    var s = new GCalc.Solver ();
+    string str = entry.text.replace ("=", "");
+    try {
+      var r = s.solve (str);
+      if (r is GCalc.MathResult) {
+        entry.text = r.expression.to_string ();
+      }
+    } catch (GLib.Error e) {
+      warning (_("Math Expression evaluation error: %s"), e.message);
+    }
+  }
+}
+
diff --git a/gci/gci.deps.in b/gci/gci.deps.in
new file mode 100644
index 00000000..5adb695e
--- /dev/null
+++ b/gci/gci.deps.in
@@ -0,0 +1,2 @@
+gcalc-2
+gtk+-3.0
diff --git a/gci/gci.pc.in b/gci/gci.pc.in
new file mode 100644
index 00000000..15e94644
--- /dev/null
+++ b/gci/gci.pc.in
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=@libdir@
+datadir=@prefix@/share
+includedir=@prefix@/include
+
+Name: libgcalc
+Description: GNOME Calculator Libray GTK Interface
+URL: http://live.gnome.org/
+Version: @PROJECT_VERSION@
+Requires: gcalc-2 >= 3.34 gtk+-3.0 > 3.19.3
+Libs: -L${libdir} -lgci-@API_VERSION@
+Cflags: -I${includedir}/gci-@API_VERSION@
diff --git a/gci/meson.build b/gci/meson.build
new file mode 100644
index 00000000..f20b431e
--- /dev/null
+++ b/gci/meson.build
@@ -0,0 +1,116 @@
+GCI_PROJECT_NAME='gci'
+GCI_API_VERSION='1'
+GCI_VERSIONED_PROJECT_NAME=GCI_PROJECT_NAME+'-'+GCI_API_VERSION
+GCI_CAMEL_CASE_NAME='GCi'
+GCI_VERSIONED_CAMEL_CASE_NAME=GCI_CAMEL_CASE_NAME+'-'+GCI_API_VERSION
+GCI_GIR_NAME= GCI_VERSIONED_CAMEL_CASE_NAME+'.gir'
+GCI_TYPELIB_NAME= GCI_VERSIONED_CAMEL_CASE_NAME+'.typelib'
+GCI_VAPI_NAME = GCI_VERSIONED_PROJECT_NAME+'.vapi'
+
+conf = configuration_data()
+conf.set('prefix', get_option('prefix'))
+conf.set('libdir', '${exec_prefix}/'+get_option ('libdir'))
+conf.set('PROJECT_NAME', GCI_PROJECT_NAME)
+conf.set('PROJECT_VERSION', meson.project_version ())
+conf.set('API_VERSION', GCI_API_VERSION)
+
+configure_file(input : 'gci.pc.in',
+       output : 'gci-@0@.pc'.format(GCI_API_VERSION),
+       configuration : conf,
+       install : true,
+       install_dir : join_paths(get_option('libdir'), 'pkgconfig'))
+
+configure_file(input : 'gci.deps.in',
+       output : 'gci-@0@.deps'.format(GCI_API_VERSION),
+       configuration : conf,
+       install : true,
+       install_dir : vapidir)
+
+gci_nsinfo = configure_file(input : 'namespace-info.vala.in',
+       output : 'namespace-info.vala',
+       configuration : conf)
+gci_namespaceinfo_dep = declare_dependency (sources : gci_nsinfo)
+
+gci_confh = configuration_data ()
+gci_confh.set_quoted('PACKAGE_LOCALE_DIR', join_paths(get_option('prefix'), get_option('datadir'), 'locale'))
+gci_confh.set_quoted('GETTEXT_PACKAGE', 'GCalc')
+configure_file(output : 'config.h',
+       configuration : gci_confh)
+
+
+gci_sources = files([
+       'gci-entry-controller.vala'
+])
+
+
+gci_inc_libh = include_directories ('.')
+gci_inc_libh_dep = declare_dependency (include_directories : gci_inc_libh)
+gci_build_dir = meson.current_build_dir ()
+gci_sources_dir = meson.current_source_dir ()
+
+gci_deps = [
+       gio,
+       gci_namespaceinfo_dep,
+       inc_libh_dep,
+       inc_rooth_dep,
+       gci_inc_libh_dep,
+       gee,
+       gtk
+]
+
+# LT_VERSION for ABI related changes
+# From: https://autotools.io/libtool/version.html
+# This rules applies to Meson 0.43
+# Increase the current value whenever an interface has been added, removed or changed.
+# Always increase revision value whenever an interface has been added, removed or changed.
+# Increase the age value only if the changes made to the ABI are backward compatible.
+# Set version to the value of subtract age from current
+# Reset current and version to 1 and, age and version to 0 if library's name is changed
+GCI_LT_CURRENT='0'
+GCI_LT_REVISION='0'
+GCI_LT_AGE='0'
+GCI_LT_VERSION='0'
+libgci = library(GCI_VERSIONED_PROJECT_NAME,
+       gci_sources,
+       version : GCI_LT_VERSION,
+       soversion : GCI_LT_VERSION+'.'+GCI_LT_AGE+'.'+GCI_LT_REVISION,
+       vala_header : GCI_PROJECT_NAME+'.h',
+       vala_vapi : GCI_VAPI_NAME,
+       vala_gir : GCI_GIR_NAME,
+       dependencies : gci_deps,
+       vala_args: [
+               '--use-header',
+       ],
+       c_args : [
+               '-include',
+               meson.current_build_dir() + '/config.h',
+       ],
+       link_with: [ libgcalc ],
+       install : true,
+       install_dir : [
+               true,
+               join_paths (get_option('includedir'), 'gci-@0@'.format (API_VERSION), 'gci'),
+               vapidir,
+               true
+       ])
+
+if not get_option('disable-introspection')
+if g_ir_compiler.found()
+custom_target('gci-typelib',
+       command: [
+               g_ir_compiler,
+               '--shared-library', 'lib'+GCI_PROJECT_NAME+'-@0@.so'.format (GCI_API_VERSION),
+               '--output', '@OUTPUT@',
+               join_paths(meson.current_build_dir(), GCI_GIR_NAME)
+       ],
+       output: GCI_TYPELIB_NAME,
+       depends: libgci,
+       install: true,
+       install_dir: join_paths(get_option('libdir'), 'girepository-1.0'))
+endif
+endif
+
+libgci_dep = declare_dependency(include_directories : gci_inc_libh,
+  link_with : libgci,
+  dependencies: gci_deps,
+  )
diff --git a/gci/namespace-info.vala.in b/gci/namespace-info.vala.in
new file mode 100644
index 00000000..e539779f
--- /dev/null
+++ b/gci/namespace-info.vala.in
@@ -0,0 +1,24 @@
+/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
+/* Attr.vala
+ *
+ * Copyright (C) 2019 Daniel Espinosa <esodan gmail com>
+ *
+ * This library 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 2.1 of the License, or (at your option) any later version.
+
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Authors:
+ *      Daniel Espinosa <esodan gmail com>
+ */
+[CCode (gir_namespace = "GCi", gir_version = "@API_VERSION@", cheader_filename = "gci/@PROJECT_NAME@.h")]
+namespace GCi {}
diff --git a/meson.build b/meson.build
index 16d11c4a..7173794e 100644
--- a/meson.build
+++ b/meson.build
@@ -64,6 +64,7 @@ subdir('vapi')
 subdir('gcalc')
 if not get_option ('disable-ui')
 gtk = dependency('gtk+-3.0', version: '>= 3.19.3')
+subdir('gci')
 gtksourceview = dependency('gtksourceview-4', version: '>= 4.0.2')
 subdir('data')
 subdir('lib')
diff --git a/tests/gci-test-entry-controller.ui b/tests/gci-test-entry-controller.ui
new file mode 100644
index 00000000..4747c6aa
--- /dev/null
+++ b/tests/gci-test-entry-controller.ui
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <template class="TestsWindow" parent="GtkApplicationWindow">
+    <property name="can_focus">False</property>
+    <property name="title" translatable="yes">Testing GCi.EntryController</property>
+    <child>
+      <placeholder/>
+    </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">GCi Test</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="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="padding">12</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="button">
+            <property name="label" translatable="yes">Close</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <style>
+              <class name="destructive-action"/>
+            </style>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/tests/meson.build b/tests/meson.build
index 24d1d3a3..b65bd9f4 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -49,6 +49,29 @@ test_serializer = executable('test-serializer', test_serializer_sources,
   include_directories: gnome_calculator_tests_includes,
 )
 test('Serializer test', test_serializer)
+
+
+gci_test_deps = [
+       gee,
+       gtk,
+       inc_rooth_dep,
+       inc_libh_dep,
+       gci_inc_libh_dep
+]
+
+test_entry_controler_resource_files = files('test-entry-controller.gresource.xml')
+test_entry_controler_resources = gnome.compile_resources('test-entry-controller-resources', 
test_entry_controler_resource_files)
+
+test_entry_controler_sources = [
+  'test-gci-entry-controller.vala',
+]
+test_entry_controler_sources += test_entry_controler_resources
+
+test_entry_controler = executable('test-entry-controller', test_entry_controler_sources,
+  dependencies: gci_test_deps,
+  link_with: [libgci, libgcalc],
+)
+test('gci-entry-controller', test_entry_controler)
 endif
 
 tests_deps = [
diff --git a/tests/test-entry-controller.gresource.xml b/tests/test-entry-controller.gresource.xml
new file mode 100644
index 00000000..e8ca34da
--- /dev/null
+++ b/tests/test-entry-controller.gresource.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/org/gnome/Calculator">
+    <file preprocess="xml-stripblanks">gci-test-entry-controller.ui</file>
+  </gresource>
+</gresources>
diff --git a/tests/test-gci-entry-controller.vala b/tests/test-gci-entry-controller.vala
new file mode 100644
index 00000000..d42f605e
--- /dev/null
+++ b/tests/test-gci-entry-controller.vala
@@ -0,0 +1,74 @@
+/* -*- Mode: Vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
+/*
+ * GCalc Unit Tests
+ * Copyright (C) Daniel Espinosa Ortiz 2019 <esodan gmail com>
+ *
+ * libgda 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.
+ *
+ * libgda 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/>.
+ */
+using GCalc;
+using GCi;
+
+class Tests {
+  [GtkTemplate (ui = "/org/gnome/Calculator/gci-test-entry-controller.ui")]
+  class Window : Gtk.ApplicationWindow {
+    [GtkChild]
+    Gtk.Entry entry;
+    [GtkChild]
+    Gtk.Button button;
+
+    GCi.EntryController controller;
+
+    construct {
+      controller = new GCi.EntryController ();
+      controller.entry = entry;
+      this.destroy.connect (()=>{
+        application.quit ();
+      });
+      GLib.Timeout.add (10000, ()=>{
+        application.quit ();
+      });
+      button.clicked.connect (()=>{
+        message ("Closing...");
+        application.quit ();
+      });
+    }
+
+    public Window (Gtk.Application app) {
+      Object(application: app);
+    }
+  }
+  class Application : Gtk.Application {
+    public Application () {
+                 Object(application_id: "test.gci.entry.controler",
+                                 flags: ApplicationFlags.FLAGS_NONE);
+         }
+
+         protected override void activate () {
+                 // Create the window of this application and show it
+                 Gtk.ApplicationWindow w = new Window (this);
+                 w.show_all ();
+         }
+  }
+  static int main (string[] args)
+  {
+    GLib.Intl.setlocale (GLib.LocaleCategory.ALL, "");
+    Test.init (ref args);
+    Test.add_func ("/gci/entry/controler",
+    ()=>{
+      var app = new Application ();
+      app.run ();
+    });
+    return Test.run ();
+  }
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]