From abce15dd1a0e9f28b953179c4d9b6d27766685e8 Mon Sep 17 00:00:00 2001 From: Paolo Capriotti Date: Mon, 16 Mar 2009 18:59:09 +0100 Subject: [PATCH] More work on the connection class. --- .gitignore | 2 + lib/console.rb | 45 +++++++++++++ lib/games/chess/chess.rb | 1 + lib/ics/connection.rb | 168 ++++++++++++++++++++++++---------------------- lib/ics/driver.rb | 78 +++++++++++++++++++-- lib/ics/example/main.rb | 23 +++++++ lib/ics/example/window.rb | 28 ++++++++ lib/ics/protocol.rb | 7 +- lib/ics/style12.rb | 3 + lib/qtutils.rb | 18 ++++- 10 files changed, 280 insertions(+), 93 deletions(-) create mode 100644 lib/console.rb rewrite lib/ics/connection.rb (82%) create mode 100644 lib/ics/example/main.rb create mode 100644 lib/ics/example/window.rb diff --git a/.gitignore b/.gitignore index b25c15b..54e43cb 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ *~ +.#* +\#*# diff --git a/lib/console.rb b/lib/console.rb new file mode 100644 index 0000000..27fcbf9 --- /dev/null +++ b/lib/console.rb @@ -0,0 +1,45 @@ +require 'qtutils' + +class Console < Qt::Widget + include Observable + + def initialize(parent) + super + + layout = Qt::VBoxLayout.new + @output = Qt::TextEdit.new(self) + @input = Qt::LineEdit.new(self) + + layout.add_widget(@output) + layout.add_widget(@input) + setLayout layout + + @output.read_only = true + f = @output.font + f.family = 'monospace' + @output.font = f + @output.current_font = f + @bold_font = f + @bold_font.bold = true + + @input.on(:returnPressed) do + text = @input.text + with_font(@bold_font) do + @output.append text + end + @input.text = '' + fire :input => text + end + end + + def with_font(font) + old = @output.current_font + @output.current_font = font + yield + @output.current_font = old + end + + def append(text) + @output.append(text) + end +end diff --git a/lib/games/chess/chess.rb b/lib/games/chess/chess.rb index a2d5827..a67474f 100644 --- a/lib/games/chess/chess.rb +++ b/lib/games/chess/chess.rb @@ -21,6 +21,7 @@ Game.add :chess, Game.new( :piece => Piece, :players => [:white, :black]) + Game.add :chess5x5, Game.get(:chess).extend( :size => Point.new(5, 5)) diff --git a/lib/ics/connection.rb b/lib/ics/connection.rb dissimilarity index 82% index 49234dc..b65fbf8 100644 --- a/lib/ics/connection.rb +++ b/lib/ics/connection.rb @@ -1,81 +1,87 @@ -require 'socket' - -module ICS - -# -# A connection to an ICS server -# -class Connection - attr_accessor :debug - - def initialize(host, port, protocol) - @protocol = protocol - @create_socket = lambda do - puts "connecting to #{host}:#{port}" - TCPSocket.new(host, port) - end - - @state = :stopped - @stop_flag = false - @last_chunk = '' - @ignore_pending = false - @debug = false - end - - def start - @stop_flag = false - @socket = @create_socket[] - - Thread.new do - begin - loop do - break if @stop_flag - data = @socket.recv(1024) - break unless data - read_chunk data - end - - @state = :stopped - rescue Exception => e - puts "Connection thread died!!" - puts e - puts e.backtrace - end - end - end - - def stop - @stop_flag = true - end - - def send(data) - puts "> #{data}" if @debug - @socket.print(data + "\n\r") - end - - private - - def read_chunk(data) - return if data.empty? - chunks = data.split("\n\r", -1) # don't omit trailing empty fields - - i = if @ignore_pending - 1 - else - chunks[0] = @last_chunk + chunks[0] - 0 - end - chunks[i...-1].each do |c| - line = c.chomp - processed = @protocol.process line - puts "< #{line}" if @debug - end - if not chunks.last.empty? - @last_chunk = chunks.last - processed = @protocol.process_partial chunks.last - @last_chunk = '' if processed - end - end -end - -end +require 'qtutils' + +module ICS + +# +# A connection to an ICS server +# +class Connection < Qt::Object + attr_accessor :debug + + signals :hostFound, :established, + 'receivedLine(QString, int)', + 'receivedText(QString, int)' + + def initialize(host, port) + super nil + + @create_socket = lambda do + puts "connecting to #{host}:#{port}" + s = Qt::TcpSocket.new(self) + connect(s, SIGNAL(:hostFound), self, SIGNAL(:hostFound)) + s.connect(s, SIGNAL(:connected), self, SIGNAL(:established)) + s.on(:readyRead) { process_line } + s.connect_to_host(host, port) + s + end + end + + def process_line + puts "processing line" + unless @socket + puts "no socket!" + return + end + + while @socket.can_read_line + line = @socket.read_line.to_s + line = @buffer + line.gsub("\r", '') + emit receivedLine(line, @buffer.size) + @buffer = '' + end + + if (size = @socket.bytes_available) > 0 + data = @socket.read_all + offset = @buffer.size + @buffer += data.to_s.gsub("\r", '') + emit receivedText(@buffer, offset) + end + + end + + def start + @socket = @create_socket.call + @connected = true + @buffer = '' + end + + def stop + end + + def send_text(text) + puts "> #{text}" if @debug + unless @connected + @unsent_text += @text + "\n" + return + end + + unless @socket + puts "no socket!" + return + end + + process_line + os = Qt::TextStream(@socket) + os << text + "\n" + end + + def on_received_line(&blk) + connect(self, SIGNAL('receivedLine(QString, int)'), &blk) + end + + def on_received_text(&blk) + connect(self, SIGNAL('receivedText(QString, int)'), &blk) + end +end + +end diff --git a/lib/ics/driver.rb b/lib/ics/driver.rb index cf20298..61dcc25 100644 --- a/lib/ics/driver.rb +++ b/lib/ics/driver.rb @@ -1,19 +1,85 @@ $:.unshift(File.join(File.dirname(__FILE__), '..')) require 'qtutils' +require 'board/table' +require 'themes/loader' +require 'games/chess/chess' +require 'controller' +require 'history' require 'ics/connection' require 'ics/protocol' +require 'console' protocol = ICS::Protocol.new c = ICS::Connection.new('freechess.org', 5000, protocol) protocol.add_observer ICS::AuthModule.new(c, 'guest', '') protocol.add_observer ICS::StartupModule.new(c) -protocol.observe :text do |line| - puts line + +description = "KDE Board Game Suite" +version = "1.5" +about = KDE::AboutData.new("tagua", "Tagua", KDE.ki18n("Tagua"), + version, KDE.ki18n(description),KDE::AboutData::License_GPL,KDE.ki18n("(C) 2003 whoever the author is")) + +about.addAuthor(KDE.ki18n("author1"), KDE.ki18n("whatever they did"), "email@somedomain") +about.addAuthor(KDE.ki18n("author2"), KDE.ki18n("they did something else"), "another@email.address") + +KDE::CmdLineArgs.init(ARGV, about) + +app = KDE::Application.new + +class Scene < Qt::GraphicsScene + def initialize + super + end end -# c.debug = true -c.start -while line = gets - c.send line +theme_loader = ThemeLoader.new +theme = Struct.new(:pieces, :background).new +theme.pieces = theme_loader.get('Celtic') +theme.background = theme_loader.get('Default', Point.new(8, 8)) + +chess = Chess::Game.new + +scene = Qt::GraphicsScene.new + +state = chess.new_state +state.setup + +board = Board.new(scene, theme, chess, state) + + +table = Table.new(scene, board) +table.size = Qt::Size.new(500, 500) + +history = History.new(state) +controller = Controller.new(board, history) + +table.show + +console = Console.new(nil) +console.show + +protocol.observe :text do |text| + console.run_later { console.append(text) } +end + +console.observe :input do |text| + c.send(text) end +board.observe :new_move do |data| + move = data[:move] + m = ('a'[0] + move.src.x).chr + + (8 - move.src.y).to_s + + ('a'[0] + move.dst.x).chr + + (8 - move.dst.y).to_s + puts m + c.send m +end + +protocol.observe :style12 do |style12| + puts style12.inspect +end + +c.start + +app.exec diff --git a/lib/ics/example/main.rb b/lib/ics/example/main.rb new file mode 100644 index 0000000..549e0e8 --- /dev/null +++ b/lib/ics/example/main.rb @@ -0,0 +1,23 @@ +require 'qtutils' +require 'ics/connection' +require 'ics/example/window' + +description = "Connection example" +version = "0.1" +about = KDE::AboutData.new("connection", + "Connection Example", + KDE.ki18n("Connection Example"), + version, + KDE.ki18n(description), + KDE::AboutData::License_GPL, + KDE.ki18n("(C) 2009 Paolo Capriotti")) + +KDE::CmdLineArgs.init(ARGV, about) + +app = KDE::Application.new + +w = Window.new +w.show + +app.exec + diff --git a/lib/ics/example/window.rb b/lib/ics/example/window.rb new file mode 100644 index 0000000..631af76 --- /dev/null +++ b/lib/ics/example/window.rb @@ -0,0 +1,28 @@ +class Window < Qt::Widget + def initialize(parent = nil) + super parent + + quit = Qt::PushButton.new("Quit", self) + connect(quit, SIGNAL(:clicked), + self, SLOT(:close)) + + start_button = Qt::PushButton.new("Start", self) + start_button.on(:clicked) { start } + + layout = Qt::VBoxLayout.new + layout.add_widget start_button + layout.add_widget quit + set_layout layout + + @conn = ICS::Connection.new('freechess.org', 5000) + r = lambda do |text, off| + puts "received (#{off}): #{text}" + end + @conn.on_received_line(&r) + @conn.on_received_text(&r) + end + + def start + @conn.start + end +end diff --git a/lib/ics/protocol.rb b/lib/ics/protocol.rb index 1414af0..3d335c4 100644 --- a/lib/ics/protocol.rb +++ b/lib/ics/protocol.rb @@ -9,9 +9,9 @@ class Protocol @@actions = [] @@partial_actions = [] GAME_TYPES = { - :standard => :chess, - :blitz => :chess, - :lightning => :chess } + 'standard' => :chess, + 'blitz' => :chess, + 'lightning' => :chess } def self.on(regex, type = :full, &blk) # ugly hack to work around the missing @@ -161,7 +161,6 @@ class StartupModule def on_prompt if not @startup - puts "starting up!" @connection.send("alias $ @"); @connection.send("iset startpos 1"); @connection.send("iset ms 1"); diff --git a/lib/ics/style12.rb b/lib/ics/style12.rb index 78ac99c..6f3521e 100644 --- a/lib/ics/style12.rb +++ b/lib/ics/style12.rb @@ -1,4 +1,5 @@ require 'games/games' +require 'ics/icsapi' module ICS @@ -63,11 +64,13 @@ class Style12 def self.from_match(match, games) game_number = match[GAME_NUMBER].to_i current_game = games[game_number] + puts "current_game = #{current_game.inspect}" game = if current_game current_game[:game] else Game.dummy end + puts "game = #{game}" icsapi = ICSApi.new(game) state = diff --git a/lib/qtutils.rb b/lib/qtutils.rb index d7edaa0..6e279c5 100644 --- a/lib/qtutils.rb +++ b/lib/qtutils.rb @@ -106,9 +106,17 @@ class Qt::Pixmap end end -class Qt::Object +class Qt::Base def on(sign, &blk) - connect(SIGNAL(sign.to_s + '()', &blk)) + connect(SIGNAL(sign.to_s + '()'), &blk) + end + + def in(interval, &blk) + Qt::Timer.in(interval, self, &blk) + end + + def run_later(&blk) + self.in(0, &blk) end end @@ -125,4 +133,10 @@ class Qt::Timer # that it is not garbage collected timer end + + def self.in(interval, target = nil, &blk) + single_shot(interval, + Qt::BlockInvocation.new(target, blk, 'invoke()'), + SLOT('invoke()')) + end end -- 2.11.4.GIT