spek-window.cc (10902B)
1 #include <wx/aboutdlg.h> 2 #include <wx/artprov.h> 3 #include <wx/dnd.h> 4 #include <wx/filename.h> 5 #include <wx/protocol/http.h> 6 #include <wx/sstream.h> 7 8 // WX on WIN doesn't like it when pthread.h is included first. 9 #include <pthread.h> 10 11 #include <spek-utils.h> 12 13 #include "spek-artwork.h" 14 #include "spek-preferences-dialog.h" 15 #include "spek-preferences.h" 16 #include "spek-spectrogram.h" 17 18 #include "spek-window.h" 19 20 DECLARE_EVENT_TYPE(SPEK_NOTIFY_EVENT, -1) 21 DEFINE_EVENT_TYPE(SPEK_NOTIFY_EVENT) 22 23 BEGIN_EVENT_TABLE(SpekWindow, wxFrame) 24 EVT_MENU(wxID_OPEN, SpekWindow::on_open) 25 EVT_MENU(wxID_SAVE, SpekWindow::on_save) 26 EVT_MENU(wxID_EXIT, SpekWindow::on_exit) 27 EVT_MENU(wxID_PREFERENCES, SpekWindow::on_preferences) 28 EVT_MENU(wxID_HELP, SpekWindow::on_help) 29 EVT_MENU(wxID_ABOUT, SpekWindow::on_about) 30 EVT_COMMAND(-1, SPEK_NOTIFY_EVENT, SpekWindow::on_notify) 31 END_EVENT_TABLE() 32 33 // Forward declarations. 34 static void * check_version(void *); 35 36 class SpekDropTarget : public wxFileDropTarget 37 { 38 public: 39 SpekDropTarget(SpekWindow *window) : wxFileDropTarget(), window(window) {} 40 41 protected: 42 virtual bool OnDropFiles(wxCoord, wxCoord, const wxArrayString& filenames){ 43 if (filenames.GetCount() == 1) { 44 window->open(filenames[0]); 45 return true; 46 } 47 return false; 48 } 49 50 private: 51 SpekWindow *window; 52 }; 53 54 SpekWindow::SpekWindow(const wxString& path) : 55 wxFrame(NULL, -1, wxEmptyString, wxDefaultPosition, wxSize(640, 480)), path(path) 56 { 57 this->description = _("Spek - Acoustic Spectrum Analyser"); 58 SetTitle(this->description); 59 60 #ifndef OS_OSX 61 SetIcons(wxArtProvider::GetIconBundle(ART_SPEK, wxART_FRAME_ICON)); 62 #endif 63 64 wxMenuBar *menu = new wxMenuBar(); 65 66 wxMenu *menu_file = new wxMenu(); 67 wxMenuItem *menu_file_open = new wxMenuItem(menu_file, wxID_OPEN); 68 menu_file->Append(menu_file_open); 69 wxMenuItem *menu_file_save = new wxMenuItem(menu_file, wxID_SAVE); 70 menu_file->Append(menu_file_save); 71 menu_file->AppendSeparator(); 72 menu_file->Append(wxID_EXIT); 73 menu->Append(menu_file, _("&File")); 74 75 wxMenu *menu_edit = new wxMenu(); 76 wxMenuItem *menu_edit_prefs = new wxMenuItem(menu_edit, wxID_PREFERENCES); 77 menu_edit_prefs->SetItemLabel(menu_edit_prefs->GetItemLabelText() + "\tCtrl-E"); 78 menu_edit->Append(menu_edit_prefs); 79 menu->Append(menu_edit, _("&Edit")); 80 81 wxMenu *menu_help = new wxMenu(); 82 wxMenuItem *menu_help_contents = new wxMenuItem( 83 menu_help, wxID_HELP, wxString(_("&Help")) + "\tF1"); 84 menu_help->Append(menu_help_contents); 85 wxMenuItem *menu_help_about = new wxMenuItem(menu_help, wxID_ABOUT); 86 menu_help_about->SetItemLabel(menu_help_about->GetItemLabelText() + "\tShift-F1"); 87 menu_help->Append(menu_help_about); 88 menu->Append(menu_help, _("&Help")); 89 90 SetMenuBar(menu); 91 92 wxToolBar *toolbar = CreateToolBar(); 93 toolbar->AddTool( 94 wxID_OPEN, 95 wxEmptyString, 96 wxArtProvider::GetBitmap(ART_OPEN, wxART_TOOLBAR), 97 menu_file_open->GetItemLabelText() 98 ); 99 toolbar->AddTool( 100 wxID_SAVE, 101 wxEmptyString, 102 wxArtProvider::GetBitmap(ART_SAVE, wxART_TOOLBAR), 103 menu_file_save->GetItemLabelText() 104 ); 105 toolbar->AddStretchableSpace(); 106 toolbar->AddTool( 107 wxID_HELP, 108 wxEmptyString, 109 wxArtProvider::GetBitmap(ART_HELP, wxART_TOOLBAR), 110 _("Help") 111 ); 112 toolbar->Realize(); 113 114 wxSizer *sizer = new wxBoxSizer(wxVERTICAL); 115 116 // wxInfoBar is too limited, construct a custom one. 117 wxPanel *info_bar = new wxPanel(this); 118 info_bar->Hide(); 119 info_bar->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT)); 120 info_bar->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK)); 121 wxSizer *info_sizer = new wxBoxSizer(wxHORIZONTAL); 122 wxStaticText *label = new wxStaticText( 123 info_bar, -1, _("A new version of Spek is available, click to download.")); 124 label->SetCursor(*new wxCursor(wxCURSOR_HAND)); 125 label->Connect(wxEVT_LEFT_DOWN, wxCommandEventHandler(SpekWindow::on_visit)); 126 // This second Connect() handles clicks on the border 127 info_bar->Connect(wxEVT_LEFT_DOWN, wxCommandEventHandler(SpekWindow::on_visit)); 128 info_sizer->Add(label, 1, wxALIGN_CENTER_VERTICAL | wxALL, 6); 129 wxBitmapButton *button = new wxBitmapButton( 130 info_bar, -1, wxArtProvider::GetBitmap(ART_CLOSE, wxART_BUTTON), 131 wxDefaultPosition, wxDefaultSize, wxNO_BORDER); 132 button->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(SpekWindow::on_close)); 133 info_sizer->Add(button, 0, wxALIGN_CENTER_VERTICAL); 134 info_bar->SetSizer(info_sizer); 135 sizer->Add(info_bar, 0, wxEXPAND); 136 137 this->spectrogram = new SpekSpectrogram(this); 138 sizer->Add(this->spectrogram, 1, wxEXPAND); 139 140 this->cur_dir = wxGetHomeDir(); 141 142 if (!path.IsEmpty()) { 143 open(path); 144 } 145 146 SetDropTarget(new SpekDropTarget(this)); 147 148 SetSizer(sizer); 149 150 pthread_t thread; 151 pthread_create(&thread, NULL, &check_version, this); 152 } 153 154 void SpekWindow::open(const wxString& path) 155 { 156 wxFileName file_name(path); 157 if (file_name.FileExists()) { 158 this->path = path; 159 wxString full_name = file_name.GetFullName(); 160 // TRANSLATORS: window title, %s is replaced with the file name 161 wxString title = wxString::Format(_("Spek - %s"), full_name.c_str()); 162 SetTitle(title); 163 164 this->spectrogram->open(path); 165 } 166 } 167 168 // TODO: s/audio/media/ 169 static const char *audio_extensions[] = { 170 "3gp", 171 "aac", 172 "aif", 173 "aifc", 174 "aiff", 175 "amr", 176 "awb", 177 "ape", 178 "au", 179 "dts", 180 "flac", 181 "flv", 182 "gsm", 183 "m4a", 184 "m4p", 185 "mp3", 186 "mp4", 187 "mp+", 188 "mpc", 189 "mpp", 190 "oga", 191 "ogg", 192 "opus", 193 "ra", 194 "ram", 195 "snd", 196 "wav", 197 "wma", 198 "wv", 199 NULL 200 }; 201 202 void SpekWindow::on_open(wxCommandEvent&) 203 { 204 static wxString filters = wxEmptyString; 205 static int filter_index = 1; 206 207 if (filters.IsEmpty()) { 208 filters.Alloc(1024); 209 filters += _("All files"); 210 filters += "|*.*|"; 211 filters += _("Audio files"); 212 filters += "|"; 213 for (int i = 0; audio_extensions[i]; ++i) { 214 if (i) { 215 filters += ";"; 216 } 217 filters += "*."; 218 filters += wxString::FromAscii(audio_extensions[i]); 219 } 220 filters.Shrink(); 221 } 222 223 wxFileDialog *dlg = new wxFileDialog( 224 this, 225 _("Open File"), 226 this->cur_dir, 227 wxEmptyString, 228 filters, 229 wxFD_OPEN 230 ); 231 dlg->SetFilterIndex(filter_index); 232 233 if (dlg->ShowModal() == wxID_OK) { 234 this->cur_dir = dlg->GetDirectory(); 235 filter_index = dlg->GetFilterIndex(); 236 open(dlg->GetPath()); 237 } 238 239 dlg->Destroy(); 240 } 241 242 void SpekWindow::on_save(wxCommandEvent&) 243 { 244 static wxString filters = wxEmptyString; 245 246 if (filters.IsEmpty()) { 247 filters = _("PNG images"); 248 filters += "|*.png"; 249 } 250 251 wxFileDialog *dlg = new wxFileDialog( 252 this, 253 _("Save Spectrogram"), 254 this->cur_dir, 255 wxEmptyString, 256 filters, 257 wxFD_SAVE | wxFD_OVERWRITE_PROMPT 258 ); 259 260 // Suggested name is <file_name>.png 261 wxString name = _("Untitled"); 262 if (!this->path.IsEmpty()) { 263 wxFileName file_name(this->path); 264 name = file_name.GetFullName(); 265 } 266 name += ".png"; 267 dlg->SetFilename(name); 268 269 if (dlg->ShowModal() == wxID_OK) { 270 this->cur_dir = dlg->GetDirectory(); 271 this->spectrogram->save(dlg->GetPath()); 272 } 273 274 dlg->Destroy(); 275 } 276 277 void SpekWindow::on_exit(wxCommandEvent&) 278 { 279 Close(true); 280 } 281 282 void SpekWindow::on_preferences(wxCommandEvent&) 283 { 284 SpekPreferencesDialog dlg(this); 285 dlg.ShowModal(); 286 } 287 288 void SpekWindow::on_help(wxCommandEvent&) 289 { 290 wxLaunchDefaultBrowser( 291 wxString::Format("http://spek.cc/man-%s.html", PACKAGE_VERSION) 292 ); 293 } 294 295 void SpekWindow::on_about(wxCommandEvent&) 296 { 297 wxAboutDialogInfo info; 298 info.AddDeveloper("Alexander Kojevnikov"); 299 info.AddDeveloper("Andreas Cadhalpun"); 300 info.AddDeveloper("Colin Watson"); 301 info.AddDeveloper("Daniel Hams"); 302 info.AddDeveloper("Fabian Deutsch"); 303 info.AddDeveloper("Jonathan Gonzalez V"); 304 info.AddDeveloper("Simon Ruderich"); 305 info.AddDeveloper("Stefan Kost"); 306 info.AddDeveloper("Thibault North"); 307 info.AddArtist("Olga Vasylevska"); 308 // TRANSLATORS: Add your name here 309 wxString translator = _("translator-credits"); 310 if (translator != "translator-credits") { 311 info.AddTranslator(translator); 312 } 313 info.SetName("Spek"); 314 info.SetVersion(PACKAGE_VERSION); 315 info.SetCopyright(_("Copyright (c) 2010-2013 Alexander Kojevnikov and contributors")); 316 info.SetDescription(this->description); 317 #ifdef OS_UNIX 318 info.SetWebSite("http://spek.cc/", _("Spek Website")); 319 info.SetIcon(wxArtProvider::GetIcon("spek", wxART_OTHER, wxSize(128, 128))); 320 #endif 321 wxAboutBox(info); 322 } 323 324 void SpekWindow::on_notify(wxCommandEvent&) 325 { 326 this->GetSizer()->Show((size_t)0); 327 this->Layout(); 328 } 329 330 void SpekWindow::on_visit(wxCommandEvent&) 331 { 332 wxLaunchDefaultBrowser("http://spek.cc"); 333 } 334 335 void SpekWindow::on_close(wxCommandEvent& event) 336 { 337 wxWindow *self = ((wxWindow *)event.GetEventObject())->GetGrandParent(); 338 self->GetSizer()->Hide((size_t)0); 339 self->Layout(); 340 } 341 342 static void * check_version(void *p) 343 { 344 // Does the user want to check for updates? 345 SpekPreferences& prefs = SpekPreferences::get(); 346 if (!prefs.get_check_update()) { 347 return NULL; 348 } 349 350 // Calculate the number of days since 0001-01-01, borrowed from GLib. 351 wxDateTime now = wxDateTime::Now(); 352 int year = now.GetYear() - 1; 353 int days = year * 365; 354 days += (year >>= 2); // divide by 4 and add 355 days -= (year /= 25); // divides original # years by 100 356 days += year >> 2; // divides by 4, which divides original by 400 357 days += now.GetDayOfYear(); 358 359 // When was the last update? 360 int diff = days - prefs.get_last_update(); 361 if (diff < 7) { 362 return NULL; 363 } 364 365 // Get the version number. 366 wxString version; 367 wxHTTP http; 368 if (http.Connect("spek.cc")) { 369 wxInputStream *stream = http.GetInputStream("/version"); 370 if (stream) { 371 wxStringOutputStream out(&version); 372 stream->Read(out); 373 version.Trim(); 374 delete stream; 375 } 376 } 377 378 if (version.IsEmpty()) { 379 return NULL; 380 } 381 382 if (1 == spek_vercmp(version.mb_str(wxConvLibc), PACKAGE_VERSION)) { 383 SpekWindow *self = (SpekWindow *)p; 384 wxCommandEvent event(SPEK_NOTIFY_EVENT, -1); 385 event.SetEventObject(self); 386 wxPostEvent(self, event); 387 } 388 389 // Update the preferences. 390 prefs.set_check_update(true); 391 prefs.set_last_update(days); 392 return NULL; 393 }