1 #include <wx/intl.h>
2 #include <wx/stattext.h>
3 #include <wx/statline.h>
4 #include <wx/textdlg.h>
5 #include <wx/combobox.h>
6 #include <wx/button.h>
7 #include <wx/sizer.h>
8 #include <wx/checkbox.h>
9 #include <wx/filename.h>
10 #include <wx/log.h>
11 #if wxUSE_TOGGLEBTN
12 #include <wx/tglbtn.h>
13 #endif
14
15 #include "playbacklistctrl.h"
16 #include "replaylist.h"
17 #include "playbackthread.h"
18 #include "ui.h"
19 #include "chatpanel.h"
20 #include "uiutils.h"
21 #include "settings.h"
22 #include "mapctrl.h"
23 #include "playbackfilter.h"
24 #include "iconimagelist.h"
25
26 #include "utils/customdialogs.h"
27 #include "utils/debug.h"
28 #include "hosting/battleroomlistctrl.h"
29
30
BEGIN_EVENT_TABLE_TEMPLATE1(PlaybackTab,wxPanel,PlaybackTraits)31 BEGIN_EVENT_TABLE_TEMPLATE1( PlaybackTab, wxPanel, PlaybackTraits )
32
33 EVT_BUTTON ( PLAYBACK_WATCH , PlaybackTab::OnWatch )
34 EVT_BUTTON ( PLAYBACK_RELOAD , PlaybackTab::OnReload )
35 EVT_BUTTON ( PLAYBACK_DELETE , PlaybackTab::OnDelete )
36 EVT_LIST_ITEM_SELECTED ( RLIST_LIST , PlaybackTab::OnSelect )
37 // this doesn't get triggered (?)
38 EVT_LIST_ITEM_DESELECTED( wxID_ANY , PlaybackTab::OnDeselect )
39 EVT_CHECKBOX ( PLAYBACK_LIST_FILTER_ACTIV , PlaybackTab::OnFilterActiv )
40 EVT_COMMAND ( wxID_ANY, PlaybacksLoadedEvt , PlaybackTab::AddAllPlaybacks )
41 #if wxUSE_TOGGLEBTN
42 EVT_TOGGLEBUTTON ( PLAYBACK_LIST_FILTER_BUTTON , PlaybackTab::OnFilter )
43 #else
44 EVT_CHECKBOX ( PLAYBACK_LIST_FILTER_BUTTON , PlaybackTab::OnFilter )
45 #endif
46
47 END_EVENT_TABLE()
48
49 template < class PlaybackTraits >
50 PlaybackTab<PlaybackTraits>::PlaybackTab( wxWindow* parent ):
51 wxScrolledWindow( parent, -1 ),
52 m_replay_loader ( 0 )
53 {
54 wxLogMessage( _T( "PlaybackTab::PlaybackTab()" ) );
55
56 m_replay_loader = new LoaderType( this );
57
58 wxBoxSizer* m_main_sizer;
59 m_main_sizer = new wxBoxSizer( wxVERTICAL );
60
61 wxBoxSizer* m_filter_sizer;
62 m_filter_sizer = new wxBoxSizer( wxVERTICAL );
63
64 wxBoxSizer* m_replaylist_sizer;
65 m_replaylist_sizer = new wxBoxSizer( wxVERTICAL );
66
67 m_replay_listctrl = new ListCtrlType( this );
68 m_replaylist_sizer->Add( m_replay_listctrl, 1, wxEXPAND);
69
70 m_main_sizer->Add( m_replaylist_sizer, 1, wxEXPAND);;
71
72 wxBoxSizer* m_info_sizer;
73 m_info_sizer = new wxBoxSizer( wxHORIZONTAL );
74
75 m_minimap = new MapCtrl( this, 100, 0, true, true, false, false );
76 m_info_sizer->Add( m_minimap, 0, wxALL, 5 );
77
78 wxFlexGridSizer* m_data_sizer;
79 m_data_sizer = new wxFlexGridSizer( 4, 2, 0, 0 );
80
81 m_map_lbl = new wxStaticText( this, wxID_ANY, _( "Map:" ), wxDefaultPosition, wxDefaultSize, 0 );
82 m_data_sizer->Add( m_map_lbl, 1, wxALL | wxEXPAND, 5 );
83
84 m_map_text = new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
85 m_data_sizer->Add( m_map_text, 1, wxALL | wxEXPAND, 5 );
86
87 m_mod_lbl = new wxStaticText( this, wxID_ANY, _( "Game:" ), wxDefaultPosition, wxDefaultSize, 0 );
88 m_data_sizer->Add( m_mod_lbl, 1, wxALL | wxEXPAND, 5 );
89
90 m_mod_text = new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
91 m_data_sizer->Add( m_mod_text, 1, wxALL | wxEXPAND, 5 );
92
93 m_players_lbl = new wxStaticText( this, wxID_ANY, _( "Players:" ), wxDefaultPosition, wxDefaultSize, 0 );
94 m_data_sizer->Add( m_players_lbl, 1, wxALL | wxEXPAND, 5 );
95
96 m_players_text = new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
97 m_data_sizer->Add( m_players_text, 1, wxALL | wxEXPAND, 5 );
98
99 m_info_sizer->Add( m_data_sizer, 1, wxEXPAND | wxALL, 0 );
100
101 m_players = new BattleroomListCtrl( this, 0, true, false );
102 m_info_sizer->Add( m_players , 2, wxALL | wxEXPAND, 0 );
103
104 m_main_sizer->Add( m_info_sizer, 0, wxEXPAND, 5 );
105
106
107 m_filter = new PlaybackListFilter<ThisType>( this , wxID_ANY, this , wxDefaultPosition, wxSize( -1, -1 ), wxEXPAND );
108 m_filter_sizer->Add( m_filter, 0, wxEXPAND, 5 );
109
110 m_main_sizer->Add( m_filter_sizer, 0, wxEXPAND, 5 );
111
112 m_buttons_sep = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
113 m_main_sizer->Add( m_buttons_sep, 0, wxALL | wxEXPAND, 5 );
114
115 wxBoxSizer* m_buttons_sizer;
116 m_buttons_sizer = new wxBoxSizer( wxHORIZONTAL );
117
118 #if wxUSE_TOGGLEBTN
119 m_filter_show = new wxToggleButton( this, PLAYBACK_LIST_FILTER_BUTTON , wxT( " Filter " ), wxDefaultPosition , wxSize( -1, 28 ), 0 );
120 #else
121 m_filter_show = new wxCheckBox( this, PLAYBACK_LIST_FILTER_BUTTON , wxT( " Filter " ), wxDefaultPosition , wxSize( -1, 28 ), 0 );
122 #endif
123
124 m_buttons_sizer->Add( m_filter_show, 0, 0, 5 );
125
126 m_filter_activ = new wxCheckBox( this, PLAYBACK_LIST_FILTER_ACTIV , wxT( "Activated" ), wxDefaultPosition, wxDefaultSize, 0 );
127 m_buttons_sizer->Add( m_filter_activ, 1, wxALL | wxEXPAND, 5 );
128
129 m_buttons_sizer->Add( 0, 0, 1, wxEXPAND, 0 );
130
131 m_watch_btn = new wxButton( this, PLAYBACK_WATCH, PlaybackTraits::IsReplayType ? _( "Watch" ) : _( "Load" ), wxDefaultPosition, wxSize( -1, 28 ), 0 );
132 m_buttons_sizer->Add( m_watch_btn, 0, wxBOTTOM | wxLEFT | wxRIGHT, 5 );
133
134 m_delete_btn = new wxButton( this, PLAYBACK_DELETE, _( "Delete" ), wxDefaultPosition, wxSize( -1, 28 ), 0 );
135 m_buttons_sizer->Add( m_delete_btn, 0, wxBOTTOM | wxRIGHT, 5 );
136
137 m_reload_btn = new wxButton( this, PLAYBACK_RELOAD, _( "Reload list" ), wxDefaultPosition, wxSize( -1, 28 ), 0 );
138 m_buttons_sizer->Add( m_reload_btn, 0, wxBOTTOM | wxRIGHT, 5 );
139
140 m_main_sizer->Add( m_buttons_sizer, 0, wxEXPAND, 5 );
141
142 m_filter->Hide();
143
144 SetSizer( m_main_sizer );
145
146 ReloadList();
147
148 //none selected --> shouldn't watch/delete that
149 Deselect();
150
151 SetScrollRate( SCROLL_RATE, SCROLL_RATE );
152 Layout();
153 ConnectGlobalEvent(this, GlobalEvent::OnUnitsyncReloaded, wxObjectEventFunction(&PlaybackTab::OnUnitsyncReloaded));
154 ConnectGlobalEvent(this, GlobalEvent::OnSpringTerminated, wxObjectEventFunction(&PlaybackTab::OnSpringTerminated));
155 }
156
157 template < class PlaybackTraits >
~PlaybackTab()158 PlaybackTab<PlaybackTraits>::~PlaybackTab()
159 {
160 m_minimap->SetBattle( NULL );
161 if ( m_filter != 0 )
162 m_filter->SaveFilterValues();
163
164 wxLogDebugFunc( wxEmptyString );
165 }
166
167 template < class PlaybackTraits >
AddAllPlaybacks(wxCommandEvent &)168 void PlaybackTab<PlaybackTraits>::AddAllPlaybacks( wxCommandEvent& /*unused*/ )
169 {
170 assert(wxThread::IsMain());
171 const typename ListType::playback_map_t& replays =
172 playbacklist<ListType>().GetPlaybacksMap();
173
174 for ( typename ListType::playback_const_iter_t i = replays.begin();i != replays.end();++i ) {
175 AddPlayback( i->second );
176 }
177 m_replay_listctrl->SortList( true );
178 }
179
180 template < class PlaybackTraits >
AddPlayback(const PlaybackType & replay)181 void PlaybackTab<PlaybackTraits>::AddPlayback( const PlaybackType& replay ) {
182
183 if ( m_filter->GetActiv() && !m_filter->FilterPlayback( replay ) ) {
184 return;
185 }
186
187 m_replay_listctrl->AddPlayback( replay );
188 }
189
190 template < class PlaybackTraits >
RemovePlayback(const PlaybackType & replay)191 void PlaybackTab<PlaybackTraits>::RemovePlayback( const PlaybackType& replay )
192 {
193 int index = m_replay_listctrl->GetIndexFromData( &replay );
194
195 if ( index == -1 )
196 return;
197
198 if ( index == m_replay_listctrl->GetSelectedIndex() )
199 Deselect();
200
201 m_replay_listctrl->RemovePlayback( replay );
202 }
203
204 template < class PlaybackTraits >
RemovePlayback(const int index)205 void PlaybackTab<PlaybackTraits>::RemovePlayback( const int index )
206 {
207 if ( index == -1 )
208 return;
209
210 if ( index == m_replay_listctrl->GetSelectedIndex() )
211 Deselect();
212
213 m_replay_listctrl->RemovePlayback( index );
214 }
215
216 template < class PlaybackTraits >
UpdatePlayback(const PlaybackType & replay)217 void PlaybackTab<PlaybackTraits>::UpdatePlayback( const PlaybackType& replay )
218 {
219 if ( m_filter->GetActiv() && !m_filter->FilterPlayback( replay ) ) {
220 RemovePlayback( replay );
221 return;
222 }
223
224 int index = m_replay_listctrl->GetIndexFromData( &replay );
225
226 if ( index != -1 )
227 m_replay_listctrl->RefreshItem( index );
228 else
229 AddPlayback( replay );
230
231 }
232
233 template < class PlaybackTraits >
RemoveAllPlaybacks()234 void PlaybackTab<PlaybackTraits>::RemoveAllPlaybacks()
235 {
236 m_replay_listctrl->Clear();
237 //shouldn't list be cleared too here? (koshi)
238 }
239
240
241 template < class PlaybackTraits >
UpdateList()242 void PlaybackTab<PlaybackTraits>::UpdateList()
243 {
244 const typename ListType::playback_map_t& replays =
245 playbacklist<ListType>().GetPlaybacksMap();
246
247 for ( typename ListType::playback_const_iter_t i = replays.begin(); i != replays.end(); ++i ) {
248 UpdatePlayback( i->second );
249 }
250 m_replay_listctrl->RefreshVisibleItems();
251 }
252
253
254 template < class PlaybackTraits >
SetFilterActiv(bool activ)255 void PlaybackTab<PlaybackTraits>::SetFilterActiv( bool activ )
256 {
257 m_filter->SetActiv( activ );
258 m_filter_activ->SetValue( activ );
259 }
260
261 template < class PlaybackTraits >
OnFilter(wxCommandEvent &)262 void PlaybackTab<PlaybackTraits>::OnFilter( wxCommandEvent& /*unused*/ )
263 {
264 if ( m_filter_show->GetValue() ) {
265 m_filter->Show( );
266 this->Layout();
267 }
268 else {
269 m_filter->Hide( );
270 this->Layout();
271 }
272 }
273
274 template < class PlaybackTraits >
OnWatch(wxCommandEvent &)275 void PlaybackTab<PlaybackTraits>::OnWatch( wxCommandEvent& /*unused*/ )
276 {
277 if ( m_replay_listctrl->GetSelectedIndex() != -1 ) {
278 int m_sel_replay_id = m_replay_listctrl->GetSelectedData()->id;
279
280 wxString type = PlaybackTraits::IsReplayType ? _( "replay" ) : _( "savegame" ) ;
281 wxLogMessage( _T( "Watching %s %d " ), type.c_str(), m_sel_replay_id );
282 try {
283 PlaybackType& rep = playbacklist<ListType>().GetPlaybackById( m_sel_replay_id );
284
285 bool versionfound = ui().IsSpringCompatible(_T("spring"), rep.SpringVersion);
286 if ( !ReplayTraits::IsReplayType )
287 versionfound = true; // quick hack to bypass spring version check
288 if ( !versionfound ) {
289 wxString message = wxFormat( _( "No compatible installed spring version has been found, this %s requires version: %s\n" ) ) % type% rep.SpringVersion;
290 customMessageBox( SL_MAIN_ICON, message, _( "Spring error" ), wxICON_EXCLAMATION | wxOK );
291 wxLogWarning ( _T( "no spring version supported by this replay found" ) );
292 AskForceWatch( rep );
293 return;
294 }
295 rep.battle.GetMe().SetNick(sett().GetDefaultNick());
296 bool watchable = rep.battle.MapExists() && rep.battle.ModExists();
297 if ( watchable )
298 rep.battle.StartSpring();
299 else {
300 wxString downloadProc = _( "Should i try to download it for you?\nYou can see the progress in the \"Download Manager\" tab." );
301 OfflineBattle& battle = rep.battle;
302
303 if ( !battle.ModExists() ) {
304 if ( customMessageBox( SL_MAIN_ICON, _( "You need to download the game before you can watch this replay.\n\n" ) + downloadProc, _( "Game not available" ), wxYES_NO | wxICON_QUESTION ) == wxYES ) {
305 wxString modhash = battle.GetHostModHash();
306 wxString modname = battle.GetHostModName();
307 ui().Download (_T("game"), modname, modhash);
308 }
309 else {
310 AskForceWatch( rep );
311 }
312 return;
313 }
314
315 if ( !battle.MapExists() ) {
316 if ( customMessageBox( SL_MAIN_ICON, _( " I couldn't find the map to be able to watch this replay\nThis can be caused by tasclient writing broken map hash value\nIf you're sure you have the map, press no\nYou need to download the map to be able to watch this replay.\n\n" ) + downloadProc, _( "Map not available" ), wxYES_NO | wxICON_QUESTION ) == wxYES ) {
317 wxString maphash = battle.GetHostMapHash();
318 wxString mapname = battle.GetHostMapName();
319 ui().Download ( _T("map"), mapname, maphash );
320 }
321 else {
322 AskForceWatch( rep );
323 }
324 }
325 }
326 } catch ( std::runtime_error ) {
327 return;
328 }
329 } else {
330 Deselected();
331 }
332 }
333
334 template < class PlaybackTraits >
AskForceWatch(typename PlaybackTab<PlaybackTraits>::PlaybackType & rep) const335 void PlaybackTab<PlaybackTraits>::AskForceWatch( typename PlaybackTab<PlaybackTraits>::PlaybackType& rep ) const
336 {
337 if ( customMessageBox( SL_MAIN_ICON, _( "I don't think you will be able to watch this replay.\nTry anyways? (MIGHT CRASH!)" ) , _( "Invalid replay" ), wxYES_NO | wxICON_QUESTION ) == wxYES ) {
338 rep.battle.StartSpring();
339 }
340 }
341
342 template < class PlaybackTraits >
OnDelete(wxCommandEvent &)343 void PlaybackTab<PlaybackTraits>::OnDelete( wxCommandEvent& /*unused*/ )
344 {
345 int sel_index = m_replay_listctrl->GetSelectedIndex();
346 if ( sel_index >= 0 ) {
347 try {
348 const PlaybackType& rep = *m_replay_listctrl->GetSelectedData();
349 int m_sel_replay_id = rep.id;
350 int index = m_replay_listctrl->GetIndexFromData( &rep );
351 wxLogMessage( _T( "Deleting replay %d " ), m_sel_replay_id );
352 wxString fn = rep.Filename;
353 if ( !playbacklist<ListType>().DeletePlayback( m_sel_replay_id ) )
354 customMessageBoxNoModal( SL_MAIN_ICON, _( "Could not delete Replay: " ) + fn,
355 _( "Error" ) );
356 else {
357 RemovePlayback( index ); // Deselect is called in there too
358 }
359 } catch ( std::runtime_error ) {
360 return;
361 }
362 } else {
363 Deselected();
364 }
365 }
366
367 template < class PlaybackTraits >
OnFilterActiv(wxCommandEvent &)368 void PlaybackTab<PlaybackTraits>::OnFilterActiv( wxCommandEvent& /*unused*/ )
369 {
370 m_filter->SetActiv( m_filter_activ->GetValue() );
371 }
372
373 template < class PlaybackTraits >
OnSelect(wxListEvent & event)374 void PlaybackTab<PlaybackTraits>::OnSelect( wxListEvent& event )
375 {
376 wxLogDebugFunc( wxEmptyString );
377 if ( event.GetIndex() == -1 ) {
378 Deselect();
379 }
380 else
381 {
382 try
383 {
384 m_watch_btn->Enable( true );
385 m_delete_btn->Enable( true );
386 int index = event.GetIndex();
387 m_replay_listctrl->SetSelectedIndex( index );
388
389 //this might seem a bit backwards, but it's currently the only way that doesn't involve casting away constness
390 int m_sel_replay_id = m_replay_listctrl->GetDataFromIndex( index )->id;
391 PlaybackType& rep = playbacklist<ListType>().GetPlaybackById( m_sel_replay_id );
392
393
394 wxLogMessage( _T( "Selected replay %d " ), m_sel_replay_id );
395
396 m_players_text->SetLabel( wxEmptyString );
397 m_map_text->SetLabel( rep.battle.GetHostMapName() );
398 m_mod_text->SetLabel( rep.battle.GetHostModName() );
399 m_minimap->SetBattle( &( rep.battle ) );
400 m_minimap->UpdateMinimap();
401
402 m_players->Clear();
403 m_players->SetBattle( ( IBattle* )&rep.battle );
404 for ( size_t i = 0; i < rep.battle.GetNumUsers(); ++i ) {
405 try {
406 User& usr = rep.battle.GetUser( i );
407 m_players->AddUser( usr );
408 }
409 catch ( ... )
410 {}
411 }
412 }
413 catch ( ... ) {
414 Deselect();
415 }
416 event.Skip();
417 }
418 }
419
420 template < class PlaybackTraits >
OnDeselect(wxListEvent &)421 void PlaybackTab<PlaybackTraits>::OnDeselect( wxListEvent& /*unused*/ )
422 {
423 Deselected();
424 }
425
426 template < class PlaybackTraits >
Deselect()427 void PlaybackTab<PlaybackTraits>::Deselect()
428 {
429 m_replay_listctrl->SelectNone();
430 Deselected();
431 }
432
433 template < class PlaybackTraits >
Deselected()434 void PlaybackTab<PlaybackTraits>::Deselected()
435 {
436 m_watch_btn->Enable( false );
437 m_delete_btn->Enable( false );
438 m_players_text->SetLabel( wxEmptyString );
439 m_map_text->SetLabel( wxEmptyString );
440 m_mod_text->SetLabel( wxEmptyString );
441 m_minimap->SetBattle( NULL );
442 m_minimap->UpdateMinimap();
443 m_minimap->Refresh();
444 m_players->Clear();
445 m_players->SetBattle( NULL );
446 }
447
448 template < class PlaybackTraits >
ReloadList()449 void PlaybackTab<PlaybackTraits>::ReloadList()
450 {
451 Deselect();
452 m_replay_listctrl->Clear();
453 m_replay_loader->Run();
454 }
455
456 template < class PlaybackTraits >
OnReload(wxCommandEvent &)457 void PlaybackTab<PlaybackTraits>::OnReload( wxCommandEvent& /*unused*/ )
458 {
459 ReloadList();
460 }
461
462 template < class PlaybackTraits >
OnSpringTerminated(wxCommandEvent &)463 void PlaybackTab<PlaybackTraits>::OnSpringTerminated( wxCommandEvent& /*data*/ )
464 {
465 ReloadList();
466 }
467
468 template < class PlaybackTraits >
OnUnitsyncReloaded(wxCommandEvent &)469 void PlaybackTab<PlaybackTraits>::OnUnitsyncReloaded( wxCommandEvent& /*data*/ )
470 {
471 ReloadList();
472 }
473