diff --git a/wx/Makefile.am b/wx/Makefile.am index 6f60f25bb..0f627a284 100644 --- a/wx/Makefile.am +++ b/wx/Makefile.am @@ -5,8 +5,10 @@ SUBDIRS = images bin_PROGRAMS = Xmission Xmission_SOURCES = \ - xmission.cc \ + speed-stats.cc \ torrent-filter.cc \ - torrent-list.cc + torrent-list.cc \ + torrent-stats.cc \ + xmission.cc Xmission_LDADD = ../libtransmission/libtransmission.a @WX_LIBS@ $(PTHREAD_LIBS) -lm diff --git a/wx/foreach.h b/wx/foreach.h new file mode 100644 index 000000000..680b84df4 --- /dev/null +++ b/wx/foreach.h @@ -0,0 +1,24 @@ +#ifndef _Foreach_h_ +#define _Foreach_h_ + +#define foreach(Type,var,itname) \ + for (Type::iterator itname(var.begin()), \ + itname##end(var.end()); itname!=itname##end; \ + ++itname) + +#define foreach_const(Type,var,itname) \ + for (Type::const_iterator itname(var.begin()), \ + itname##end(var.end()); itname!=itname##end; \ + ++itname) + +#define foreach_r(Type,var,itname) \ + for (Type::reverse_iterator itname(var.rbegin()), \ + itname##end(var.rend()); itname!=itname##end; \ + ++itname) + +#define foreach_const_r(Type,var,itname) \ + for (Type::const_reverse_iterator itname(var.rbegin()), \ + itname##end(var.rend()); itname!=itname##end; \ + ++itname) + +#endif diff --git a/wx/speed-stats.cc b/wx/speed-stats.cc new file mode 100644 index 000000000..d4e7d69c9 --- /dev/null +++ b/wx/speed-stats.cc @@ -0,0 +1,53 @@ +/* + * This file Copyright (C) 2007 Charles Kerr + * + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2(b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + */ + +#include +#include +#include +#include +#include "speed-stats.h" + +BEGIN_EVENT_TABLE( SpeedStats, wxPanel ) + EVT_PAINT( SpeedStats::OnPaint ) +END_EVENT_TABLE() + +SpeedStats :: SpeedStats( wxWindow * parent, + wxWindowID id, + const wxPoint & pos, + const wxSize & size, + long style, + const wxString & name ): + wxPanel( parent, id, pos, size, style, name ) +{ +} + +void +SpeedStats :: Update( tr_handle_t * WXUNUSED(handle) ) +{ +} + +void +SpeedStats :: OnPaint( wxPaintEvent& WXUNUSED(event) ) +{ +#if 0 + int w, h; + mySpeedPanel->GetSize( &w, &h ); + wxMemoryDC dc; + wxBitmap bitmap( w, h ); + dc.SelectObject( bitmap ); + + wxColour backgroundColor = *wxBLACK; + dc.SetBrush( wxBrush( backgroundColor ) ); + dc.SetPen( wxBrush( backgroundColor ) ); + dc.DrawRectangle( 0, 0, w, h ); + + std::cerr << "paint" << std::endl; +#endif +} diff --git a/wx/speed-stats.h b/wx/speed-stats.h new file mode 100644 index 000000000..aeaed01fa --- /dev/null +++ b/wx/speed-stats.h @@ -0,0 +1,41 @@ +/* + * This file Copyright (C) 2007 Charles Kerr + * + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2(b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + */ + +#ifndef __XMISSION_SPEED_STATS_H__ +#define __XMISSION_SPEED_STATS_H__ + +#include +#include + +class SpeedStats: public wxPanel +{ + public: + + SpeedStats( wxWindow * parent, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTAB_TRAVERSAL, + const wxString& name = _T("panel")); + + virtual ~SpeedStats() {} + + void Update( tr_handle_t * handle ); + + public: + + void OnPaint( wxPaintEvent& ); + + private: + + DECLARE_EVENT_TABLE() +}; + +#endif diff --git a/wx/torrent-list.cc b/wx/torrent-list.cc index 0d9914550..81affba5a 100644 --- a/wx/torrent-list.cc +++ b/wx/torrent-list.cc @@ -19,7 +19,7 @@ namespace enum { COL_POSITION, - COL_DONE, + COL_PERCENT_DONE, COL_DOWNLOAD_SPEED, COL_ETA, COL_HASH, @@ -67,7 +67,7 @@ namespace if( columns.empty() ) { columns[_T("position")] = COL_POSITION; - columns[_T("done")] = COL_DONE; + columns[_T("done")] = COL_PERCENT_DONE; columns[_T("download-speed")] = COL_DOWNLOAD_SPEED; columns[_T("eta")] = COL_ETA; columns[_T("hash")] = COL_HASH; @@ -132,7 +132,8 @@ namespace { int i; static const char *sizestrs[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" }; - for ( i=0; size>>10; ++i ) size = size>>10; + for ( i=0; size>>10; ++i ) + size = size >> 10; char buf[512]; snprintf( buf, sizeof(buf), "%.*f %s", bestDecimal(size), (double)size, sizestrs[i] ); return toWxStr( buf ); @@ -143,9 +144,9 @@ namespace return getReadableSize( (uint64_t)f ); } - wxString getReadableSpeed( float f ) + wxString getReadableSpeed( float kib_sec ) { - wxString xstr = getReadableSize(f); + wxString xstr = getReadableSize(1024*kib_sec); xstr += _T("/s"); return xstr; } @@ -175,7 +176,7 @@ TorrentListCtrl :: TorrentListCtrl( tr_handle_t * handle, wxWindow * parent, const wxPoint & pos, const wxSize & size): - wxListCtrl( parent, TORRENT_LIST_CTRL, pos, size, wxLC_REPORT ), + wxListCtrl( parent, TORRENT_LIST_CTRL, pos, size, wxLC_REPORT|wxLC_HRULES ), myHandle( handle ), myConfig( config ) { @@ -216,12 +217,12 @@ TorrentListCtrl :: RefreshTorrent( tr_torrent_t * tor, xstr = toWxStr( buf ); break; - case COL_DONE: + case COL_PERCENT_DONE: snprintf( buf, sizeof(buf), "%d%%", (int)(s->percentDone*100.0) ); xstr = toWxStr( buf ); break; - case COL_DOWNLOAD_SPEED: break; + case COL_DOWNLOAD_SPEED: if( s->rateDownload > 0.01 ) xstr = getReadableSpeed( s->rateDownload ); else @@ -247,8 +248,7 @@ TorrentListCtrl :: RefreshTorrent( tr_torrent_t * tor, case COL_PEERS: /* FIXME: this is all peers, not just leechers */ - snprintf( buf, sizeof(buf), "%d (%d)", s->peersTotal, s->peersConnected ); - xstr = toWxStr( buf ); + xstr = wxString::Format( _("%d of %d"), s->peersConnected, s->peersTotal ); break; case COL_RATIO: @@ -283,7 +283,7 @@ TorrentListCtrl :: RefreshTorrent( tr_torrent_t * tor, switch( s->status ) { case TR_STATUS_STOPPING: xstr = _("Stopping"); break; case TR_STATUS_STOPPED: xstr = _("Stopped"); break; - case TR_STATUS_CHECK: xstr = _("Checking Files"); break; + case TR_STATUS_CHECK: xstr = wxString::Format ( _("Checking Files (%.0f)"), s->recheckProgress ); break; case TR_STATUS_CHECK_WAIT: xstr = _("Waiting to Check"); break; case TR_STATUS_DOWNLOAD: xstr = _("Downloading"); break; case TR_STATUS_DONE: @@ -388,7 +388,7 @@ TorrentListCtrl :: Compare( long item1, long item2, long sortData ) ret = item1 - item2; break; - case COL_DONE: + case COL_PERCENT_DONE: if( sa->percentDone < sb->percentDone ) ret = -1; else if( sa->percentDone > sb->percentDone ) @@ -581,10 +581,10 @@ TorrentListCtrl :: Rebuild() switch( *it ) { case COL_POSITION: h = _("#"); format = wxLIST_FORMAT_CENTRE; break; - case COL_DONE: h = _("Done"); format = wxLIST_FORMAT_RIGHT; break; - case COL_DOWNLOAD_SPEED: h = _("Down"); width = 50; format = wxLIST_FORMAT_RIGHT; break; + case COL_PERCENT_DONE: h = _("Done"); width = 50; format = wxLIST_FORMAT_RIGHT; break; + case COL_DOWNLOAD_SPEED: h = _("Down"); width = 80; format = wxLIST_FORMAT_RIGHT; break; case COL_ETA: h = _("ETA"); format = wxLIST_FORMAT_RIGHT; break; - case COL_HASH: h = _("SHA1 Hash"); break; + case COL_HASH: h = _("Checksum"); break; case COL_NAME: h = _("Name"); width = 500; break; case COL_PEERS: h = _("Peers"); format = wxLIST_FORMAT_RIGHT; break; case COL_RATIO: h = _("Ratio"); format = wxLIST_FORMAT_RIGHT; break; @@ -596,7 +596,7 @@ TorrentListCtrl :: Rebuild() case COL_STATE: h = _("State"); width = 120; break; case COL_STATUS: h = _("Status"); width = 120; break; case COL_TOTAL: h = _("Total"); break; - case COL_UPLOAD_SPEED: h = _("Up"); width = 50; format = wxLIST_FORMAT_RIGHT;break; + case COL_UPLOAD_SPEED: h = _("Up"); width = 80; format = wxLIST_FORMAT_RIGHT;break; default: h = _("Error"); break; } @@ -676,3 +676,22 @@ TorrentListCtrl :: getStat( tr_torrent_t * tor ) } return ts.stat; } + +/*** +**** +***/ + +void +TorrentListCtrl :: SelectAll( ) +{ + for( int i=0, n=GetItemCount(); i torrents_v; diff --git a/wx/torrent-stats.cc b/wx/torrent-stats.cc new file mode 100644 index 000000000..8b2874395 --- /dev/null +++ b/wx/torrent-stats.cc @@ -0,0 +1,67 @@ +/* + * This file Copyright (C) 2007 Charles Kerr + * + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2(b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + */ + +#include +#include +#include +#include "torrent-stats.h" + +BEGIN_EVENT_TABLE(TorrentStats, wxPanel) +END_EVENT_TABLE() + +namespace +{ + enum + { + STAT_TIME_ELAPSED, + STAT_DOWNLOADED, + STAT_UPLOADED, + STAT_SHARE_RATIO, + STAT_SEEDS, + STAT_REMAINING, + STAT_DOWNLOAD_SPEED, + STAT_DOWNLOAD_SPEED_LIMIT, + STAT_UPLOAD_SPEED, + STAT_UPLOAD_SPEED_LIMIT, + N_STATS + }; + + wxString getLabelText( int n ) + { + wxString xstr; + + switch( n ) + { + case STAT_TIME_ELAPSED: xstr = _("Time Elapsed"); break; + case STAT_DOWNLOADED: xstr = _("Downloaded"); break; + case STAT_UPLOADED: xstr = _("Uploaded"); break; + case STAT_SHARE_RATIO: xstr = _("Share Ratio"); break; + case STAT_SEEDS: xstr = _("Seeds"); break; + case STAT_REMAINING: xstr = _("Time Remaining"); break; + case STAT_DOWNLOAD_SPEED: xstr = _("Download Speed"); break; + case STAT_DOWNLOAD_SPEED_LIMIT: xstr = _("Download Speed Limit"); break; + case STAT_UPLOAD_SPEED: xstr = _("Upload Speed"); break; + case STAT_UPLOAD_SPEED_LIMIT: xstr = _("Upload Speed Limit"); break; + default: break; + } + + return xstr; + } +} + +TorrentStats :: TorrentStats( wxWindow * parent, + wxWindowID id, + const wxPoint & pos, + const wxSize & size, + long style, + const wxString & name ): + wxPanel( parent, id, pos, size, style, name ) +{ +} diff --git a/wx/torrent-stats.h b/wx/torrent-stats.h new file mode 100644 index 000000000..12f8a333a --- /dev/null +++ b/wx/torrent-stats.h @@ -0,0 +1,33 @@ +/* + * This file Copyright (C) 2007 Charles Kerr + * + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2(b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + */ + +#ifndef __XMISSION_TORRENT_STATS_H__ +#define __XMISSION_TORRENT_STATS_H__ + +#include + +class TorrentStats: public wxPanel +{ + public: + + TorrentStats( wxWindow * parent, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTAB_TRAVERSAL, + const wxString& name = _T("panel")); + + virtual ~TorrentStats() {} + + private: + DECLARE_EVENT_TABLE() +}; + +#endif diff --git a/wx/xmission.cc b/wx/xmission.cc index 27a4b36d6..bd4358ed3 100755 --- a/wx/xmission.cc +++ b/wx/xmission.cc @@ -13,15 +13,21 @@ #include #include #include + #include + #include #include -#include +#include #include +#include +#include +#include #include #include #include #include +#include #include #include #include @@ -44,8 +50,11 @@ extern "C" #include } +#include "foreach.h" +#include "speed-stats.h" #include "torrent-filter.h" #include "torrent-list.h" +#include "torrent-stats.h" /*** **** @@ -84,14 +93,23 @@ namespace return getReadableSize( (uint64_t)f ); } - wxString getReadableSpeed( float f ) + wxString getReadableSpeed( float kib_sec ) { - wxString xstr = getReadableSize(f); + wxString xstr = getReadableSize(1024*kib_sec); xstr += _T("/s"); return xstr; } } +namespace +{ + const wxCmdLineEntryDesc cmdLineDesc[] = + { + { wxCMD_LINE_SWITCH, _T("p"), _("pause"), _("pauses all the torrents on startup"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, + { wxCMD_LINE_NONE, NULL, NULL, NULL, wxCMD_LINE_VAL_STRING, 0 } + }; +} + /*** **** ***/ @@ -99,12 +117,12 @@ namespace class MyApp : public wxApp { virtual bool OnInit(); + virtual ~MyApp(); + wxSingleInstanceChecker * myChecker; }; namespace { - const char * destination = "/home/charles/torrents"; /*FIXME*/ - tr_handle_t * handle = NULL; typedef std::vector torrents_v; @@ -113,21 +131,37 @@ namespace class MyFrame : public wxFrame, public TorrentListCtrl::Listener { public: - MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); + MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, bool paused); virtual ~MyFrame(); public: void OnExit( wxCommandEvent& ); void OnAbout( wxCommandEvent& ); void OnOpen( wxCommandEvent& ); - void OnRecheck( wxCommandEvent& ); - void OnTimer( wxTimerEvent& ); void OnFilterSelected( wxListEvent& ); + + void OnStart( wxCommandEvent& ); void OnStartUpdate( wxUpdateUIEvent& ); + + void OnStop( wxCommandEvent& ); void OnStopUpdate( wxUpdateUIEvent& ); + + void OnRemove( wxCommandEvent& ); void OnRemoveUpdate( wxUpdateUIEvent& ); - void OnRefreshUpdate( wxUpdateUIEvent& ); + + void OnRecheck( wxCommandEvent& ); + void OnRecheckUpdate( wxUpdateUIEvent& ); + + void OnInfo( wxCommandEvent& ); void OnInfoUpdate( wxUpdateUIEvent& ); + + void OnSelectAll( wxCommandEvent& ); + void OnSelectAllUpdate( wxUpdateUIEvent& ); + void OnDeselectAll( wxCommandEvent& ); + void OnDeselectAllUpdate( wxUpdateUIEvent& ); + + void OnPulse( wxTimerEvent& ); + virtual void OnTorrentListSelectionChanged( TorrentListCtrl*, const std::set& ); private: @@ -140,13 +174,17 @@ protected: private: TorrentListCtrl * myTorrentList; + TorrentStats * myTorrentStats; wxListCtrl * myFilters; wxTaskBarIcon myTrayIcon; wxIcon myLogoIcon; wxIcon myTrayIconIcon; + SpeedStats * mySpeedStats; torrents_v myTorrents; torrents_v mySelectedTorrents; int myFilter; + std::string mySavePath; + time_t myExitTime; private: DECLARE_EVENT_TABLE() @@ -155,6 +193,7 @@ private: enum { ID_START, + ID_DESELECTALL, ID_EDIT_PREFS, ID_SHOW_DEBUG_WINDOW, ID_Pulse, @@ -162,52 +201,140 @@ enum }; BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU ( wxID_ABOUT, MyFrame::OnAbout ) + EVT_TIMER ( ID_Pulse, MyFrame::OnPulse ) EVT_LIST_ITEM_SELECTED( ID_Filter, MyFrame::OnFilterSelected ) - EVT_MENU( wxID_REFRESH, MyFrame::OnRecheck ) + EVT_MENU ( wxID_EXIT, MyFrame::OnExit ) + EVT_MENU ( wxID_OPEN, MyFrame::OnOpen ) + EVT_MENU ( ID_START, MyFrame::OnStart ) EVT_UPDATE_UI( ID_START, MyFrame::OnStartUpdate ) + EVT_MENU ( wxID_STOP, MyFrame::OnStop ) EVT_UPDATE_UI( wxID_STOP, MyFrame::OnStopUpdate ) + EVT_MENU ( wxID_REFRESH, MyFrame::OnRecheck ) + EVT_UPDATE_UI( wxID_REFRESH, MyFrame::OnRecheckUpdate ) + EVT_MENU ( wxID_REMOVE, MyFrame::OnRemove ) EVT_UPDATE_UI( wxID_REMOVE, MyFrame::OnRemoveUpdate ) - EVT_UPDATE_UI( wxID_REFRESH, MyFrame::OnRefreshUpdate ) + EVT_MENU ( wxID_PROPERTIES, MyFrame::OnInfo ) EVT_UPDATE_UI( wxID_PROPERTIES, MyFrame::OnInfoUpdate ) + EVT_MENU ( wxID_SELECTALL, MyFrame::OnSelectAll ) + EVT_UPDATE_UI( wxID_SELECTALL, MyFrame::OnSelectAllUpdate ) + EVT_MENU ( ID_DESELECTALL, MyFrame::OnDeselectAll ) + EVT_UPDATE_UI( ID_DESELECTALL, MyFrame::OnDeselectAllUpdate ) END_EVENT_TABLE() IMPLEMENT_APP(MyApp) + +void +MyFrame :: OnSelectAll( wxCommandEvent& ) +{ + myTorrentList->SelectAll( ); +} + +void +MyFrame :: OnSelectAllUpdate( wxUpdateUIEvent& event ) +{ + event.Enable( mySelectedTorrents.size() < myTorrents.size() ); +} + +void +MyFrame :: OnDeselectAll( wxCommandEvent& ) +{ + myTorrentList->DeselectAll ( ); +} + +void +MyFrame :: OnDeselectAllUpdate( wxUpdateUIEvent& event ) +{ + event.Enable( !mySelectedTorrents.empty() ); +} + +/** +**/ + void MyFrame :: OnStartUpdate( wxUpdateUIEvent& event ) { unsigned long l = 0; - for( torrents_v::iterator it(mySelectedTorrents.begin()), - end(mySelectedTorrents.end()); it!=end; ++it ) + foreach( torrents_v, mySelectedTorrents, it ) l |= tr_torrentStat(*it)->status; /* FIXME: expensive */ event.Enable( (l & TR_STATUS_INACTIVE)!=0 ); } +void +MyFrame :: OnStart( wxCommandEvent& WXUNUSED(unused) ) +{ + foreach( torrents_v, mySelectedTorrents, it ) + if( tr_torrentStat(*it)->status & TR_STATUS_INACTIVE ) + tr_torrentStart( *it ); +} + +/** +**/ void MyFrame :: OnStopUpdate( wxUpdateUIEvent& event ) { unsigned long l = 0; - for( torrents_v::iterator it(mySelectedTorrents.begin()), - end(mySelectedTorrents.end()); it!=end; ++it ) + foreach( torrents_v, mySelectedTorrents, it ) l |= tr_torrentStat(*it)->status; /* FIXME: expensive */ event.Enable( (l & TR_STATUS_ACTIVE)!=0 ); } +void +MyFrame :: OnStop( wxCommandEvent& WXUNUSED(unused) ) +{ + foreach( torrents_v, mySelectedTorrents, it ) + if( tr_torrentStat(*it)->status & TR_STATUS_ACTIVE ) + tr_torrentStop( *it ); +} + +/** +**/ void MyFrame :: OnRemoveUpdate( wxUpdateUIEvent& event ) { - event.Enable( !mySelectedTorrents.empty() ); + event.Enable( !mySelectedTorrents.empty() ); } void -MyFrame :: OnRefreshUpdate( wxUpdateUIEvent& event ) +MyFrame :: OnRemove( wxCommandEvent& WXUNUSED(unused) ) +{ + foreach( torrents_v, mySelectedTorrents, it ) { + tr_torrentRemoveSaved( *it ); + tr_torrentClose( *it ); + } +} + +/** +**/ + +void +MyFrame :: OnRecheckUpdate( wxUpdateUIEvent& event ) { event.Enable( !mySelectedTorrents.empty() ); } +void +MyFrame :: OnRecheck( wxCommandEvent& WXUNUSED(unused) ) +{ + foreach( torrents_v, mySelectedTorrents, it ) + tr_torrentRecheck( *it ); +} + +/** +**/ + void MyFrame :: OnInfoUpdate( wxUpdateUIEvent& event ) { event.Enable( !mySelectedTorrents.empty() ); } +void +MyFrame :: OnInfo( wxCommandEvent& WXUNUSED(unused) ) +{ + std::cerr << "FIXME: info" << std::endl; +} + +/** +**/ void MyFrame :: OnOpen( wxCommandEvent& WXUNUSED(event) ) { @@ -230,7 +357,7 @@ void MyFrame :: OnOpen( wxCommandEvent& WXUNUSED(event) ) const std::string filename = toStr( paths[i] ); tr_torrent_t * tor = tr_torrentInit( handle, filename.c_str(), - destination, + mySavePath.c_str(), 0, NULL ); if( tor ) myTorrents.push_back( tor ); @@ -248,20 +375,34 @@ bool MyApp::OnInit() { handle = tr_init( "wx" ); + wxCmdLineParser cmdParser( cmdLineDesc, argc, argv ); + if( cmdParser.Parse ( ) ) + return false; + + const wxString name = wxString::Format( _T("MyApp-%s"), wxGetUserId().c_str()); + myChecker = new wxSingleInstanceChecker( name ); + if ( myChecker->IsAnotherRunning() ) { + wxLogError(_("An instance of Transmission is already running.")); + return false; + } + + const bool paused = cmdParser.Found( _("p") ); + MyFrame * frame = new MyFrame( _T("Xmission"), wxPoint(50,50), - wxSize(900,600)); - - frame->Connect( wxID_OPEN, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction) &MyFrame::OnOpen ); - frame->Connect( wxID_ABOUT, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction) &MyFrame::OnAbout ); - frame->Connect( wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction) &MyFrame::OnExit ); - frame->Connect( ID_Pulse, wxEVT_TIMER, (wxObjectEventFunction) &MyFrame::OnTimer ); + wxSize(900,600), + paused); frame->Show( true ); SetTopWindow( frame ); return true; } +MyApp :: ~MyApp() +{ + delete myChecker; +} + /*** **** ***/ @@ -294,13 +435,6 @@ MyFrame :: OnFilterSelected( wxListEvent& event ) ApplyCurrentFilter( ); } -void -MyFrame :: OnRecheck( wxCommandEvent& WXUNUSED(unused) ) -{ - for( torrents_v::iterator it(mySelectedTorrents.begin()), - end(mySelectedTorrents.end()); it!=end; ++it ) - tr_torrentRecheck( *it ); -} void MyFrame :: OnTorrentListSelectionChanged( TorrentListCtrl* list, @@ -311,20 +445,37 @@ MyFrame :: OnTorrentListSelectionChanged( TorrentListCtrl* list, } void -MyFrame :: OnTimer(wxTimerEvent& WXUNUSED(event) ) +MyFrame :: OnPulse(wxTimerEvent& WXUNUSED(event) ) { + if( myExitTime ) { + std::cerr << __FILE__ << ':' << __LINE__ << ' ' << tr_torrentCount(handle) << " torrents left" << std::endl; + if ( !tr_torrentCount(handle) || myExitTimeRefresh ( ); + mySpeedStats->Update( handle ); - float dl, ul; - tr_torrentRates( handle, &dl, &ul ); - wxString s = _("Download: "); - s += getReadableSpeed( dl ); - s += _T("\n"); - s +=_("Upload: "); - s += getReadableSpeed( ul ); - myTrayIcon.SetIcon( myTrayIconIcon, s ); + float down, up; + tr_torrentRates( handle, &down, &up ); + wxString xstr = _("Total DL: "); + xstr += getReadableSpeed( down ); + SetStatusText( xstr, 1 ); + xstr = _("Total UL: "); + xstr += getReadableSpeed( up ); + SetStatusText( xstr, 2 ); + + xstr = _("Download: "); + xstr += getReadableSpeed( down ); + xstr += _T("\n"); + xstr +=_("Upload: "); + xstr += getReadableSpeed( up ); + myTrayIcon.SetIcon( myTrayIconIcon, xstr ); + + myTorrentList->Refresh ( ); } MyFrame::~MyFrame() @@ -335,16 +486,30 @@ MyFrame::~MyFrame() delete myConfig; } -MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size): +MyFrame :: MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, bool paused): wxFrame((wxFrame*)NULL,-1,title,pos,size), myConfig( new wxConfig( _T("xmission") ) ), myPulseTimer( this, ID_Pulse ), myLogoIcon( transmission_xpm ), myTrayIconIcon( systray_xpm ), - myFilter( TorrentFilter::SHOW_ALL ) + myFilter( TorrentFilter::SHOW_ALL ), + myExitTime( 0 ) { SetIcon( myLogoIcon ); + long port; + wxString key = _T("port"); + if( !myConfig->Read( key, &port, 9090 ) ) + myConfig->Write( key, port ); + tr_setBindPort( handle, port ); + + key = _T("save-path"); + wxString wxstr; + if( !myConfig->Read( key, &wxstr, wxFileName::GetHomeDir() ) ) + myConfig->Write( key, wxstr ); + mySavePath = toStr( wxstr ); + std::cerr << __FILE__ << ':' << __LINE__ << " save-path is [" << mySavePath << ']' << std::endl; + /** *** Menu **/ @@ -365,6 +530,9 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size): menuBar->Append( m, _T("&File") ); m = new wxMenu; + m->Append( wxID_SELECTALL, _T("Select &All") ); + m->Append( ID_DESELECTALL, _T("&Deselect All") ); + m->AppendSeparator(); m->Append( wxID_PROPERTIES, _T("Torrent &Info") ); m->Append( wxID_PREFERENCES, _T("Edit &Preferences") ); menuBar->Append( m, _T("&Edit") ); @@ -433,16 +601,18 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size): wxNotebook * notebook = new wxNotebook( hsplit, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP ); - wxButton * tmp = new wxButton( notebook, wxID_ANY, _T("Hello World")); - notebook->AddPage( tmp, _T("General"), false ); + myTorrentStats = new TorrentStats( notebook ); + notebook->AddPage( myTorrentStats, _T("General"), false ); + wxButton * tmp = new wxButton( notebook, wxID_ANY, _T("Hello &World")); + notebook->AddPage( tmp, _T("Peers") ); + tmp = new wxButton( notebook, wxID_ANY, _T("&Hello World")); + notebook->AddPage( tmp, _T("Pieces") ); tmp = new wxButton( notebook, wxID_ANY, _T("Hello World")); - notebook->AddPage( tmp, _T("Peers"), false ); + notebook->AddPage( tmp, _T("Files") ); + mySpeedStats = new SpeedStats( notebook, wxID_ANY ); + notebook->AddPage( mySpeedStats, _T("Speed"), true ); tmp = new wxButton( notebook, wxID_ANY, _T("Hello World")); - notebook->AddPage( tmp, _T("Pieces"), false ); - tmp = new wxButton( notebook, wxID_ANY, _T("Hello World")); - notebook->AddPage( tmp, _T("Files"), false ); - tmp = new wxButton( notebook, wxID_ANY, _T("Hello World")); - notebook->AddPage( tmp, _T("Logger"), false ); + notebook->AddPage( tmp, _T("Logger") ); hsplit->SplitHorizontally( row1, notebook ); @@ -450,8 +620,11 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size): *** Statusbar **/ - CreateStatusBar(); - SetStatusText(_T("Welcome to Xmission!")); + const int widths[] = { -1, 150, 150 }; + wxStatusBar * statusBar = CreateStatusBar( WXSIZEOF(widths) ); + SetStatusWidths( WXSIZEOF(widths), widths ); + const int styles[] = { wxSB_FLAT, wxSB_NORMAL, wxSB_NORMAL }; + statusBar->SetStatusStyles( WXSIZEOF(widths), styles ); /** *** Refresh @@ -463,20 +636,33 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size): *** Load the torrents **/ - const int flags = TR_FLAG_PAUSED; + int flags = 0; + if( paused ) + flags |= TR_FLAG_PAUSED; int count = 0; - tr_torrent_t ** torrents = tr_loadTorrents ( handle, destination, flags, &count ); + tr_torrent_t ** torrents = tr_loadTorrents ( handle, mySavePath.c_str(), flags, &count ); myTorrents.insert( myTorrents.end(), torrents, torrents+count ); myTorrentList->Add( myTorrents ); tr_free( torrents ); wxTimerEvent dummy; - OnTimer( dummy ); + OnPulse( dummy ); } void MyFrame::OnExit(wxCommandEvent& WXUNUSED(event)) { - Destroy( ); + Enable( false ); + + foreach( torrents_v, myTorrents, it ) + tr_torrentClose( *it ); + + myTorrents.clear (); + mySelectedTorrents.clear (); + + ApplyCurrentFilter (); + + /* give the connections a max of 10 seconds to shut themselves down */ + myExitTime = time(0) + 10; } void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))