/*************************************************************************
* UrBackup - Client/Server backup system
* Copyright (C) 2011-2015 Martin Raiber
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
**************************************************************************/
#include "Status.h"
#include "main.h"
#include "TranslationHelper.h"
#include "stringtools.h"
extern wxString res_path;
extern wxString ico_ext;
extern wxBitmapType ico_type;
const int reset_error_count=20;
namespace
{
wxString getInternetConnectionStatus(wxString str, unsigned int last_seen)
{
if(str==wxT("initializing"))
{
return _("Initializing.");
}
else if(str==wxT("wait_local"))
{
return _("Waiting for local UrBackup server.");
}
else if(str==wxT("connected_local"))
{
unsigned int min_last_seen = (last_seen/1000)/60;
wxString last_seen;
last_seen << min_last_seen;
return _("Connected to local UrBackup server.")+wxT("\n")+_("Not trying to connect to Internet server.")+wxT("\n")+
trans_1(_("Local server last seen _1_ minutes ago."), last_seen);
}
else if(str==wxT("no_server"))
{
return _("No Internet server configured.");
}
else if(str==wxT("connected"))
{
return _("Connected to Internet server");
}
else if(str==wxT("connecting_failed"))
{
return _("Could not connect to Internet server. Server unreachable.");
}
else if(str.find(wxT("error:"))==0)
{
return trans_1(_("Error: _1_"), str.substr(6));
}
return str;
}
std::string PrettyPrintTime(wxLongLong_t ms)
{
std::string ret;
unsigned int c_s=1000;
unsigned int c_m=c_s*60;
unsigned int c_h=c_m*60;
unsigned int c_d=c_h*24;
if( ms>c_d)
{
wxLongLong_t t=ms/c_d;
if(!ret.empty()) ret+=" ";
ret+=nconvert(t)+wxT(" ")+wxPLURAL("day", "days", static_cast(t));
ms-=t*c_d;
}
if( ms>c_h)
{
wxLongLong_t t=ms/c_h;
if(!ret.empty()) ret+=" ";
ret+=nconvert(t)+wxT(" ")+wxPLURAL("hour", "hours", static_cast(t));
ms-=t*c_h;
}
if( ms>c_m)
{
wxLongLong_t t=ms/c_m;
if(!ret.empty()) ret+=" ";
ret+=nconvert(t)+wxT(" ")+wxPLURAL("minute", "minutes", static_cast(t));
ms-=t*c_m;
}
return ret;
}
}
Status* Status::instance = NULL;
Status::Status(wxWindow* parent, wxLongLong_t follow_only_process_id)
: GUIStatus(parent, follow_only_process_id)
{
SetIcon(wxIcon(res_path+wxT("backup-ok.")+ico_ext, ico_type));
if(updateStatus(0))
{
SetFocus();
Raise();
Show(true);
#if !defined(__WXMAC__) && !defined(__linux__)
RequestUserAttention();
#endif
if (follow_only_process_id == 0)
{
instance = this;
}
Start(1000);
}
#ifndef __APPLE__
SetDoubleBuffered(true);
#endif
error_count=reset_error_count;
}
bool Status::updateStatus(int errcnt)
{
SStatusDetails status_details = Connector::getStatusDetails(&connection);
if(!status_details.ok)
{
if(errcnt-1<=0)
{
Stop();
wxMessageBox(_("There was an error. Currently nothing can be backed up."), wxT("UrBackup"), wxOK|wxICON_ERROR);
Close();
}
return false;
}
if (follow_only_process_id != 0)
{
for (size_t i = 0; i < status_details.running_processes.size();)
{
if (status_details.running_processes[i].process_id != follow_only_process_id)
{
status_details.running_processes.erase(status_details.running_processes.begin() + i);
}
else
{
++i;
}
}
}
if(last_status_details == status_details)
{
return true;
}
last_status_details = status_details;
if (!status_details.running_processes.empty())
{
if (status_details.running_processes.size() < m_processItem.size())
{
removeCurrentProcesses(status_details.running_processes.size());
}
else
{
resizeForProcesses(status_details.running_processes.size());
}
for (size_t i = 0; i < status_details.running_processes.size(); ++i)
{
SProcessItem& item = m_processItem[i];
SRunningProcess& proc = status_details.running_processes[i];
wxString status_text = getStatusText(proc.action);
item.m_gauge1->Enable();
if (proc.percent_done >= 0)
{
item.m_gauge1->SetValue(proc.percent_done);
}
else
{
item.m_gauge1->Pulse();
}
wxString eta_text = wxEmptyString;
if (proc.eta_ms>0)
{
eta_text = trans_1(_("ETA: Approx. _1_"), PrettyPrintTime(proc.eta_ms));
eta_text += " ";
}
if (!proc.details.empty())
{
if (proc.action == "RESTORE_FILES")
{
eta_text += trans_2(_("File: _1_"), proc.details, wxString(convert(proc.detail_pc)));
}
else if (proc.action == "INCRI" || proc.action == "FULLI")
{
eta_text += trans_1(_("Volume: _1_"), proc.details);
}
if (proc.detail_pc != -1)
{
if (proc.action == "RESTORE_FILES")
{
wxString s;
s << proc.detail_pc;
eta_text += getPercentText(s);
}
}
}
item.m_staticText312->SetLabel(eta_text);
wxString s;
s << proc.percent_done;
status_text += wxT(" ");
status_text += getPercentText(s);
item.m_staticText31->SetLabel(status_text);
}
}
else
{
removeCurrentProcesses(1);
SProcessItem& item = m_processItem[0];
item.m_staticText312->SetLabel(wxEmptyString);
item.m_gauge1->SetValue(0);
item.m_gauge1->Disable();
if (follow_only_process_id == 0)
{
item.m_staticText31->SetLabel(_("Idle."));
}
else
{
item.m_staticText31->SetLabel(_("Restore finished."));
}
}
if (follow_only_process_id == 0)
{
if (status_details.last_backup_time>0)
{
wxDateTime lastbackup_dt((wxLongLong)(status_details.last_backup_time * 1000));
m_staticText37->SetLabel(trans_1(_("Last backup on _1_"), lastbackup_dt.Format()));
}
else
{
m_staticText37->SetLabel(wxEmptyString);
}
wxString servers_text;
for (size_t i = 0; iSetLabel(wxEmptyString);
}
else
{
m_staticText32->SetLabel(_("Servers:"));
}
m_staticText33->SetLabel(servers_text);
m_staticText35->SetLabel(getInternetConnectionStatus(status_details.internet_status, status_details.time_since_last_lan_connection));
}
relayout();
return true;
}
void Status::Notify(void)
{
if(!IsVisible())
{
Stop();
return;
}
if(!updateStatus(error_count))
{
--error_count;
}
else
{
error_count=reset_error_count;
}
}
Status* Status::getInstance()
{
return instance;
}
void Status::OnClose()
{
if (follow_only_process_id == 0)
{
instance = NULL;
}
if (connection.client != NULL)
{
connection.client->Destroy();
connection.client = NULL;
}
Destroy();
}