I am trying to add a procedure to pop-up a modal dialog inside a plug-in.
Its purpose is to query a response at designated steps within the control-flow of the plug-in (not just acquire parameters at its start).
I have tried using gtk - I get a dialog but it is asynchronous - the plugin continues execution. It needs to operate as a synchronous function.
I have tried registering a plugin in order to take advantage of the gimpfu start-up dialogue for same. By itself, it works; it shows up in the procedural db when queried. But I never seem to be able to actually invoke it from within another plug-in - its either an execution error or wrong number of arguments no matter how many permutations I try.
[Reason behind all of this nonsense: I have written a lot of extension Python scripts for PaintShopPro. I have written a App package (with App.Do, App.Constants, Environment and the like that lets me begin to port those scripts to GIMP -- yes it is perverse, and yes sometimes the code just has to be rewritten, but for a lot of what I actual use in the PSP.API it is sufficient.
However, debugging and writing the module rhymes with witch. So. I am trying to add emulation of psp's "SetExecutionMode" (ie interactive). If
set, the intended behavior is that the App.Do() method will "pause" after/before it runs the applicable psp emulation code by popping up a simple message dialog.]
A simple modal dialogue within a gimp python-fu plug-in can be implemented via gtk's Dialog interface, specifically gtk.MessageDialog.
A generic dialog can be created via
queryDialogue = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT \
gtk.MESSAGE_QUESTION, \
gtk.BUTTONS_OK_CANCEL, "")
Once the dialog has been shown,
a synchronous response may be obtained from it
queryDialogue.show()
response = queryDialogue.run()
queryDialogue.hide()
The above assumes that the dialog is not created and thence destroyed after each use.
In the use case (mentioned in the question) of a modal dialog to manage single stepping through a pspScript in gimp via an App emulator package, the dialogue message contents need to be customized for each use. [Hence, the "" for the message argument in the Constructor. [more below]]
In addition, the emulator must be able to accept a [cancel] response to 'get out of Dodge' - ie quit the entire plug-in (gracefully). I could not find a gimpfu interface for the latter, (and do not want to kill the app entirely via gimp.exit()). Hence, this is accomplished by raising a custom Exception class [appTerminate] within the App pkg and catching the exception in the outer-most scope of the plugin. When caught, then, the plug-in returns (exits).[App.Do() can not return a value to indicate continue/exit/etc, because the pspScripts are to be included verbatim.]
The following is an abbreviated skeleton of the solution -
a plug-in incorporating (in part) a pspScript
the App.py pkg supplying the environment and App.Do() to support the pspScript
a Map.py pkg supporting how pspScripts use dot-notation for parameters
App.py demonstrates creation, customization and use of a modal dialog - App.doContinue() displays the dialogue illustrating how it can be customized on each use.
App._parse() parses the pspScript (excerpt showing how it determines to start/stop single-step via the dialogue)
App._exec() implements the pspScript commands (excerpt showing how it creates the dialogue, identifies the message widget for later customization, and starts/stops its use)
# App.py (abbreviated)
#
import gimp
import gtk
import Map # see https://stackoverflow.com/questions/2352181/how-to- use-a-dot-to-access-members-of-dictionary
from Map import *
pdb = gimp.pdb
isDialogueAvailable = False
queryDialogue = None
queryMessage = None
Environment = Map({'executionMode' : 1 })
_AutoActionMode = Map({'Match' : 0})
_ExecutionMode = Map({'Default' : 0}, Silent=1, Interactive=2)
Constants = Map({'AutoActionMode' : _AutoActionMode}, ExecutionMode=_ExecutionMode ) # etc...
class appTerminate(Exception): pass
def Do(eNvironment, procedureName, options = {}):
global appTerminate
img = gimp.image_list()[0]
lyr = pdb.gimp_image_get_active_layer(img)
parsed = _parse(img, lyr, procedureName, options)
if eNvironment.executionMode == Constants.ExecutionMode.Interactive:
resp = doContinue(procedureName, parsed.detail)
if resp == -5: # OK
print procedureName # log to stdout
if parsed.valid:
if parsed.isvalid:
_exec(img, lyr, procedureName, options, parsed, eNvironment)
else:
print "invalid args"
else:
print "invalid procedure"
elif resp == -6: # CANCEL
raise appTerminate, "script cancelled"
pass # terminate plugin
else:
print procedureName + " skipped"
pass # skip execution, continue
else:
_exec(img, lyr, procedureName, options, parsed, eNvironment)
return
def doContinue(procedureName, details):
global queryMessage, querySkip, queryDialogue
# - customize the dialog -
if details == "":
msg = "About to execute procedure \n "+procedureName+ "\n\nContinue?"
else:
msg = "About to execute procedure \n "+procedureName+ "\n\nDetails - \n" + details +"\n\nContinue?"
queryMessage.set_text(msg)
queryDialogue.show()
resp = queryDialogue.run() # get modal response
queryDialogue.hide()
return resp
def _parse(img, lyr, procedureName, options):
# validate and interpret App.Do options' semantics vz gimp
if procedureName == "Selection":
isValid=True
# ...
# parsed = Map({'valid' : True}, isvalid=True, start=Start, width=Width, height=Height, channelOP=ChannelOP ...
# /Selection
# ...
elif procedureName == "SetExecutionMode":
generalOptions = options['GeneralSettings']
newMode = generalOptions['ExecutionMode']
if newMode == Constants.ExecutionMode.Interactive:
msg = "set mode interactive/single-step"
else:
msg = "set mode silent/run"
parsed = Map({'valid' : True}, isvalid=True, detail=msg, mode=newMode)
# /SetExecutionMode
else:
parsed = Map({'valid' : False})
return parsed
def _exec(img, lyr, procedureName, options, o, eNvironment):
global isDialogueAvailable, queryMessage, queryDialogue
#
try:
# -------------------------------------------------------------------------------------------------------------------
if procedureName == "Selection":
# pdb.gimp_rect_select(img, o.start[0], o.start[1], o.width, o.height, o.channelOP, ...
# /Selection
# ...
elif procedureName == "SetExecutionMode":
generalOptions = options['GeneralSettings']
eNvironment.executionMode = generalOptions['ExecutionMode']
if eNvironment.executionMode == Constants.ExecutionMode.Interactive:
if isDialogueAvailable:
queryDialogue.destroy() # then clean-up and refresh
isDialogueAvailable = True
queryDialogue = gtk.MessageDialog(None, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL, "")
queryDialogue.set_title("psp/APP.Do Emulator")
queryDialogue.set_size_request(450, 180)
aqdContent = queryDialogue.children()[0]
aqdHeader = aqdContent.children()[0]
aqdMsgBox = aqdHeader.children()[1]
aqdMessage = aqdMsgBox.children()[0]
queryMessage = aqdMessage
else:
if isDialogueAvailable:
queryDialogue.destroy()
isDialogueAvailable = False
# /SetExecutionMode
else: # should not get here (should have been screened by parse)
raise AssertionError, "unimplemented PSP procedure: " + procedureName
except:
raise AssertionError, "App.Do("+procedureName+") generated an exception:\n" + sys.exc_info()
return
A skeleton of the plug-in itself. This illustrates incorporating a pspScript which includes a request for single-step/interactive execution mode, and thus the dialogues. It catches the terminate exception raised via the dialogue, and then terminates.
def generateWebImageSet(dasImage, dasLayer, title, mode):
try:
img = dasImage.duplicate()
# ...
bkg = img.layers[-1]
frameWidth = 52
start = bkg.offsets
end = (start[0]+bkg.width, start[1]+frameWidth)
# pspScript: (snippet included verbatim)
# SetExecutionMode / begin interactive single-step through pspScript
App.Do( Environment, 'SetExecutionMode', {
'GeneralSettings': {
'ExecutionMode': App.Constants.ExecutionMode.Interactive
}
})
# Selection
App.Do( Environment, 'Selection', {
'General' : {
'Mode' : 'Replace',
'Antialias' : False,
'Feather' : 0
},
'Start': start,
'End': end
})
# Promote
App.Do( Environment, 'SelectPromote' )
# und_so_weiter ...
except App.appTerminate:
raise AssertionError, "script cancelled"
# /generateWebImageSet
# _generateFloatingCanvasSetWeb.register -----------------------------------------
#
def generateFloatingCanvasSetWeb(dasImage, dasLayer, title):
mode="FCSW"
generateWebImageSet(dasImage, dasLayer, title, mode)
register(
"generateFloatingCanvasSetWeb",
"Generate Floating- Frame GW Canvas Image Set for Web Page",
"Generate Floating- Frame GW Canvas Image Set for Web Page",
"C G",
"C G",
"2019",
"<Image>/Image/Generate Web Imagesets/Floating-Frame Gallery-Wrapped Canvas Imageset...",
"*",
[
( PF_STRING, "title", "title", "")
],
[],
generateFloatingCanvasSetWeb)
main()
I realize that this may seem like a lot of work just to be able to include some pspScripts in a gimp plug-in, and to be able to single-step through the emulation. But we are talking about maybe 10K lines of scripts (and multiple scripts).
However, if any of this helps anyone else with dialogues inside plug-ins, etc., so much the better.
I try to create a simple function who try to fill specific fields in own form when I select the ID of patient registered in other form/module. I put an example:
Module Registro:
(create patient)
(automatic generation ID and visible)
-Nombre:
-Email:
-Teléfono:
(save)
Admisión module:
(Open new form)
-ID: select id
(function for auto fill the next fields)
-Nombre: nombre (registro)
-Email: email(registro)
-Teléfono: teléfono(registro)
Use the new API Odoo 8.0 I try this, but doesn't work with message: error 500 type.
función autocompletar campos
#api.onchange('telefono_contacto','persona_contacto','email','nombre_acompanante') # mete campos a afectar
def autofill(self):
# comdición; si esta con el id seleccionado
# self.id_anamnesis
# llenar los campos con los correspondientes del id
# self.telefono_contacto =''
# self.persona_contacto = ''
# self.email = ''
# self.nombre_acompanante = ''
pass # aquí la lógica
(La plataforma es Odoo 8.0, S.O: Ubuntu 14.04)
Thank you and best reegards,
Marco García Baturan.
product_id = fields.Many2one("myproduct.model",string="Product", required=True)
description = fields.Char("Description", related="product_id.description", store=True)
It is done using related="......"
What I have done is When I select my product it will automatically
set description of that particular product.
So you need to add related where you want to auto fill.
If you set store=True then description is store into database.
I'm having a strange problem when trying to set a callback for Facebook Authentication via Omniauth. In my controller (simplified to just the code necessary to show the error) I have:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
raise env.inspect
# auth_hash = env["omniauth.auth"]
end
end
this works in production mode, showing me the hash. However in test mode env is set to nil.
I have the following set in my spec_helper.rb file
OmniAuth.config.test_mode = true
OmniAuth.config.add_mock(:facebook, {"credentials" => {
"token" => "foo-token"
}
})
and my spec looks like this:
require 'spec_helper'
describe Users::OmniauthCallbacksController do
describe "Facebook" do
before(:each) do
request.env["devise.mapping"] = Devise.mappings[:user]
request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:facebook]
end
it "should be a redirect" do
get :facebook
response.should redirect_to(root_path)
end
end
end
Can anyone enlighten me on what I need to do to have env not be nil when running my tests?
I use the following in my spec_helper.rb :
RACK_ENV = ENV['ENVIRONMENT'] ||= 'test'
I don't use Rails or Devise though so YMMV. I've also seen various threads saying that someone had to do this before their requires to get it to work.
So I have a rails app 2.x app that works fine via the web, but when trying to perform a POST I keep getting "Redirected to http://localhost:3000/session/new Filter chain halted as [:require_user] rendered_or_redirected.". In my iPhone app, I can create a new session and sign-in via my iPhone app, but cannot POST to say the POSTS_Controller.
I have this in my code
Posts_Controller
before_filter :require_user, :only => [:create, :update, :destroy]
Application_Controller
# Filters added to this controller apply to all controllers in the application.
# Likewise, all the methods added will be available for all controllers.
class ApplicationController < ActionController::Base
include AuthenticatedSystem
include Geokit::Geocoders
helper :all # include all helpers, all the time
#session :session_key => '_cwa_session_id'
#filter_parameter_logging :password
# See ActionController::RequestForgeryProtection for details
# Uncomment the :secret if you're not using the cookie session store
protect_from_forgery # :secret => 'eejj7eded74769099999944a729b4f'
#filter_parameter_logging(:password)
before_filter :login_from_cookie
before_filter :find_user_interests
before_filter :find_user_posts
protected
def find_user_interests
#user_interests = cur_user ? cur_user.interesting_posts : []
logger.debug "User interests hash: #{current_user.inspect}"
end
def find_user_posts
#user_posts = cur_user ? cur_user.posts : []
end
def cur_user
User.find(session[:user_id]) if session[:user_id]
end
def require_user
unless cur_user
flash[:error] = "You must be logged in to do that."
redirect_to '/session/new'
return false
end
end
geocode_ip_address
def geokit
#location = session[:geo_location]
end
end
I have been working on this for 2 months and cannot figure out the issue. In my iPhone app I am using ObjectiveResource. I am sending over json and have "Mime::Type.register_alias "application/json", :json" set up on the rails side.
I am not a rails developer, but the before filter for require_user is unable to pass the cur_user test in that is cannot find :user_id in the session hash. Are you sure that you have a session that persists when using the iPhone? Are you using devise for authentication? Just for kicks, does it work if you manually pass the user_id as params?
I am trying to call a web service in rhosync application.rb, I see a 500 error response in rhosync console .. and 'server returned an error' in BB simulator .. :(
Some info about my setup -
I have created a rhodes app that connects to a rhosync app when user enters user name and password and clicks on "login". I am calling this webservice through "authenticate" method of application.rb of the rhosync application ..
def authenticate(username,password,session)
Rho::AsyncHttp.get(:url => 'http://mywebserviceURL',:callback => (url_for :action => :httpget_callback),:callback_param => "" )
end
UPDATE
Instead of http:async, I tried consuming a soap based webservice and it worked just fine .. here is code if anyone cones here in search of a sample.. in application.rb of rhosync app
require "soap/rpc/driver"
class Application < Rhosync::Base
class << self
def authenticate(username,password,session)
driver = SOAP::RPC::Driver.new('http://webserviceurl')
driver.add_method('authenticate', 'username', 'password')
ret=driver.authenticate(username,password)
if ret=="Success" then
true
else
false
end
end
end
Application.initializer(ROOT_PATH)
You can typically find the problem if you crank up your log. Edit rhoconfig.txt in your app
set these properties -
# Rhodes runtime properties
MinSeverity = 1
LogToOutput = 1
LogCategories = *
ExcludeLogCategories =
then try again and watch the terminal output. Feel free to post the log back and I'll take a look.
You also might want to echo out puts the mywebserviceURL if you're using that as a variable, I trust you just changed that for the post here. Can you access the webservice if you hit it with a browser?
require "soap/rpc/driver"
class Application < Rhosync::Base
class << self
def authenticate(username,password,session)
driver = SOAP::RPC::Driver.new('http://webserviceurl')
driver.add_method('authenticate', 'username', 'password')
ret=driver.authenticate(username,password)
if ret=="Success" then
true
else
false
end
end
end
Application.initializer(ROOT_PATH)
in this what is done in add_method and authenticate method and where it to be written.