Add scriptable property to Cocoa application derived from NSObject <NSApplicationDelegate>? - objective-c

Can someone point me to an example of this working. I just want to set a property value via AppleScript. I have gone through all of the scriptable examples, which are setup differently.
<?xml version="1.0" encoding="UTF-8"?>
<dictionary title="">
<suite name="Circle View Scripting" code="bccS" description="Commands and classes for Circle View Scripting">
<class name="application" code="capp" description="" >
<cocoa class="NSApplication"/>
<property name="circletext" code="crtx" type="text" description="The text that gets spun into a circle">
<cocoa key="circleText"/>
</property>
<property name="myint" code="crmy" type="integer" description="The text that gets spun into a circle">
<cocoa key="myInt"/>
</property>
</class>
</suite>
the header file:
// header
#interface MyDelegate : NSObject <NSApplicationDelegate>
{
WebScriptObject *scriptObject;
WebView *webView;
NSWindow *window;
NSInteger myInt;
}
// implementation
- (BOOL)application:(NSApplication*)sender delegateHandlesKey:(NSString*)key
{
return key isEqualToString:#"myInt"] || [key isEqualToString:#"circleText"];;
}
-(NSInteger)myInt
{
NSInteger myInteger = 42;
return myInteger;
}
-(void)setMyInt:(NSInteger*)newVal
{
// do nothing right now
NSLog(#"SETTER CALLED");
}
// Applescript attempt to set property "myInt"
tell application "BrowserConfigClient"
set myint to 7
properties
end tell
Ultimately, the delegateHandlesKey method is called, I am able to return a value for the property, but the setter is never called. Thanks in advance...

Your method statement has an error...
-(void)setMyInt:(NSInteger*)newVal
There should not be a "*" as NSInteger is not a "pointer" variable. I see in the comments of your question that Ken Thomases has already told you this so make sure to fix it.
So if this is not your problem then look at your sdef file. I can see you did not close the dictionary tag. You need this as the last line of that file.
</dictionary>
I also have this as the second line in my sdef files...
<!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd">

Related

HBM mapping both field and property

I have the following class:
public class Foo
{
//...
protected int? someData;
public int? SomeData
{
get {return someData;}
set {someData = value;}
}
//...
}
This class is mapped in HBM file:
<class name="Foo" table="Foo">
//....
<property name="someData" access="field" column="SOME_DATA" />
//....
</class>
For legacy reasons, the columns were mapped to a fields (lowercase), which are unaccessible (not public properties - uppercase).
These lowercase mappings are using multiple times in the project as part of HQL strings, criteria-based queries and so on. It is close to impossible to find all usages.
The problem is that such usage makes it impossible to use even on simple lambda:
session.Query<Foo>().Select(f=>f.SomeData)
throws error, as uppercase "SomeData" is not mapped, and
session.Query<Foo>().Select(f=>f.someData)
does not compile, as lowercase "someData" is protected.
What happens, if I will map BOTH field and property:
<property name="someData" access="field" column="SOME_DATA" />
<property name="SomeData" access="property" column="SOME_DATA" />
I tried quickly, and it seems to work, but will it have any drawback?
Is there any other simple solution, that will not require editing every criteria-based query in project?
Thanks for any help.
You can map the same column multiple times but with recent NHibernate versions only one of the properties need to be mapped as modifiable. So just add insert="false" update="false" to your additional mappings to avoid any issues in future:
<property name="someData" access="field" column="SOME_DATA" />
<property name="SomeData" access="property" column="SOME_DATA" update="false" insert="false" />

How to subclass GTK IconView in Vala with Glade

When I try to subclass a GTK IconView in Vala using Glade, I get a segmentation fault. Is this a bug in Vala, or am I just doing something wrong? This is using vala 0.42.3. Maybe this is related to how IconView doesn't have a base() constructor? (see: Chain up to 'Gtk.Box.new' not supported)
test.vala:
using Gtk;
public class IconViewSubclass : Gtk.IconView {
public IconViewSubclass() {
}
}
public static int main(string[] args) {
Gtk.init(ref args);
var builder = new Builder.from_file("test.glade");
var window = builder.get_object("window") as Window;
var iconViewSubclass = builder.get_object("iconViewSubclass") as IconViewSubclass;
iconViewSubclass.set_pixbuf_column(0);
iconViewSubclass.set_text_column(1);
window.show_all();
Gtk.main();
return 0;
}
test.glade:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkListStore" id="store">
<columns>
<!-- column-name pixbuf -->
<column type="GdkPixbuf"/>
<!-- column-name text -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkWindow" id="window">
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkIconView" id="iconViewSubclass">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin">6</property>
<property name="model">store</property>
</object>
</child>
</object>
</interface>
$ valac --pkg gtk+-3.0 test.vala && ./test
Segmentation fault
It looks like you need to let the Gtk.Builder know IconViewSubclass exists using expose_object(). This allows the sub-type to be used in the Builder UI definition file. Here's an example that compiles and does not segfault:
test.ui:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.18"/>
<object class="GtkWindow" id="window">
<property name="window-position">GTK_WIN_POS_CENTER</property>
<property name="default-height">250</property>
<property name="default-width">250</property>
<child>
<placeholder/>
</child>
<child>
<object class="IconViewSubclass" id="iconViewSubclass">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin">6</property>
</object>
</child>
</object>
</interface>
and test.vala:
using Gtk;
public class IconViewSubclass : Gtk.IconView {}
public static int main(string[] args) {
Gtk.init(ref args);
var builder = new Builder ();
builder.expose_object ("IconViewSubclass", new IconViewSubclass ());
try {
builder.add_from_file ("test.ui");
} catch (Error error) {
print (#"$(error.message)");
}
var window = builder.get_object ("window") as Window;
var iconViewSubclass = (IconViewSubclass)builder.get_object ("iconViewSubclass");
iconViewSubclass.set_pixbuf_column (0);
iconViewSubclass.set_text_column (1);
window.show_all();
Gtk.main();
return 0;
}
You may want to look into using templates with Vala [GtkTemplate], [GtkChild] and [GtkCallback] attributes. The attributes will tell Vala to generate the boiler plate code for you.
AIThomas' code worked great, however, in order to continue editing the UI file in Glade I had to add a catalog file, as follows:
<?xml version="1.0" encoding="UTF-8"?>
<glade-catalog name="test" depends="gtk+">
<glade-widget-classes>
<glade-widget-class name="IconViewSubclass" generic-name="iconviewsubclass" title="IconViewSubclass" parent="GtkIconView"/>
</glade-widget-classes>
<glade-widget-group name="test" title="test">
<glade-widget-class-ref name="IconViewSubclass"/>
</glade-widget-group>
</glade-catalog>
I also discovered that the subclass name in Vala must correspond exactly with the widget name in the UI XML, i.e. changing IconViewSubclass to IconViewSubclass2 in test.vala will give you:
$ valac --pkg gtk+-3.0 test.vala && ./test
test.ui:14:1 Invalid object type 'IconViewSubclass'Segmentation fault
You can also use a namespace as part of the class name, i.e. namespace Foo { public class Bar : Baz } should work for a widget of type FooBar in the UI XML file.

android-binding: onclick depend on variable

I need when isFavorite is true then when click then call onClickSubscribe() else call onClickUnsubscribe().
In my fragment:
#Override
public void onClickSubscribe() {
}
In my xml:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View" />
<variable
name="handler"
type="SubscribeBrandDialogFragment" />
</data>
<TextView
android:id="#+id/subscribeTextView"
android:layout_width="185dp"
android:layout_height="40dp"
android:onClick="#{handler.isFavorite ? handler.onClickSubscribe() : handler.onClickUnsubscribe()}"
android:text="#{handler.isFavorite ? #string/unsubscribe : #string/subscribe}"/>
</layout>
But I get error:
e: [kapt] An exception occurred: android.databinding.tool.util.LoggedErrorException: Found data binding errors.
****/ data binding error ****msg:Cannot find the setter for attribute 'android:onClick' with parameter type void on android.widget.TextView.
file:res\layout\subscribe_brand_dialog.xml
loc:100:31 - 100:108
****\ data binding error ****
at android.databinding.tool.processing.Scope.assertNoError(Scope.java:112)
Cannot find the setter for attribute 'android:onClick' with parameter
type void on android.widget.TextView
What does this say? Exactly this is problem!
If you don't write ()-> in your onClick then you have to give your View type as first parameter in method.
Solution
Change onClick line to below.
android:onClick="#{handler.isFavorite ? handler::onClickSubscribe : handler::onClickUnsubscribe}"
And set TextView as first parameter of onClickSubscribe & onClickUnsubscribe like.
void onClickSubscribe (TextView tv) {
...
}
& same for onClickUnsubscribe
All done!
I like shortcuts, so here is Tip
Make a common method with Boolean.
void onSubscribe(boolean isSubscribe){
if(isSubscribe){}
else {}
}
and call it like
android:onClick="#{() -> handler.onSubscribe(handler.isFavorite)}"
So your two methods are reduced to 1.
If you need to pass any other value just change parameter of onSubscribe. and pass from xml.
you can use this :
android:onClick="#{()->handler.isFavorite ? handler.onClickSubscribe() : handler.onClickUnsubscribe()}"
do no forget ()-> at first

NHibernate stored procedure problem

I'm having a hard time trying to get my stored procedure works with NHibernate. The data returned from the SP does not correspond to any database table.
This is my mapping file:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel.Entities">
<sql-query name="DoSomething">
<return class="SomeClass">
<return-property name="ID" column="ID"/>
</return>
exec [dbo].[sp_doSomething]
</sql-query>
</hibernate-mapping>
Here is my domain class:
namespace DomainModel.Entities
{
public class SomeClass
{
public SomeClass()
{
}
public virtual Guid ID
{
get;
set;
}
}
}
When I run the code, it fails with
Exception Details: NHibernate.HibernateException: Errors in named queries: {DoSomething}
at line 80
Line 78: config.Configure(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "NHibernate.config"));
Line 79:
Line 80: g_sessionFactory = config.BuildSessionFactory();
When I debug into NHibernate code, it seems that SomeClass is not added to the persister dictionary because there isn't a class mapping (only sql-query) defined in hbm.xml. And later on in CheckNamedQueries function, it is not able to find the persistor for SomeClass.
I've checked all the obvious things (e.g. make hbm as an embedded resource) and my code isn't too much different from other samples I found on the web, but somehow I just can't get it working. Any idea how I can resolve this issue?
Well, where is your class mapping for SomeClass?
You still need to map it. Read http://nhibernate.info/doc/nh/en/index.html#querysql-load.
Look at using a class mapping with a subselect block. I found this in the Java documentation but maybe it will work for .Net too.
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/mapping.html (scroll down to section 5.1.3)

Defining and executing simple AppleScript commands in a Cocoa app

I'm trying to add some scripting functionality to a Cocoa app that I've written. I've created an sdef (Scripting Definition File) for my project. So far I have been successful in accessing object children (elements) with AppleScript but I cannot for the life of me figure out how to call methods (commands).
Here is my sdef file.
<suite name="mySuite" code="mSUI" description="My Application Suite">
<class name="application" code="capp" description="Top level scripting object.">
<cocoa class="NSApplication"/>
<!-- I can access these elements fine -->
<element description="Test children." type="child" access="r">
<cocoa key="myChildren"/>
</element>
<!-- Cannot seem to call this method :( -->
<responds-to command="testmethod">
<cocoa method="exposedMethod:"/>
</responds-to>
</class>
<class name="child" code="cHIL" description="A Child." plural="children">
<cocoa class="Child"/>
<property name="name" code="pnam" description="The child name." type="text" access="r">
<cocoa key="name"/>
</property>
</class>
<command name="testmethod" code="tEST" description="Execute the test method" />
</suite>
Here are my controller class implementations (this is the delegate of my application)
MyController.h
#import <Cocoa/Cocoa.h>
#interface MyController : NSObject {
NSMutableArray* myChildren;
}
// Some Methods
#end
MyController+Scripting.m
#import "MyController+Scripting.h"
#implementation MyController (Scripting)
// This works when I'm accessing the myChildren
- (BOOL)application:(NSApplication*)sender delegateHandlesKey:(NSString*)key {
NSLog(#"Key = %#", key);
return ([key isEqualToString:#"myChildren"]);
}
// This does NOT work...
- (void)exposedMethod:(NSScriptCommand*)command {
NSLog(#"Invoked Test Script Method %#", [command description]);
}
#end
Lastly, the AppleScript I am trying is:
tell application "MyApplication"
testmethod
end tell
which responds with "AppleScript Error - The variable testmethod is not defined."
Any ideas what I'm doing wrong here? I feel like I'm missing something simple but my Googling doesn't seem to be turning up anything helpful.
Things look mostly right, but the code for the <command/> should be a two-part code (eight characters) and not four.
I just posted a detailed solution on how to add a command with argument here: https://stackoverflow.com/a/10773994/388412
In short: I think you should subclass NSScriptCommand and override -(void)performDefaultImplementation rather than exposing a method in your controller. At least that's what I distilled from the docs:
"This command is a subclass of NSScriptCommand, containing one method, performDefaultImplementation. That method overrides the version in NSScriptCommand"
… and it works fine for me, see my linked answer for details.
(I've actually never added scriptability to a Cocoa app, so take my stab in the dark with a grain of salt.)
The first thing I would guess is that exposedMethod: takes a parameter, but I don't see where one might be specified in your sdef or AppleScript. In fact, it looks like AppleScript is treating testmethod as a variable, not a command. (Maybe it should be something like "testmethod with ..." instead?) You may need to define a <parameter> or <direct-parameter> element for the command in the sdef.
Also, wouldn't you need an object to call the method on? Since your controller is the application delegate, I'm not sure of the intricacies there, but might AppleScript try to invoke testMethod: on NSApplication instead of your delegate?
I'm guessing you've looked at Apple's sample code and other resources, but if not, here are a few links that may help:
Introduction to Cocoa Scripting Guide
TechNote 2106: Scripting Interface Guidelines
http://developer.apple.com/samplecode/SimpleScriptingObjects/
http://developer.apple.com/samplecode/SimpleScriptingPlugin/
http://www.shadowlab.org/softwares/SdefEditor/sdef-format.html
Good luck!