Strange treeview behaviour: strikeout text only if bold - ruby

I need to show some treeview item text striked out text into a QT treeview from Ruby.
After some reading on QT documentation and much coding, I found that only when rendering font in bold, also the strikeout was rendered.
So I wonder, where I'm doing wrong?
This is the code to achive the result shown above. Note as I set strikeout for every even row item.
I'm using Ruby 1.8.7 and Qt 4.6.2 and qt4ruby 4.4.3-6 on Mandriva Linux.
require 'Qt4'
require 'date'
class MyStandardItem < Qt::StandardItem
def initialize(str = nil)
super str
end
def data(role = Qt::UserRole + 1)
return super(role) unless role == Qt::FontRole
ret_val = Qt::Font.new()
#parameters for "fromString":font family, pointSizeF, pixelSize, QFont::StyleHint, QFont::Weight, QFont::Style, underline, strikeOut, fixedPitch, rawMode
ret_val.fromString "sans serif,-1,-1,0,0,0,0,0,0,0"
case role
when Qt::FontRole
ret_val.setStrikeOut(true) if (index.row % 2) == 0
if index.column == 1
ret_val.weight = Qt::Font.Bold
else
ret_val.weight = Qt::Font.Normal
end
return Qt::Variant.fromValue(ret_val)
end
return ret_val
end
end
Qt::Application.new(ARGV) do
treeview = Qt::TreeView.new do
model = Qt::StandardItemModel.new self
head = [MyStandardItem.new "Qt v. #{Qt.version}"]
head << MyStandardItem.new("Ruby v. #{VERSION}")
head << MyStandardItem.new("Qt4Ruby v. 4.4.3-6 (Mandriva)")
model.append_row head
(1..10).each do |i|
col0 = MyStandardItem.new 'some text'
col0.check_state = ((i % 3) == 0)? Qt.Checked : Qt.Unchecked
col0.checkable = true
col0.editable= false
col1 = MyStandardItem.new "line ##{i}"
col2 = MyStandardItem.new((Date.today + i).strftime '%d/%m/%y')
model.append_row [col0, col1, col2]
end
self.model = model
show
end
exec
end

Eventually I find an hackish trick to overcome this problem. Playing around after reading again the enum QFont::Weight description I tried to set
ret_val.weight = 51 # Qt::Font.Normal value is 50
instead of
ret_val.weight = Qt::Font.Normal
and magically the normal text appears striked out!
Maybe this strange behaviour is due to a bug on QT?

Related

Can mechanize for Ruby filter the contents of a <select> by class?

Sorry, but I didn't find the documentation enlightening at all. Basically, I am trying to iterate through a where some options are not valid. The ones I want have 'class="active"'. Can I do that with mechanize? Here's what I have so far:
class Scraper
def init
mech = Mechanize.new
page = mech.get('url')
#Now go through the <select> to get product numbers for the different flavors
form = page.form_with(:id => 'twister')
select = form.field_with(:name => 'dropdown_selected_flavor_name')
select.options.each do |o|
if (o.text != "")
value = o
end
productNumber = trim_pn(value.to_s[2..12])
puts productNumber
end
end
#Checks validity of product number and removes excess characters if necessary
def trim_pn(pn)
if (pn[0] == ",")
pn = pn[1..-1]
end
return pn
end
end
p = Scraper.new
p.init
All that does is grabs the product number and removes some extra info that I don't want. I thought replacing the .each do with this:
select.options_with(:class => 'active').each do |o|
if (o.text != "")
value = o
end
end
But that throws "undefined method 'dom_class' for Mechanize:Form:Option blah blah." Is there are different way I should be approaching this?

Dynamically check if a field in JSON is nil without using eval

Here's an extract of the code that I am using:
def retrieve(user_token, quote_id, check="quotes")
end_time = Time.now + 15
match = false
until Time.now > end_time || match
#response = http_request.get(quote_get_url(quote_id, user_token))
eval("match = !JSON.parse(#response.body)#{field(check)}.nil?")
end
match.eql?(false) ? nil : #response
end
private
def field (check)
hash = {"quotes" => '["quotes"][0]',
"transaction-items" => '["quotes"][0]["links"]["transactionItems"]'
}
hash[check]
end
I was informed that using eval in this manner is not good practice. Could anyone suggest a better way of dynamically checking the existence of a JSON node (field?). I want this to do:
psudo: match = !JSON.parse(#response.body) + dynamic-path + .nil?
Store paths as arrays of path elements (['quotes', 0]). With a little helper function you'll be able to avoid eval. It is, indeed, completely inappropriate here.
Something along these lines:
class Hash
def deep_get(path)
path.reduce(self) do |memo, path_element|
return unless memo
memo[path_element]
end
end
end
path = ['quotes', 0]
hash = JSON.parse(response.body)
match = !hash.deep_get(path).nil?

Keyboard Shortcut doesn't work in ruby-gtk2 TextView

I'm practicing on a GUI based on Gtk and Ruby. I planned to make a little window that has a TextView and a button. When you input text in the TextView and press the button, it calls the Twitter gem's method and tweets to Twitter.
After that succeeded, I wanted to make a keyboard short-cut to do this: like, when you hit Ctrl+Enter it Tweets.
Here's part of the source code I have written. (Only around the GUI)
# require "gtk2"
# require "twitter"
## error classes and methods first
class Error_pop
def initialize(text)
#pop = Gtk::Dialog.new(
"Error",
nil,
Gtk::Dialog::MODAL,
[Gtk::Stock::OK, Gtk::Dialog::RESPONSE_OK]
)
#pop.default_response = Gtk::Dialog::RESPONSE_OK
#pop.set_size_request(400, 100)
#label = Gtk::Label.new("#{ text }")
#table = Gtk::Table.new(3, 1, false)
#table.attach_defaults(#label, 0, 1, 0, 2)
#pop.vbox.add(#table)
end
attr_accessor :pop, :table, :label
end
module Tueet
def tueet(text, account)
begin
account.rest_api.update(text) # calls gem: twitter
rescue => reason
error_pop = Error_pop.new(reason)
error_pop.pop.show_all
error_pop.pop.run do |response|
if response == Gtk::Dialog::RESPONSE_OK
end
end
error_pop.pop.destroy
return text
else
return nil
end
end
module_function :tueet
end
## making gui
window = Gtk::Window.new(Gtk::Window::TOPLEVEL)
window.title = "Tweet Box"
window.set_size_request(300, 150)
window.resizable = false
window.signal_connect('delete_event') do
Gtk.main_quit
false
end
inputter = Gtk::TextView.new
inputter.editable = true
inputter.wrap_mode = Gtk::TextTag::WRAP_WORD_CHAR
inputter_event = Gtk::EventBox.new # for key binding
inputter_event.events = Gdk::Event::KEY_PRESS_MASK
tweetbutton = Gtk::Button.new("tweet")
table = Gtk::Table.new(4, 9, true)
table.attach(inputter, 0, 9, 0, 3, Gtk::FILL||Gtk::EXPAND, Gtk::FILL||Gtk::EXPAND, 5, 5)
table.attach(tweetbutton, 3, 6, 3, 4)
inputter_event.add(table)
window.add(inputter_event)
inputter_event.realize
## signals and stuff
text = nil
tweetbutton.signal_connect('clicked') do
text = inputter.buffer.text
returned_text = Tueet.tueet(text, client[0]) # client[n] holds the authorized account information
inputter.buffer.text = String(returned_text)
end
inputter_event.signal_connect('key-press-event') do |wdt, evt|
key = Gdk::Keyval.to_name(evt.keyval)
p ("KeyPress: #{ key }was pressed") # these lines
p evt.state # are for
p evt.keyval # debugging
if key == 'Return' && # when "Ctrl + Return", do Tueet.tueet
( evt.state & Gdk::Window::CONTROL_MASK ==
Gdk::Window::ModifierType::CONTROL_MASK )
Tueet.tueet(text, client[0])
end
end
window.show_all
Gtk.main
And, this doesn't work. When I press Ctrl + Enter, it simply linebreaks inside the TextView.
Only, when doing this:
inputter = Gtk::TextView.new
inputter.editable = false # <- making this false
inputter.wrap_mode = Gtk::TextTag::WRAP_WORD_CHAR
makes the keybinding work, but disables me to input what I want to tweet to the TextView.
How can I work this out? I wonder how many GUI applications do this.

JRuby require error on .so file

I am working on a feature for an application that has to run on JRuby. Out of habit I develop on 'Native' Ruby. When I try to run any methods from this class in JRuby I get error messages like:
MissingSourceFile: no such file to load -- serialport
I think the problem lies in in the require 'serialport.so'. Is there a way to make this work in JRuby? Is there another way to require a .so file? Or a gem that can work with JRuby to provide the SerialPort class? I tried installing the ruby-serialport gem but that doesn't seem to install properly (Windows nmake issues).
Here is what my class file looks like:
require 'serialport.so'
class AlphaDisplay
#STATES
SOLID = "b"
ROTATE = "a"
BLINK = "c"
#COLORS
RED = "1"
GREEN = "2"
YELLOW = "3"
ORANGE = "7"
def self.message(address = 00, text = "ICS", color = AlphaDisplay::GREEN, state = AlphaDisplay::SOLID)
address = address.to_s
if address.length == 1
address = "0#{address}"
end
string = 1.chr + 90.chr + address + 2.chr + 65.chr + 65.chr + 27.chr + 26.chr + state + 28.chr + color + text + 4.chr
return string
end
def self.test(address = 00, text = "ICS", color = AlphaDisplay::GREEN, state = AlphaDisplay::SOLID)
sp = SerialPort.new(0, 9600, 8, 1, SerialPort::NONE)
sp.write(message(address,text,color,state))
sp.close
end
end
def SerialPort::new(port, *params)
sp = create(port)
begin
sp.set_modem_params(*params)
rescue
sp.close
raise
end
return sp
end
def SerialPort::open(port, *params)
sp = create(port)
begin
sp.set_modem_params(*params)
if (block_given?)
yield sp
sp.close
return nil
end
rescue
sp.close
raise
end
return sp
end
As far as I know, JRuby doesn't provide any native emulation layer, just the Ruby interpreter in Java. The problem is that ".so" files are UNIX specific and cannot run on Windows without some sort of emulation/translation.
You're better off avoiding Ruby libraries which require native extensions if you're going to use JRuby.

How to loop through an table and turn rows into objects using nokogiri

I want to use nokogiri to loop through a html and create an object corresponding to every row. I am able to define the root xpaths where I want the data to fill the object varibles comes from but I dont know how to group these as an object.
My code is below. I know it doesn't work but I dont know what direction to go to make it work.
require 'rubygems'
require 'nokogiri'
doc = Nokogiri::HTML.parse(<<-HTML_END)
"
LV1LV2LV3
MV1MV2MV3
NV1NV2NV3
"
HTML_END
class Post
def initialize(v1, v2, v3 )
#v1 =v1
#v2 = v2
#v3 = v3
end
def v1= (v1)
#v1 =v1
end
def v2
#v2 =v2
end
def v3
#v3 =v3
end
end
class PostList
def initialize
#posts = Array.new
end
def append(aPost)
#posts.push(aPost)
self
end
def deleteFirst
#posts.shift
end
def deleteLast
#posts.pop
end
end
list = PostList.new
parent = doc.css('body').first
gets the contects of the row
parent.xpath("//div/table[#class='ipbtable']/tr" ).each do |a_tag|
k1 = "x"
k2 = "x"
k3 = "x"
a_tag.xpath("td[1]").each do |x_tag|
puts x_tag.content
end
list.append(Post.new(k1, k2, k3) )
end
The main problem with the code appears to be you're passing strings ('K1', 'K2', 'K3') that vaguely resemble the names of variables rather than the variables themselves (k1, k2, k3). However, you could express this more succinctly as:
doc.search('table > tr').each do |row|
properties = row.search('td/text()').collect {|text| text.to_s}
list.append Post.new(*properties)
end
This simply loops over each row and creates a Post using the textual content of each td in the row.

Resources