#include "wxinc.h" #include "incstr.h" #include "agasys.h" #include "xvt.h" /////////////////////////////////////////////////////////// // Unzip support /////////////////////////////////////////////////////////// #include #include #include #include static unsigned int aga_getziplist(const char* zipfile, wxArrayString& aFiles) { wxFFileInputStream fin(zipfile); wxZipInputStream zip(fin); for (wxZipEntry* z = zip.GetNextEntry(); z; z = zip.GetNextEntry()) { const wxString str = z->GetInternalName(); aFiles.Add(str); } return aFiles.GetCount(); } static int aga_find_slash(const wxString& path, int from) { for (int i = from; path[i]; i++) if (wxIsPathSeparator(path[i])) return i; return -1; } static void aga_create_dir(wxString strPath) { if (!wxEndsWithPathSeparator(strPath)) strPath += wxFILE_SEP_PATH; for (int i = aga_find_slash(strPath, 0); i > 0; i = aga_find_slash(strPath, i+1)) { const wxString strDir = strPath.Mid(0,i); if (!::wxDirExists(strDir)) { if (!::wxMkdir(strDir)) { wxString strMsg = "Impossibile creare la cartella "; strMsg << strDir << " !!"; wxMessageBox(strMsg, "Attenzione!", wxICON_ERROR); } } } } bool aga_unzip(const char* zipfile, const char* destdir) { wxArrayString aFiles; const unsigned int files = aga_getziplist(zipfile, aFiles); wxProgressDialog pi("Unzip", "", files, NULL, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT); pi.SetSize(480, 120); pi.Center(); for (unsigned int f = 0; f < files; f++) { const wxString& strFileName = aFiles[f]; if (!pi.Update(f, strFileName)) break; if (wxEndsWithPathSeparator(strFileName) || strFileName.Find('.') < 0) // Is dir name { wxString strOutDir = destdir; if (!wxEndsWithPathSeparator(strOutDir)) strOutDir += wxFILE_SEP_PATH; strOutDir += strFileName; aga_create_dir(strOutDir); } else { wxZipInputStream fin(zipfile, strFileName); wxString strOutFile = destdir; if (!wxEndsWithPathSeparator(strOutFile) && !wxIsPathSeparator(strFileName[0])) strOutFile += wxFILE_SEP_PATH; strOutFile += strFileName; wxString strPath; ::wxSplitPath(strOutFile, &strPath, NULL, NULL); aga_create_dir(strPath); wxFileOutputStream fout(strOutFile); fout.Write(fin); } } return files > 0; } /////////////////////////////////////////////////////////// // Zip support /////////////////////////////////////////////////////////// static void AddFileToZip(const wxString& strPrefix, const wxString& strFile, wxZipOutputStream& zip) { if (!wxFileExists(strFile)) return; wxString strPath, strName, strExt; wxSplitPath(strFile, &strPath, &strName, &strExt); wxString strRelName; strRelName = strPath.Mid(strPrefix.Length()); if (!strRelName.IsEmpty()) strRelName += '/'; strRelName += strName; strRelName += '.'; strRelName += strExt; zip.PutNextEntry(strRelName); wxFileInputStream fin(strFile); zip.Write(fin); // Scrivo file compresso } static bool AddFilesToZip(const wxString& strBase, wxArrayString& aFiles, const char* zipfile) { wxFFileOutputStream out(zipfile); wxZipOutputStream zip(out); const size_t nFiles = aFiles.GetCount(); wxProgressDialog pi("Zip", "", nFiles, NULL, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT); pi.SetSize(480, 120); pi.Center(); for (size_t i = 0; i < nFiles; i++) { const wxString& str = aFiles[i]; if (!pi.Update(i, str)) break; AddFileToZip(strBase, str, zip); } return true; } bool aga_zip(const char* srcfiles, const char* zipfile) { wxString strBase, strMask, strExt; wxSplitPath(srcfiles, &strBase, &strMask, &strExt); strMask += '.'; strMask += strExt; wxArrayString aFiles; wxDir::GetAllFiles(strBase, &aFiles, strMask); return AddFilesToZip(strBase, aFiles, zipfile); } bool aga_zip_filelist(const char* filelist, const char* zipfile) { wxArrayString aFiles; ifstream fin(filelist); while (!fin.eof()) { char name[_MAX_PATH]; fin.getline(name, sizeof(name)); if (*name) aFiles.Add(name); else break; } return AddFilesToZip("", aFiles, zipfile); } /////////////////////////////////////////////////////////// // DDE /////////////////////////////////////////////////////////// #ifdef __WXMSW__ #include #define wxAgaClient wxDDEClient #define wxAgaConnection wxDDEConnection #else // Forse inutile: forse gia' fatto da wxWidgets #include #define wxAgaClient wxTCPClient #define wxAgaConnection wxTCPConnection #endif static wxAgaClient* _net_client = NULL; static unsigned long _net_conns = 0; unsigned long aga_dde_connect(const char* host, const char* service, const char* topic) { if (_net_client == NULL) { _net_client = new wxAgaClient; _net_conns = 0; } wxConnectionBase* conn = _net_client->MakeConnection(host, service, topic); if (conn != NULL) _net_conns++; return (unsigned long)conn; } bool aga_dde_execute(unsigned long connection, const char* msg) { bool ok = false; if (connection != 0) { wxAgaConnection* conn = (wxAgaConnection*)connection; ok = conn->Execute((char*)msg, -1); } return ok; } bool aga_dde_terminate(unsigned long connection) { bool ok = false; if (connection != 0 && _net_client != NULL) { wxAgaConnection* conn = (wxAgaConnection*)connection; ok = conn->Disconnect(); if (ok && _net_conns > 0) { _net_conns--; if (_net_conns == 0) { delete _net_client; _net_client = NULL; } } } return ok; } /////////////////////////////////////////////////////////// // TProgressIndicator /////////////////////////////////////////////////////////// class TProgressIndicator : public wxDialog { enum { MAX_GAUGES = 16 }; wxGauge* m_pGauge[MAX_GAUGES]; wxStaticText* m_pPassed; wxStaticText* m_pResidual; wxStaticText* m_pEstimated; wxStopWatch m_chrono; long m_nNextUpdate; protected: DECLARE_EVENT_TABLE(); void Init(wxString msg, int nGauges, bool bCancellable); wxString msec2str(long ms) const; long Elapsed() const { return m_chrono.Time(); } public: void SetRange(int nRange, int nGauge = 0); bool SetProgress(int nPos, int nGauge = 0); void SetMessage(wxString msg); TProgressIndicator(wxString msg, bool bCancellable, int nGauges); TProgressIndicator(size_t nRange, wxString msg, bool bCancellable); virtual ~TProgressIndicator(); }; BEGIN_EVENT_TABLE(TProgressIndicator, wxDialog) // EVT_MENU(wxID_CANCEL, TProgressIndicator::OnCancel) END_EVENT_TABLE() wxString TProgressIndicator::msec2str(long ms) const { int s = ms/1000; const int h = s / 3600; s -= h*3600; const int m = s / 60; s -= m*60; return wxString::Format(wxT("%02d:%02d:%02d"), h, m, s); } void TProgressIndicator::SetRange(int nRange, int nGauge) { wxASSERT(nRange >= 0 && nGauge >= 0 && nGauge < MAX_GAUGES); m_pGauge[nGauge]->SetRange(nRange); } bool TProgressIndicator::SetProgress(int nPos, int nGauge) { if (!IsShown()) return false; wxASSERT(nPos >= 0 && nGauge >= 0 && nGauge < MAX_GAUGES); m_pGauge[nGauge]->SetValue(nPos); const long elap = Elapsed(); if (elap > m_nNextUpdate) { m_nNextUpdate = elap+CLOCKS_PER_SEC; m_pPassed->SetLabel(msec2str(elap)); wxLongLong_t nTotValue = 0, nTotRange = 0; for (int i = 0; i < MAX_GAUGES && m_pGauge[i]; i++) { const int nValue = m_pGauge[i]->GetValue(); const int nRange = m_pGauge[i]->GetRange(); if (nValue < nRange) // Escludi dal calcolo i processi già terminati { nTotValue += nValue; nTotRange += nRange; } } if (nTotValue > 0) { const long est = long(elap * nTotRange / nTotValue); m_pEstimated->SetLabel(msec2str(est)); m_pResidual->SetLabel(msec2str(est-elap)); } wxYield(); } return true; } void TProgressIndicator::SetMessage(wxString msg) { SetLabel(msg); } void TProgressIndicator::Init(wxString msg, int nGauges, bool bCancellable) { const int nGap = 4; wxBoxSizer* pTopSizer = new wxBoxSizer(wxVERTICAL); SetSizer(pTopSizer); memset(m_pGauge, 0, sizeof(m_pGauge)); for (int i = 0; i < nGauges; i++) { m_pGauge[i] = new wxGauge(this, 1001+i, 100, wxDefaultPosition, wxSize(400, -1)); pTopSizer->Add(m_pGauge[i], 0, wxALL, nGap); } wxGridSizer* pTimersSizer = new wxGridSizer(1, 3, nGap, nGap); pTopSizer->Add(pTimersSizer, 0, wxEXPAND); wxStaticBoxSizer* pPassed = new wxStaticBoxSizer(wxVERTICAL, this, _("Elapsed Time")); pTimersSizer->Add(pPassed, 0, wxEXPAND); m_pPassed = new wxStaticText(this, 1101, wxT("00:00:00")); pPassed->Add(m_pPassed, 0, wxALL|wxALIGN_CENTER, 0); wxStaticBoxSizer* pResidual = new wxStaticBoxSizer(wxVERTICAL, this, _("Residual Time")); pTimersSizer->Add(pResidual, 0, wxEXPAND); m_pResidual = new wxStaticText(this, 1102, wxT("00:00:00")); pResidual->Add(m_pResidual, 0, wxALL|wxALIGN_CENTER, 0); wxStaticBoxSizer* pEstimated = new wxStaticBoxSizer(wxVERTICAL, this, _("Estimated Time")); pTimersSizer->Add(pEstimated, 0, wxEXPAND); m_pEstimated = new wxStaticText(this, 1103, wxT("00:00:00")); pEstimated->Add(m_pEstimated, 0, wxALL|wxALIGN_CENTER, 0); wxButton* pCancel = NULL; if (bCancellable) { pCancel = new wxButton(this, wxID_CANCEL, _("Cancel")); pTopSizer->Add(pCancel, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, nGap); } pTopSizer->SetSizeHints(this); SetMessage(msg); Show(); Enable(); Update(); m_nNextUpdate = 0; m_chrono.Start(); } TProgressIndicator::TProgressIndicator(size_t nRange, wxString msg, bool bCancellable) : wxDialog(NULL, wxID_ANY, msg) { Init(msg, 1, bCancellable); SetRange(nRange, 0); } TProgressIndicator::TProgressIndicator(wxString msg, bool bCancellable, int nGauges) : wxDialog(NULL, wxID_ANY, msg) { Init(msg, nGauges, bCancellable); } TProgressIndicator::~TProgressIndicator() { } /////////////////////////////////////////////////////////// // Multiprocess /////////////////////////////////////////////////////////// class TWorker : public wxThread { XVT_MULTITHREAD_CALLBACK m_pFunc; void* m_pCaller; void* m_pData; int m_nFirst, m_nLast, m_nTotal; TProgressIndicator* m_pi; int m_nGauge; protected: virtual ExitCode Entry(); public: TWorker(XVT_MULTITHREAD_CALLBACK func, void* pCaller, void* pData, int nFirst, int nLast, int nTotal, TProgressIndicator* pi, int nGauge); }; wxThread::ExitCode TWorker::Entry() { ExitCode ec = 0; if (m_pi != NULL) { m_pi->SetRange(m_nLast-m_nFirst, m_nGauge); for (int i = m_nFirst; i < m_nLast && ec == 0; i++) { ec = (ExitCode)m_pFunc(m_pCaller, m_pData, i, m_nTotal); if (!m_pi->SetProgress(i-m_nFirst+1, m_nGauge)) ec = ExitCode(-1); } } else { for (int i = m_nFirst; i < m_nLast && ec == 0; i++) ec = (ExitCode)m_pFunc(m_pCaller, m_pData, i, m_nTotal); } return ec; } TWorker::TWorker(XVT_MULTITHREAD_CALLBACK func, void* pCaller, void* pData, int nFirst, int nLast, int nTotal, TProgressIndicator* pi, int nGauge) : wxThread(wxTHREAD_JOINABLE), m_pFunc(func), m_pCaller(pCaller), m_pData(pData), m_nFirst(nFirst), m_nLast(nLast), m_nTotal(nTotal), m_pi(pi), m_nGauge(nGauge) { // SetPriority(WXTHREAD_MIN_PRIORITY); Create(); } BOOLEAN xvt_sys_multithread(XVT_MULTITHREAD_CALLBACK pFunc, void* pCaller, void* pData, int tot, const char* msg) { const int MAX_WORKERS = 16; // Bilanciamento automatico int nWorkers = wxThread::GetCPUCount(); if (nWorkers <= 0) nWorkers = 1; if (nWorkers > tot) nWorkers = tot; if (nWorkers > MAX_WORKERS) nWorkers = MAX_WORKERS; int ret = 0; if (nWorkers > 1) { TProgressIndicator* pi = NULL; if (msg && *msg) pi = new TProgressIndicator(msg, tot > nWorkers, nWorkers); TWorker* worker[MAX_WORKERS]; memset(worker, 0, sizeof(worker)); int nFirst, nLast = 0, w; for (w = 0; w < nWorkers; w++) { nFirst = nLast; nLast = tot*(w+1)/nWorkers; worker[w] = new TWorker(pFunc, pCaller, pData, nFirst, nLast, tot, pi, w); } for (w = 0; w < nWorkers; w++) worker[w]->Run(); if (pi != NULL) pi->Refresh(); for (w = 0; w < nWorkers; w++) { const wxThread::ExitCode r = worker[w]->Wait(); if (ret == 0 && r != 0) ret = int(r); delete worker[w]; worker[w] = NULL; } if (pi != NULL) delete pi; } else { if (msg && *msg) { TProgressIndicator pi(size_t(tot), msg, tot > nWorkers); for (int i = 0; i < tot && ret == 0; i++) { ret = pFunc(pCaller, pData, i, tot); if (!pi.SetProgress(i+1)) ret = -1; } } else { for (int i = 0; i < tot && ret == 0; i++) ret = pFunc(pCaller, pData, i, tot); } } return ret; }