1 # Copyright (c) 2009 Paolo Capriotti <p.capriotti@gmail.com>
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
13 require 'interaction/history'
15 require 'dummy_player'
17 require 'interaction/match'
23 require 'engine_prefs'
30 class MainWindow < KDE::XmlGuiWindow
37 def initialize(loader, game)
41 @theme_loader = @loader.get_matching(:theme_loader).new
43 @factories = Hash.new do |h, interface|
44 @loader.get_matching(interface)
46 @factories[:table] = Factory.new do |parent|
47 Table.new(Scene.new, @loader, @theme_loader, parent)
49 @factories[:controller] = Factory.new do |parent|
50 Controller.new(parent, @field).tap do |c|
51 c.on(:changed_active_actions) do
52 update_active_actions(c)
61 new_game(Match.new(game), :new_tab => false)
67 controller.match.close
73 @view.current.controller
80 regular_action(:open_new,
81 :icon => 'document-new',
82 :text => KDE::i18n("&New..."),
83 :shortcut => KDE::std_shortcut(:new),
84 :tooltip => KDE::i18n("Start a new game...")) do
89 :icon => 'document-open',
90 :text => KDE::i18n("&Load..."),
91 :shortcut => KDE::std_shortcut(:open),
92 :tooltip => KDE::i18n("Open a saved game...")) do
97 :icon => 'application-exit',
98 :text => KDE::i18n("&Quit"),
99 :shortcut => KDE::std_shortcut(:quit),
100 :tooltip => KDE::i18n("Quit the program")) do
104 regular_action(:save,
105 :icon => 'document-save',
106 :text => KDE::i18n("&Save"),
107 :shortcut => KDE::std_shortcut(:save),
108 :tooltip => KDE::i18n("Save the current game")) do
112 regular_action(:save_as,
113 :icon => 'document-save-as',
114 :text => KDE::i18n("Save &As..."),
115 :tooltip => KDE::i18n("Save the current game to another file")) do
119 @actions[:back] = regular_action :back, :icon => 'go-previous',
120 :text => KDE.i18n("B&ack") do
123 @actions[:forward] = regular_action :forward, :icon => 'go-next',
124 :text => KDE.i18n("&Forward") do
128 regular_action :flip, :icon => 'object-rotate-left',
129 :text => KDE.i18n("F&lip") do
130 table = @view.current.table
131 table.flip(!table.flipped?)
134 regular_action :configure_engines,
135 :icon => 'help-hint',
136 :text => KDE.i18n("Configure &Engines...") do
137 dialog = EnginePrefs.new(@engine_loader, self)
141 regular_action :configure_themes,
142 :icon => 'games-config-theme',
143 :text => KDE.i18n("Configure &Themes...") do
144 dialog = ThemePrefs.new(@loader, @theme_loader, self)
145 dialog.on(:ok) { controller.reset }
149 @actions[:undo] = regular_action(:undo,
150 :icon => 'edit-undo',
151 :text => KDE::i18n("Und&o"),
152 :shortcut => KDE::std_shortcut(:undo),
153 :tooltip => KDE::i18n("Undo the last history operation")) do
157 @actions[:redo] = regular_action(:redo,
158 :icon => 'edit-redo',
159 :text => KDE::i18n("Re&do"),
160 :shortcut => KDE::std_shortcut(:redo),
161 :tooltip => KDE::i18n("Redo the last history operation")) do
166 def load_action_providers
167 @loader.get_all_matching(:action_provider).each do |provider_klass|
168 provider = provider_klass.new
169 ActionProviderClient.new(self, provider)
174 @field = AnimationField.new(20)
176 movelist_stack = Qt::StackedWidget.new(self)
177 movelist_dock = Qt::DockWidget.new(self)
178 movelist_dock.widget = movelist_stack
179 movelist_dock.window_title = KDE.i18n("History")
180 movelist_dock.object_name = "movelist"
181 add_dock_widget(Qt::LeftDockWidgetArea, movelist_dock, Qt::Vertical)
183 action_collection[:toggle_history] = movelist_dock.toggle_view_action
185 @view = MultiView.new(self, movelist_stack, @factories)
186 @view.create(:name => game.class.plugin_name)
187 @view.on(:changed) { update_active_actions(controller) }
188 @view.on(:changed) { update_title }
193 @engine_loader = @loader.get_matching(:engine_loader).new
194 @engine_loader.reload
196 @console = Console.new(nil)
197 console_dock = Qt::DockWidget.new(self)
198 console_dock.widget = @console
199 console_dock.focus_proxy = @console
200 console_dock.window_title = KDE.i18n("Console")
201 console_dock.object_name = "console"
202 add_dock_widget(Qt::BottomDockWidgetArea, console_dock, Qt::Horizontal)
203 console_dock.window_flags = console_dock.window_flags & ~Qt::WindowStaysOnTopHint
205 action_collection[:toggle_console] = console_dock.toggle_view_action
207 self.central_widget = @view
210 def new_game(match, opts = { })
211 setup_single_player(match)
212 controller.reset(match)
215 def setup_single_player(match)
216 controller.color = match.game.players.first
217 controller.premove = false
218 opponents = match.game.players[1..-1].map do |color|
219 DummyPlayer.new(color)
221 opponents.each do |p|
222 controller.add_controlled_player(p)
225 controller.controlled.values.each do |p|
228 controller.controlled.values.each do |p|
233 def create_game(opts = { })
234 current_game = if controller.match
235 controller.match.game
237 diag = NewGame.new(self, @engine_loader, current_game)
238 diag.on(:ok) do |data|
240 match = Match.new(game, :editable => data[:engines].empty?)
242 @view.create(:activate => true,
244 :name => game.class.plugin_name)
246 @view.set_tab_text(@view.index, game.class.plugin_name)
252 match.on(:started) do
256 # set up engine players
257 players = game.players
258 data[:engines].each do |player, engine|
259 e = engine.new(player, match)
263 # set up human players
264 if data[:humans].empty?
267 contr.color = data[:humans].first
268 contr.premove = data[:humans].size == 1
269 match.register(contr)
271 data[:humans][1..-1].each do |player|
272 p = DummyPlayer.new(player)
273 contr.add_controlled_player(p)
277 contr.controlled.values.each {|p| match.start(p) }
283 url = KDE::FileDialog.get_open_url(KDE::Url.new, '*.*', self,
284 KDE.i18n("Open game"))
286 return if url.is_empty or (not url.path)
288 puts "url = #{url.inspect}"
290 ext = File.extname(url.path)[1..-1]
292 readers = Game.to_enum.find_all do |_, game|
293 game.respond_to?(:game_extensions) and
294 game.game_extensions.include?(ext)
296 [game, game.game_reader]
300 warn "Unknown file extension #{ext}"
304 tmp_file = KDE::download_tempfile(url, self)
305 return unless tmp_file
311 readers.each do |g, reader|
313 data = File.open(tmp_file) do |f|
317 history = reader.read(data, i)
321 rescue ParseException
326 warn "Could not load file #{url.path}"
331 match = Match.new(game)
332 @view.create(:activate => true,
333 :name => game.class.plugin_name)
334 setup_single_player(match)
335 match.history = history
338 controller.reset(match)
342 match = controller.match
344 pattern = if match.game.respond_to?(:game_extensions)
345 match.game.game_extensions.map{|ext| "*.#{ext}"}.join(' ')
349 url = KDE::FileDialog.get_save_url(
350 KDE::Url.new, pattern, self, KDE.i18n("Save game"))
351 match.url = write_game(url)
356 match = controller.match
366 def write_game(url = nil)
367 return if url.is_empty or (not url.path)
369 match = controller.match
372 writer = match.game.game_writer
374 info[:players] = info[:players].inject({}) do |res, pl|
375 res[pl.color] = pl.name
378 result = writer.write(info, match.history)
379 write_file(url, result)
383 def update_game_actions(match)
384 unplug_action_list('game_actions')
385 actions = if match.game.respond_to?(:actions)
386 match.game.actions(self, action_collection, controller.policy)
390 plug_action_list('game_actions', actions)
394 self.caption = @view.current_name
397 def update_active_actions(contr)
398 if contr == controller
399 contr.active_actions.each do |id, enabled|
400 action = @actions[id]
402 action.enabled = enabled