spek/src/spek-window.cc
2012-09-03 17:24:01 -07:00

385 lines
11 KiB
C++

/* spek-window.cc
*
* Copyright (C) 2010-2012 Alexander Kojevnikov <alexander@kojevnikov.com>
*
* Spek is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Spek is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Spek. If not, see <http://www.gnu.org/licenses/>.
*/
#include <wx/aboutdlg.h>
#include <wx/artprov.h>
#include <wx/dnd.h>
#include <wx/filename.h>
#include <wx/protocol/http.h>
#include <wx/sstream.h>
// WX on WIN doesn't like it when pthread.h is included first.
#include <pthread.h>
extern "C" {
#include <spek-utils.h>
}
#include "spek-preferences-dialog.hh"
#include "spek-preferences.hh"
#include "spek-spectrogram.hh"
#include "spek-window.hh"
DECLARE_EVENT_TYPE(SPEK_NOTIFY_EVENT, -1)
DEFINE_EVENT_TYPE(SPEK_NOTIFY_EVENT)
BEGIN_EVENT_TABLE(SpekWindow, wxFrame)
EVT_MENU(wxID_OPEN, SpekWindow::on_open)
EVT_MENU(wxID_SAVE, SpekWindow::on_save)
EVT_MENU(wxID_EXIT, SpekWindow::on_exit)
EVT_MENU(wxID_PREFERENCES, SpekWindow::on_preferences)
EVT_MENU(wxID_ABOUT, SpekWindow::on_about)
EVT_COMMAND(-1, SPEK_NOTIFY_EVENT, SpekWindow::on_notify)
END_EVENT_TABLE()
// Forward declarations.
static void * check_version(void *);
class SpekDropTarget : public wxFileDropTarget
{
public:
SpekDropTarget(SpekWindow *window) : wxFileDropTarget(), window(window) {}
protected:
virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames){
if (filenames.GetCount() == 1) {
window->open(filenames[0]);
return true;
}
return false;
}
private:
SpekWindow *window;
};
SpekWindow::SpekWindow(const wxString& path) :
path(path), wxFrame(NULL, -1, wxEmptyString, wxDefaultPosition, wxSize(640, 480))
{
this->description = _("Spek - Acoustic Spectrum Analyser");
SetTitle(this->description);
// TODO: test on all platforms
//SetIcon(wxIcon(wxT("spek")));
wxMenuBar *menu = new wxMenuBar();
wxMenu *menu_file = new wxMenu();
wxMenuItem *menu_file_open = new wxMenuItem(menu_file, wxID_OPEN);
menu_file->Append(menu_file_open);
wxMenuItem *menu_file_save = new wxMenuItem(menu_file, wxID_SAVE);
menu_file->Append(menu_file_save);
menu_file->AppendSeparator();
menu_file->Append(wxID_EXIT);
menu->Append(menu_file, _("&File"));
wxMenu *menu_edit = new wxMenu();
wxMenuItem *menu_edit_prefs = new wxMenuItem(menu_edit, wxID_PREFERENCES);
menu_edit_prefs->SetItemLabel(menu_edit_prefs->GetItemLabelText() + wxT("\tCtrl+E"));
menu_edit->Append(menu_edit_prefs);
menu->Append(menu_edit, _("&Edit"));
wxMenu *menu_help = new wxMenu();
wxMenuItem *menu_help_about = new wxMenuItem(menu_help, wxID_ABOUT);
menu_help_about->SetItemLabel(menu_help_about->GetItemLabelText() + wxT("\tF1"));
menu_help->Append(menu_help_about);
menu->Append(menu_help, _("&Help"));
SetMenuBar(menu);
wxToolBar *toolbar = CreateToolBar();
toolbar->AddTool(
wxID_OPEN,
menu_file_open->GetItemLabelText(),
wxArtProvider::GetBitmap(wxART_FILE_OPEN)
);
toolbar->AddTool(
wxID_SAVE,
menu_file_save->GetItemLabelText(),
wxArtProvider::GetBitmap(wxART_FILE_SAVE)
);
toolbar->Realize();
wxSizer *sizer = new wxBoxSizer(wxVERTICAL);
// wxInfoBar is too limited, construct a custom one.
wxPanel *info_bar = new wxPanel(this);
info_bar->Hide();
info_bar->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT));
info_bar->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK));
wxSizer *info_sizer = new wxBoxSizer(wxHORIZONTAL);
wxStaticText *label = new wxStaticText(
info_bar, -1, _("A new version of Spek is available, click to download."));
label->SetCursor(*new wxCursor(wxCURSOR_HAND));
label->Connect(wxEVT_LEFT_DOWN, wxCommandEventHandler(SpekWindow::on_visit));
// This second Connect() handles clicks on the border
info_bar->Connect(wxEVT_LEFT_DOWN, wxCommandEventHandler(SpekWindow::on_visit));
info_sizer->Add(label, 1, wxALIGN_CENTER_VERTICAL | wxALL, 6);
wxBitmapButton *button = new wxBitmapButton(
info_bar, -1, wxArtProvider::GetBitmap(wxT("gtk-close")),
wxDefaultPosition, wxDefaultSize, wxNO_BORDER);
button->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(SpekWindow::on_close));
info_sizer->Add(button, 0, wxALIGN_CENTER_VERTICAL);
info_bar->SetSizer(info_sizer);
sizer->Add(info_bar, 0, wxEXPAND);
this->spectrogram = new SpekSpectrogram(this);
sizer->Add(this->spectrogram, 1, wxEXPAND);
this->cur_dir = wxGetHomeDir();
if (!path.IsEmpty()) {
open(path);
}
SetDropTarget(new SpekDropTarget(this));
SetSizer(sizer);
pthread_t thread;
pthread_create(&thread, NULL, &check_version, this);
}
void SpekWindow::open(const wxString& path)
{
wxFileName file_name(path);
if (file_name.FileExists()) {
this->path = path;
wxString full_name = file_name.GetFullName();
// TRANSLATORS: window title, %s is replaced with the file name
wxString title = wxString::Format(_("Spek - %s"), full_name.c_str());
SetTitle(title);
this->spectrogram->open(path);
}
}
// TODO: s/audio/media/
static const char *audio_extensions[] = {
"3gp",
"aac",
"aif",
"aifc",
"aiff",
"amr",
"awb",
"ape",
"au",
"dts",
"flac",
"gsm",
"m4a",
"m4p",
"mp3",
"mp4",
"mp+",
"mpc",
"mpp",
"oga",
"ogg",
"ra",
"ram",
"snd",
"wav",
"wma",
"wv",
NULL
};
void SpekWindow::on_open(wxCommandEvent& event)
{
static wxString filters = wxEmptyString;
static int filter_index = 1;
if (filters.IsEmpty()) {
filters.Alloc(1024);
filters += _("All files");
filters += wxT("|*.*|");
filters += _("Audio files");
filters += wxT("|");
for (int i = 0; audio_extensions[i]; ++i) {
if (i) {
filters += wxT(";");
}
filters += wxT("*.");
filters += wxString::FromAscii(audio_extensions[i]);
}
filters.Shrink();
}
wxFileDialog *dlg = new wxFileDialog(
this,
_("Open File"),
this->cur_dir,
wxEmptyString,
filters,
wxFD_OPEN
);
dlg->SetFilterIndex(filter_index);
if (dlg->ShowModal() == wxID_OK) {
this->cur_dir = dlg->GetDirectory();
filter_index = dlg->GetFilterIndex();
open(dlg->GetPath());
}
dlg->Destroy();
}
void SpekWindow::on_save(wxCommandEvent& event)
{
static wxString filters = wxEmptyString;
if (filters.IsEmpty()) {
filters = _("PNG images");
filters += wxT("|*.png");
}
wxFileDialog *dlg = new wxFileDialog(
this,
_("Save Spectrogram"),
this->cur_dir,
wxEmptyString,
filters,
wxFD_SAVE
);
// Suggested name is <file_name>.png
wxString name = _("Untitled");
if (!this->path.IsEmpty()) {
wxFileName file_name(this->path);
name = file_name.GetFullName();
}
name += wxT(".png");
dlg->SetFilename(name);
if (dlg->ShowModal() == wxID_OK) {
this->cur_dir = dlg->GetDirectory();
this->spectrogram->save(dlg->GetPath());
}
dlg->Destroy();
}
void SpekWindow::on_exit(wxCommandEvent& event)
{
Close(true);
}
void SpekWindow::on_preferences(wxCommandEvent& event)
{
SpekPreferencesDialog dlg(this);
dlg.ShowModal();
}
void SpekWindow::on_about(wxCommandEvent& event)
{
wxAboutDialogInfo info;
info.AddDeveloper(wxT("Alexander Kojevnikov"));
info.AddDeveloper(wxT("Fabian Deutsch"));
info.AddDeveloper(wxT("Jonathan Gonzalez V"));
info.AddDeveloper(wxT("Stefan Kost"));
info.AddDeveloper(wxT("Thibault North"));
info.AddArtist(wxT("Olga Vasylevska"));
// TRANSLATORS: Add your name here
wxString translator = _("translator-credits");
if (translator != wxT("translator-credits")) {
info.AddTranslator(translator);
}
info.SetName(wxT("Spek"));
info.SetVersion(wxT(PACKAGE_VERSION));
info.SetCopyright(_("Copyright (c) 2010-2012 Alexander Kojevnikov and contributors"));
info.SetDescription(this->description);
#ifdef OS_UNIX
info.SetWebSite(wxT("http://spek-project.org/"), _("Spek Website"));
info.SetIcon(wxArtProvider::GetIcon(wxT("spek"), wxART_OTHER, wxSize(128, 128)));
#endif
wxAboutBox(info);
}
void SpekWindow::on_notify(wxCommandEvent& event)
{
this->GetSizer()->Show((size_t)0);
this->Layout();
}
void SpekWindow::on_visit(wxCommandEvent& event)
{
wxLaunchDefaultBrowser(wxT("http://spek-project.org"));
}
void SpekWindow::on_close(wxCommandEvent& event)
{
wxWindow *self = ((wxWindow *)event.GetEventObject())->GetGrandParent();
self->GetSizer()->Hide((size_t)0);
self->Layout();
}
static void * check_version(void *p)
{
// Does the user want to check for updates?
SpekPreferences& prefs = SpekPreferences::get();
if (!prefs.get_check_update()) {
return NULL;
}
// Calculate the number of days since 0001-01-01, borrowed from GLib.
wxDateTime now = wxDateTime::Now();
int year = now.GetYear() - 1;
int days = year * 365;
days += (year >>= 2); // divide by 4 and add
days -= (year /= 25); // divides original # years by 100
days += year >> 2; // divides by 4, which divides original by 400
days += now.GetDayOfYear();
// When was the last update?
int diff = days - prefs.get_last_update();
if (diff < 7) {
return NULL;
}
// Get the version number.
wxString version;
wxHTTP http;
if (http.Connect(wxT("spek-project.org"))) {
wxInputStream *stream = http.GetInputStream(wxT("/version"));
if (stream) {
wxStringOutputStream out(&version);
stream->Read(out);
version.Trim();
delete stream;
}
}
if (version.IsEmpty()) {
return NULL;
}
if (1 == spek_vercmp(version.mb_str(wxConvLibc), PACKAGE_VERSION)) {
SpekWindow *self = (SpekWindow *)p;
wxCommandEvent event(SPEK_NOTIFY_EVENT, -1);
event.SetEventObject(self);
wxPostEvent(self, event);
}
// Update the preferences.
prefs.set_check_update(true);
prefs.set_last_update(days);
return NULL;
}