%% options copyright owner = Dirk Krause copyright year = 2012 license = bsd %% wx-gui type = frame icon = dkicon_bitmap menu bar = mbMain tool bar = tbMain contents = mainSizer [wxMenuBar mbMain] contents = mFile contents = mView contents = mHelp [wxMenu mFile] text = sTexts[3] contents = miExit [wxMenuItem miExit] text = sTexts[5] tip = sTexts[8] id = DkWxPrintqdc_Quit [wxMenu mView] text = sTexts[4] contents = miUpdate [wxMenuItem miUpdate] text = sTexts[6] tip = sTexts[7] id = DkWxPrintqdc_Update [wxMenu mHelp] text = sTexts[34] contents = miHelp contents = miAbout [wxMenuItem miHelp] text = sTexts[35] tip = sTexts[37] id = DkWxPrintqdc_Help [wxMenuItem miAbout] text = sTexts[36] tip = sTexts[38] id = DkWxPrintqdc_About [wxToolBar tbMain] contents = bUpdate contents = bExit [wxToolBarToolBase bUpdate] text = sTexts[32] tip = sTexts[7] bitmap = xpm_run_conversion id = DkWxPrintqdc_Update [wxToolBarToolBase bExit] text = sTexts[33] tip = sTexts[8] bitmap = xpm_exit_program id = DkWxPrintqdc_Quit [wxBoxSizer mainSizer] direction = horizontal contents = $space(5) contents = verticalSizer contents = $space(5) [wxBoxSizer verticalSizer] direction = vertical contents = $space(5) contents = contentsSizer left contents = $space(5) [wxGridBagSizer contentsSizer] grid = 5 5 contents = lLimit 0 0 1 1 right contents = tLimit . +1 1 1 contents = lUsed +1 0 1 1 right contents = tUsed . +1 1 1 contents = lAccount +1 0 1 1 right contents = tAccount . +1 1 1 contents = $space(5) +1 0 1 1 contents = lAllowed +1 0 1 1 right contents = tAllowed . +1 1 1 contents = $space(5) +1 0 1 1 contents = lStatus +1 0 1 2 [wxStaticText lLimit] text = sTexts[9] [wxStaticText tLimit] text = sTexts[31] [wxStaticText lUsed] text = sTexts[10] [wxStaticText tUsed] text = sTexts[31] [wxStaticText lAccount] text = sTexts[11] [wxStaticText tAccount] text = sTexts[31] [wxStaticText lStatus] text = sTexts[12] [wxStaticText lAllowed] text = sTexts[13] [wxStaticText tAllowed] text = sTexts[31] %% header start %% class start /** Main window class for the wxpqdic program. */ class DkWxPrintqdcFrame : public DkWxFrame { private: /** Event table. */ DECLARE_EVENT_TABLE() protected: /** The worker thread. */ wxThread *thr; /** Timer for periodic update. */ wxTimer timer; /** Mutex to protect bRunning and quotaData. */ wxMutex mProtectData; /** Text colour: black. */ wxColour cBlack; /** Text colour: green. */ wxColour cGreen; /** Text colour: red: */ wxColour cRed; /** Data retrieved by background thread. */ wxpqdic_t quotaData; /** Localized message texts. */ wxChar const * const *sTexts; /** Request to send to server. */ char const *pRequest; /** Host to connect to. */ dkChar const *pHostname; /** Port number to connect to. */ unsigned short iPortnumber; /** Update interval. */ int iUpdateInterval; /** Error code of last non-thread error occured. */ int ec; /** Flag: A background thread is currently running. */ bool bRunning; /** Flag: A background thread was seen in previous check. */ bool bLastRunning; /** Flag: No idle event was processed yet. */ bool bFirstIdle; %% class end protected: public: /** Constructor. @param applicationName Application name. @param localizedMessages Localized message texts. @param applicationHelper Application helper object. @param wxid Window ID. @param argc Number of command line arguments. @param argv Command line arguments array. @param phc Help controller. */ DkWxPrintqdcFrame( wxChar const *applicationName, wxChar const * const *localizedMessages, DkWxAppHelper *applicationHelper, int wxid, int argc, wxChar **argv, DkWxHelpController *phc ); /** Destructor. */ ~DkWxPrintqdcFrame(); /** Check whether we can close the window. @param isLast Flag: Last window of application. @return True to close, false to prevent closing. */ bool canClose(bool isLast); /** Initialize member variables. @param argc Number of command line arguments. @param argv Command line arguments array. */ void initializeMembers(int argc, wxChar **argv); /** Handler for Quit event. @param event Event to process. */ void OnQuit(wxCommandEvent & event); /** Handler for Update event. @param event Event to process. */ void OnUpdate(wxCommandEvent & event); /** Handler for timer event. @param event Timer event to process. */ void OnTimer(wxTimerEvent & event); /** Handler for idle event. @param event Idle event to process. */ void OnIdle(wxIdleEvent & event); /** Show results from background thread. */ void showResults(); /** Start a new thread if possible. */ void startThreadIfPossible(); /** Check whether we currently have a background thread running. @return True if a thread is running, false otherwise. */ bool isRunning(); /** Set flag for background thread running. @param v New flag value. */ void setRunning(bool v); /** Convert dkChar string to char. @param dp Destination buffer pointer. @param sz Size of destination buffer. @param src Source string. @return True on success, false on error. */ bool convertWxToC8( char *dp, size_t sz, wxString & src ); /** Set results from thread. @param res Results to set. */ void setThreadResult(wxpqdic_t *res); /** Set a static text to the given value. @param wxst Text label to change. @param val Numeric value to show. */ void setTextUnsignedLong(wxStaticText *wxst, unsigned long val); /** Show error status in error code. @param ec Error code to show. */ void showErrorStatus(int ec); /** Show about dialog box. @param event Event to process. */ void OnAbout(wxCommandEvent & event); /** Show help text. @param event Event to process. */ void OnHelp(wxCommandEvent & event); }; %% header end %% module start #include "dkwxpqdc.h" #include "dkicon.xpm" #include "exit-program.xpm" #include "run-conversion.xpm" $!trace-include static wxChar const wxpqdi_version[] = { wxT("wxpqdic (part of dkt-") }; static wxChar const wxpqdi_versnumber[] = { DKT_WXCHAR_VERSION }; static wxChar const wxpqdi_versend[] = { wxT(")") }; static const wxCmdLineEntryDesc wxpqdic_cmd_line_entries[] = { { wxCMD_LINE_OPTION, wxT_2("h"), wxT_2("host"), wxT_2("Host to connect to."), wxCMD_LINE_VAL_STRING }, { wxCMD_LINE_OPTION, wxT_2("p"), wxT_2("port"), wxT_2("Port number to connect to."), wxCMD_LINE_VAL_NUMBER }, { wxCMD_LINE_OPTION, wxT_2("q"), wxT_2("queue"), wxT_2("Queue name to check."), wxCMD_LINE_VAL_STRING }, { wxCMD_LINE_OPTION, wxT_2("u"), wxT_2("user"), wxT_2("User name to check."), wxCMD_LINE_VAL_STRING }, { wxCMD_LINE_OPTION, wxT_2("i"), wxT_2("interval"), wxT_2("Time interval for automatic update."), wxCMD_LINE_VAL_NUMBER }, { wxCMD_LINE_NONE } }; /** Event table for main window. */ BEGIN_EVENT_TABLE(DkWxPrintqdcFrame,wxFrame) EVT_MENU(DkWxPrintqdc_Quit, DkWxPrintqdcFrame::OnQuit) EVT_MENU(DkWxPrintqdc_Update, DkWxPrintqdcFrame::OnUpdate) EVT_MENU(DkWxPrintqdc_Help, DkWxPrintqdcFrame::OnHelp) EVT_MENU(DkWxPrintqdc_About, DkWxPrintqdcFrame::OnAbout) EVT_TIMER(DkWxPrintqdc_Timer, DkWxPrintqdcFrame::OnTimer) EVT_IDLE(DkWxPrintqdcFrame::OnIdle) END_EVENT_TABLE() %% constructor start DkWxPrintqdcFrame::DkWxPrintqdcFrame( wxChar const *applicationName, wxChar const * const *localizedMessages, DkWxAppHelper *applicationHelper, int wxid, int argc, wxChar **argv, DkWxHelpController *phc ) : DkWxFrame(applicationName, applicationHelper, phc, wxid), timer(this, DkWxPrintqdc_Timer), mProtectData(wxMUTEX_DEFAULT), cBlack(0, 0, 0), cGreen(0, 127, 0), cRed(127, 0, 0) { /* Icon for main window. */ #if defined(__WXMSW__) wxIcon dkicon_bitmap(wxT("aaaaa")); #else wxIcon dkicon_bitmap(xpm_dkicon); #endif /* Initialize all members. */ thr = NULL; pRequest = NULL; pHostname = NULL; iPortnumber = 0; iUpdateInterval = 15; ec = 0; dk3mem_res((void *)("aData), sizeof(wxpqdic_t)); bRunning = false; bLastRunning = false; /* Save constructor arguments. */ sTexts = localizedMessages; %% constructor end /* Set Window title. */ SetTitle(sTexts[1]); /* Restore position from previous run. */ initializeMembers(argc, argv); restorePosition(); bFirstIdle = true; } %% module end /** Keywords in dkChar. */ static dkChar const * const wxpqdi_dk_kw[] = { $!string-table macro=dkT # # 0 Preference name start: Allowed to change user. # /printqd/user-change/ # # 1 Preference name: Remote host to connect. # /printqd/host # # 2 Preference name: Remote port to connect. # /printqd/port # # 3 Preference name: Queue name to check. # /printqd/queue # # 4 Interval for auto update. # /printqd/interval $!end }; /** 8-bit characters keywords used by the module. */ static char const * const wxpqdi_c8_kw[] = { $!string-table # # 0 # info # # 1 # # # 2 # \n $!end }; void DkWxPrintqdcFrame::initializeMembers(int argc, wxChar **argv) { char c8un[WXPQDI_USER_NAME_SIZE]; /* User name. */ char c8qn[sizeof(c8un)]; /* Queue name. */ dkChar c8hn[sizeof(c8un)]; /* Host name. */ dkChar pn[16+sizeof(c8un)]; /* Preference name. */ dkChar pv[32]; /* Preference value. */ wxCmdLineParser parser(wxpqdic_cmd_line_entries, argc, argv); dk3_app_t *app; dkChar const *dkptr; dkChar *pvptr; /* Start of pv. */ char *rq; /* Request data. */ size_t sl; /* String length. */ int ie; /* Input encoding. */ int se; /* File encoding. */ int res; /* Conversion result. */ int atcu; /* Allowed to change. */ int updi; /* Update interval. */ unsigned u; /* Used for sscanf. */ $? "+ DkWxPrintqdcFrame::initializeMembers" c8un[0] = '\0'; c8qn[0] = '\0'; c8hn[0] = dkT('\0'); atcu = 0; app = pHelper->getApp(); if(app) { ie = dk3app_get_encoding(app); se = dk3app_get_input_stdin_encoding(app); /* Find user name. */ dkptr = dk3app_get_logname(app); if(dkptr) { if(!dk3str_to_c8_app(c8un, sizeof(c8un), dkptr, app)) { c8un[0] = '\0'; } if((dk3str_len(wxpqdi_dk_kw[0])+dk3str_len(dkptr)) (unsigned)(DK3_US_MAX)) #endif { /* Overflow */ iPortnumber = 0; } } } /* Find queue name. */ if(dk3app_get_pref(app, wxpqdi_dk_kw[3], pv, DK3_SIZEOF(pv,dkChar))) { if(!(dk3str_to_c8_app(c8qn, sizeof(c8qn), pv, app))) { c8qn[0] = '\0'; } } /* Find auto update interval */ if(dk3app_get_pref(app, wxpqdi_dk_kw[4], pv, DK3_SIZEOF(pv,dkChar))) { #if VERSION_BEFORE_20140716 if(1 == dk3sf_sscanf3(pv, dkT("%i"), &updi)) #else if(dk3ma_i_from_string(&updi, pv, NULL)) #endif { iUpdateInterval = updi; } } } res = -1; { wxLogNull log; res = parser.Parse(false); } if(0 == res) { long l; wxString sHost(wxT("")); wxString sQueue(wxT("")); wxString sUser(wxT("")); if(parser.Found(wxT_2("h"), &sHost)) { if(!(pHelper->wxToDk(c8hn, DK3_SIZEOF(c8hn,dkChar), sHost))) { c8hn[0] = dkT('\0'); } } if(parser.Found(wxT_2("p"), &l)) { iPortnumber = (unsigned short)((unsigned long)l); } if(parser.Found(wxT_2("q"), &sQueue)) { pHelper->wxToC8(c8qn, sizeof(c8qn), sQueue); } if(atcu) { if(parser.Found(wxT_2("u"), &sUser)) { pHelper->wxToC8(c8un, sizeof(c8un), sUser); } } if(parser.Found(wxT_2("i"), &l)) { iUpdateInterval = (int)l; } } $? ". host = \"%s\"", c8hn $? ". port = %u", (unsigned)iPortnumber $? ". user = \"%s\"", c8un $? ". queue = \"%s\"", c8qn if(dk3str_len(c8hn) > 0) { $? ". host lgt = %u", (unsigned)dk3str_len(c8hn) pHostname = dk3str_dup_app(c8hn, app); if(pHostname) { $? ". host lgt = %u", (unsigned)dk3str_len(pHostname) if(iPortnumber > 0) { if(strlen(c8un) > 0) { $? ". user lgt = %u", (unsigned)strlen(c8un) if(strlen(c8qn) > 0) { $? ". queue lgt = %u", (unsigned)strlen(c8qn) sl = 4 + strlen(c8un) + strlen(c8qn) + strlen(wxpqdi_c8_kw[0]); rq = dk3_new_app(char,sl,app); if(rq) { strcpy(rq, wxpqdi_c8_kw[0]); strcat(rq, wxpqdi_c8_kw[1]); strcat(rq, c8qn); strcat(rq, wxpqdi_c8_kw[1]); strcat(rq, c8un); strcat(rq, wxpqdi_c8_kw[2]); pRequest = (char const *)rq; } else { ec = WXPQDIC_ERROR_MEMORY; } } else { ec = WXPQDIC_ERROR_NO_QUEUE_NAME; } } else { ec = WXPQDIC_ERROR_NO_USER_NAME; } } else { ec = WXPQDIC_ERROR_NO_PORT_NUMBER; } } else { ec = WXPQDIC_ERROR_NO_HOST_NAME; } } else { ec = WXPQDIC_ERROR_NO_HOST_NAME; } if(ec) { showErrorStatus(ec); Refresh(); Update(); } $? "- DkWxPrintqdcFrame::initializeMembers" } bool DkWxPrintqdcFrame::isRunning() { bool back = false; $? "+ DkWxPrintqdcFrame::isRunning" { wxMutexLocker lock(mProtectData); if(lock.IsOk()) { back = bRunning; } }$? "- DkWxPrintqdcFrame::isRunning %d", (back ? 1 : 0) return back; } void DkWxPrintqdcFrame::setRunning(bool v) { $? "+ DkWxPrintqdcFrame::setRunning" wxMutexLocker lock(mProtectData); if(lock.IsOk()) { bRunning = v; } $? "- DkWxPrintqdcFrame::setRunning" } void DkWxPrintqdcFrame::setThreadResult(wxpqdic_t *res) { wxMutexLocker lock(mProtectData); if(lock.IsOk()) { thr = NULL; bRunning = false; dk3mem_cpy((void *)("aData), (void *)res, sizeof(wxpqdic_t)); } } void DkWxPrintqdcFrame::setTextUnsignedLong(wxStaticText *wxst, unsigned long val) { char bu[64]; wxChar wbu[64]; if(wxst) { sprintf(bu, "%lu", val); if(dk3wxs_from_plain(wbu, DK3_SIZEOF(wbu,wxChar), bu)) { wxst->SetLabel(wbu); } else { wxst->SetLabel(sTexts[2]); } } } void DkWxPrintqdcFrame::showErrorStatus(int ec) { int i; /* Index in sTexts */ i = 2; if(lStatus) { switch(ec) { case WXPQDIC_ERROR_INIT: { i = 17; } break; case WXPQDIC_ERROR_NO_USER_NAME: { i = 18; } break; case WXPQDIC_ERROR_NO_HOST_NAME: { i = 19; } break; case WXPQDIC_ERROR_NO_PORT_NUMBER: { i = 20; } break; case WXPQDIC_ERROR_NO_QUEUE_NAME: { i = 21; } break; case WXPQDIC_ERROR_MEMORY: { i = 22; } break; case WXPQDIC_ERROR_NO_REQUEST: { i = 23; } break; case WXPQDIC_ERROR_CONNECT_FAILED: { i = 24; } break; case WXPQDIC_ERROR_SEND_FAILED: { i = 25; } break; case WXPQDIC_ERROR_SHUTDOWN: { i = 25; } break; case WXPQDIC_ERROR_NO_RESPONSE: { i = 26; } break; case WXPQDIC_ERROR_INVALID_RESPONSE: { i = 27; } break; } lStatus->SetLabel(sTexts[i]); if(WXPQDIC_ERROR_NONE == ec) { lStatus->SetForegroundColour(cBlack); } else { lStatus->SetForegroundColour(cRed); } } } void DkWxPrintqdcFrame::showResults() { wxpqdic_t data; int found; $? "+ DkWxPrintqdcFrame::showResults" found = 0; dk3mem_res((void *)(&data), sizeof(wxpqdic_t)); { wxMutexLocker lock(mProtectData); if(lock.IsOk()) { dk3mem_cpy((void *)(&data), (void *)("aData), sizeof(wxpqdic_t)); found = 1; } } if(found) { /* ##### */ if(data.ec) { if(tLimit) { tLimit->SetLabel(sTexts[2]); } if(tUsed) { tUsed->SetLabel(sTexts[2]); } if(tAccount) { tAccount->SetLabel(sTexts[2]); } if(tAllowed) { tAllowed->SetLabel(sTexts[2]); tAllowed->SetForegroundColour(cBlack); } showErrorStatus(data.ec); } else { if(2 == data.lt) { if(tLimit) { tLimit->SetLabel(sTexts[14]); } } else { setTextUnsignedLong(tLimit, data.li); } setTextUnsignedLong(tUsed, data.pa); setTextUnsignedLong(tAccount, data.ac); if(tAllowed) { tAllowed->SetLabel(sTexts[(data.su) ? 15 : 16]); if(data.su) { tAllowed->SetForegroundColour(cGreen); } else { tAllowed->SetForegroundColour(cRed); } } if(lStatus) { lStatus->SetLabel(sTexts[2]); } } } else { if(tLimit) { tLimit->SetLabel(sTexts[2]); } if(tUsed) { tUsed->SetLabel(sTexts[2]); } if(tAccount) { tAccount->SetLabel(sTexts[2]); } if(tAllowed) { tAllowed->SetLabel(sTexts[2]); tAllowed->SetForegroundColour(cBlack); } if(lStatus) { tAllowed->SetLabel(sTexts[2]); } } Refresh(); Update(); $? "- DkWxPrintqdcFrame::showResults" } void DkWxPrintqdcFrame::startThreadIfPossible() { DkWxPrintqdcThread *newThread; /* Background thread. */ int iStatusText = 0; /* New status text to show. */ wxThreadError runres; /* Result from run. */ $? "+ DkWxPrintqdcFrame::startThreadIfPossible" if(0 == ec) { wxMutexLocker lock(mProtectData); if(lock.IsOk()) { if(!(bRunning)) { newThread = new DkWxPrintqdcThread( this, pHelper->getApp(), pRequest, pHostname, iPortnumber ); if(newThread) { if(wxTHREAD_NO_ERROR == newThread->Create()) { newThread->SetPriority(WXTHREAD_DEFAULT_PRIORITY); thr = (wxThread *)newThread; bRunning = true; bLastRunning = true; iStatusText = 28; runres = newThread->Run(); $? ". runres = %d", (int)runres } else { iStatusText = 30; delete(newThread); } } else { iStatusText = 29; } } } } if(iStatusText) { if(lStatus) { lStatus->SetLabel(sTexts[iStatusText]); switch(iStatusText) { case 28: { lStatus->SetForegroundColour(cBlack); } break; default: { lStatus->SetForegroundColour(cRed); } break; } Refresh(); Update(); } } $? "- DkWxPrintqdcFrame::startThreadIfPossible" } DkWxPrintqdcFrame::~DkWxPrintqdcFrame() { $? "+ DkWxPrintqdcFrame::~DkWxPrintqdcFrame" dk3_release(pRequest); dk3_release(pHostname); $? "- DkWxPrintqdcFrame::~DkWxPrintqdcFrame" } void DkWxPrintqdcFrame::OnQuit(wxCommandEvent & event) { $? "+ DkWxPrintqdcFrame::OnQuit" timer.Stop(); Show(false); Close(); $? "- DkWxPrintqdcFrame::OnQuit" } void DkWxPrintqdcFrame::OnUpdate(wxCommandEvent & event) { $? "+ DkWxPrintqdcFrame::OnUpdate" startThreadIfPossible(); $? "- DkWxPrintqdcFrame::OnUpdate" } void DkWxPrintqdcFrame::OnTimer(wxTimerEvent & event) { $? "+ DkWxPrintqdcFrame::OnTimer" startThreadIfPossible(); $? "- DkWxPrintqdcFrame::OnTimer" } void DkWxPrintqdcFrame::OnHelp(wxCommandEvent & event) { openHelp(); } void DkWxPrintqdcFrame::OnAbout(wxCommandEvent & event) { wxString sVersion(wxpqdi_version); sVersion.Append(wxpqdi_versnumber); sVersion.Append(wxpqdi_versend); sVersion.Append(sTexts[40]); sVersion.Append(wxT("Copyright (c) 2013 Dirk Krause")); sVersion.Append(sTexts[40]); sVersion.Append(sTexts[40]); sVersion.Append(sTexts[41]); sVersion.Append(wxT("DK tools, wxWidgets, libpng, libjpeg, libtiff, zlib.")); sVersion.Append(sTexts[40]); sVersion.Append(sTexts[40]); sVersion.Append(sTexts[42]); sVersion.Append(wxT("http://dktools.sourceforge.net\n")); sVersion.Append(wxT("http://www.wxwidgets.org\n")); sVersion.Append(wxT("http://www.libpng.org/pub/png/libpng.html\n")); sVersion.Append(wxT("http://www.ijg.org\n")); sVersion.Append(wxT("http://www.remotesensing.org/libtiff\n")); sVersion.Append(wxT("http://www.zlib.org")); wxMessageBox(sVersion, sTexts[39]); } void DkWxPrintqdcFrame::OnIdle(wxIdleEvent & event) { $? "+ DkWxPrintqdcFrame::OnIdle" if(isRunning()) { $? ". is running" bLastRunning = true; event.RequestMore(); } else { $? ". not running" if(bLastRunning) { $? ". changed from running to idle" showResults(); } bLastRunning = false; if(bFirstIdle) { $? ". first time idle" bFirstIdle = false; startThreadIfPossible(); if(0 == ec) { if(iUpdateInterval < 5) { iUpdateInterval = 5; } timer.Start(1000 * iUpdateInterval, wxTIMER_CONTINUOUS); } } } $? "- DkWxPrintqdcFrame::OnIdle" event.Skip(); } bool DkWxPrintqdcFrame::canClose(bool isLast) { { wxMutexLocker lock(mProtectData); if(lock.IsOk()) { if(bRunning) { if(thr) { thr->Kill(); bRunning = false; thr = NULL; } } } } return(true); }