1 /***************************************************************************
2                           tqslwiz.cpp  -  description
3                              -------------------
4     begin                : Tue Nov 5 2002
5     copyright            : (C) 2002 by ARRL
6     author               : Jon Bloom
7     email                : jbloom@arrl.org
8     revision             : $Id: tqslwiz.cpp,v 1.6 2013/03/01 13:12:57 k1mu Exp $
9  ***************************************************************************/
10 
11 #include "tqslwiz.h"
12 #include <wx/tokenzr.h>
13 #ifdef HAVE_CONFIG_H
14 #include "sysconfig.h"
15 #endif
16 
17 #include <string>
18 using std::string;
19 
20 #include "wxutil.h"
21 #include "tqsltrace.h"
22 #include "winstrdefs.h"
23 
24 extern int get_address_field(const char *callsign, const char *field, string& result);
25 
26 #define TQSL_LOCATION_FIELD_UPPER	1
27 #define TQSL_LOCATION_FIELD_MUSTSEL	2
28 #define TQSL_LOCATION_FIELD_SELNXT	4
29 
30 BEGIN_EVENT_TABLE(TQSLWizard, wxWizard)
31 	EVT_WIZARD_PAGE_CHANGED(-1, TQSLWizard::OnPageChanged)
32 END_EVENT_TABLE()
33 
34 BEGIN_EVENT_TABLE(TQSLWizCertPage, TQSLWizPage)
35 	EVT_COMBOBOX(-1, TQSLWizCertPage::OnComboBoxEvent)
36 	EVT_CHECKBOX(-1, TQSLWizCertPage::OnCheckBoxEvent)
37 	EVT_WIZARD_PAGE_CHANGING(wxID_ANY, TQSLWizCertPage::OnPageChanging)
38 #if wxMAJOR_VERSION < 3 && (wxMAJOR_VERSION != 2 && wxMINOR_VERSION != 9)
39 	EVT_SIZE(TQSLWizCertPage::OnSize)
40 #endif
41 END_EVENT_TABLE()
42 
43 static char callsign[TQSL_CALLSIGN_MAX];
44 
45 void
OnPageChanged(wxWizardEvent & ev)46 TQSLWizard::OnPageChanged(wxWizardEvent& ev) {
47 	tqslTrace("TQSLWizard::OnPageChanged", NULL);
48 	(reinterpret_cast<TQSLWizPage *>(GetCurrentPage()))->SetFocus();
49 	ExtWizard::OnPageChanged(ev);
50 }
51 
TQSLWizard(tQSL_Location locp,wxWindow * parent,wxHtmlHelpController * help,const wxString & title,bool expired)52 TQSLWizard::TQSLWizard(tQSL_Location locp, wxWindow *parent, wxHtmlHelpController *help,
53 	const wxString& title, bool expired)
54 	: ExtWizard(parent, help, title), loc(locp), _curpage(-1) {
55 	tqslTrace("TQSLWizard::TQSLWizard", "locp=0x%lx, parent=0x%lx, title=%s, expired=%d", reinterpret_cast<void *>(locp), reinterpret_cast<void *>(parent), S(title), expired);
56 
57 	callsign[0] = '\0';
58 	char buf[256];
59 	if (!tqsl_getStationLocationCaptureName(locp, buf, sizeof buf)) {
60 		wxString s = wxString::FromUTF8(buf);
61 		SetLocationName(s);
62 	}
63 	tqsl_setStationLocationCertFlags(locp, expired ? TQSL_SELECT_CERT_WITHKEYS | TQSL_SELECT_CERT_EXPIRED : TQSL_SELECT_CERT_WITHKEYS);
64 	tqsl_setStationLocationCapturePage(locp, 1);
65 }
66 
67 TQSLWizPage *
GetPage(bool final)68 TQSLWizard::GetPage(bool final) {
69 	tqslTrace("TQSLWizard::GetPage", "final=%d", final);
70 	int page_num;
71 	if (final)
72 		page_num = 0;
73 	else if (tqsl_getStationLocationCapturePage(loc, &page_num))
74 		return 0;
75 	tqslTrace("TQSLWizard::GetPage", "page_num = %d", page_num);
76 	if (_pages[page_num]) {
77 		if (page_num == 0)
78 			(reinterpret_cast<TQSLWizFinalPage *>(_pages[0]))->prev = GetCurrentTQSLPage();
79 		return _pages[page_num];
80 	}
81 	if (page_num == 0)
82 		_pages[page_num] = new TQSLWizFinalPage(this, loc, GetCurrentTQSLPage());
83 	else
84 		_pages[page_num] = new TQSLWizCertPage(this, loc);
85 	_curpage = page_num;
86 	if (page_num == 0)
87 		(reinterpret_cast<TQSLWizFinalPage *>(_pages[0]))->prev = GetCurrentTQSLPage();
88 	return _pages[page_num];
89 }
90 
OnSize(wxSizeEvent & ev)91 void TQSLWizCertPage::OnSize(wxSizeEvent& ev) {
92 #if wxMAJOR_VERSION < 3 && (wxMAJOR_VERSION != 2 && wxMINOR_VERSION != 9)
93 	TQSLWizPage::OnSize(ev);
94 #endif
95 	UpdateFields();
96 }
97 
98 TQSLWizPage *
GetPrev() const99 TQSLWizCertPage::GetPrev() const {
100 	tqslTrace("TQSLWizCertPage::GetPrev", NULL);
101 	int rval;
102 
103 	tqsl_setStationLocationCapturePage(loc, loc_page);
104 	if (tqsl_hasPrevStationLocationCapture(loc, &rval) || !rval) {
105 		return 0;
106 	}
107 	tqsl_prevStationLocationCapture(loc);
108 	return GetParent()->GetPage();
109 }
110 
111 TQSLWizPage *
GetNext() const112 TQSLWizCertPage::GetNext() const {
113 	tqslTrace("TQSLWizCertPage::GetNext", NULL);
114 	TQSLWizPage *newp;
115 	bool final = false;
116 	int rval;
117 
118 	tqsl_setStationLocationCapturePage(loc, loc_page);
119 	if (!tqsl_hasNextStationLocationCapture(loc, &rval) && rval) {
120 		tqsl_nextStationLocationCapture(loc);
121 	} else {
122 		final = true;
123 	}
124 	newp = GetParent()->GetPage(final);
125 	if (!final) {
126 		reinterpret_cast<TQSLWizCertPage*>(newp)->UpdateFields();
127 	}
128 	return newp;
129 }
130 
131 void
UpdateFields(int noupdate_field)132 TQSLWizCertPage::UpdateFields(int noupdate_field) {
133 	tqslTrace("TQSLWizCertPage::UpdateFields", "noupdate_field=%d", noupdate_field);
134 	wxSize text_size = getTextSize(this);
135 
136 	validate();
137 	if (noupdate_field >= 0)
138 		tqsl_updateStationLocationCapture(loc);
139 	for (int i = noupdate_field+1; i < static_cast<int>(controls.size()); i++) {
140 		int changed;
141 		int in_type;
142 		char gabbi_name[40];
143 		tqsl_getLocationFieldChanged(loc, i, &changed);
144 		tqsl_getLocationFieldInputType(loc, i, &in_type);
145 		tqsl_getLocationFieldDataGABBI(loc, i, gabbi_name, sizeof gabbi_name);
146 
147 		ForcedMap::iterator it;
148 		it = forced.find(gabbi_name);
149 		if (it != forced.end()) {		// Something set
150 			if (it->second != callsign) {	// For a different call
151 				if (in_type == TQSL_LOCATION_FIELD_DDLIST || in_type == TQSL_LOCATION_FIELD_LIST) {
152 					tqsl_setLocationFieldIndex(loc, i, 0);
153 					(reinterpret_cast<wxComboBox *>(controls[i]))->SetSelection(0);
154 				} else {
155 					tqsl_setLocationFieldCharData(loc, i, "");
156 					(reinterpret_cast<wxTextCtrl *>(controls[i]))->SetValue(wxT(""));
157 				}
158 				forced.erase(it);
159 			}
160 		}
161 		char buf[256];
162 		string s;
163 		tqsl_getLocationFieldCharData(loc, i, buf, sizeof buf);
164 		if (strlen(buf) == 0) { // Empty
165 			if (strcmp(gabbi_name, "GRIDSQUARE") == 0) {
166 				if (get_address_field(callsign, "grid", s) == 0) {	// Got something
167 					tqsl_setLocationFieldCharData(loc, i, s.c_str());
168 					 (reinterpret_cast<wxTextCtrl *>(controls[i]))->SetValue(wxString::FromUTF8(s.c_str()));
169 					forced[gabbi_name] = callsign;
170 				}
171 			}
172 			if (strcmp(gabbi_name, "US_STATE") == 0 ||
173 			    strcmp(gabbi_name, "JA_PREFECTURE") == 0 ||
174 			    strcmp(gabbi_name, "RU_OBAST") == 0 ||
175 			    strcmp(gabbi_name, "CA_PROVINCE") == 0 ||
176 			    strcmp(gabbi_name, "CN_PROVINCE") == 0 ||
177 			    strcmp(gabbi_name, "FI_KUNTA") == 0 ||
178 			    strcmp(gabbi_name, "AU_STATE") == 0) {
179 				if (get_address_field(callsign, "state", s) == 0 || get_address_field(callsign, "pas", s) == 0) {
180 					tqsl_setLocationFieldCharData(loc, i, s.c_str());
181 					int new_sel;
182 					tqsl_getLocationFieldIndex(loc, i, &new_sel);
183 					(reinterpret_cast<wxComboBox *>(controls[i]))->SetSelection(new_sel);
184 					forced[gabbi_name] = callsign;
185 					UpdateFields(i);
186 				}
187 			}
188 
189 			if (strcmp(gabbi_name, "US_COUNTY") == 0 ||
190 			    strcmp(gabbi_name, "JA_CITY_GUN_KU") == 0) {
191 				if (get_address_field(callsign, "county", s) == 0 || get_address_field(callsign, "sas", s) == 0) {
192 					tqsl_setLocationFieldCharData(loc, i, s.c_str());
193 					int new_sel;
194 					tqsl_getLocationFieldIndex(loc, i, &new_sel);
195 					(reinterpret_cast<wxComboBox *>(controls[i]))->SetSelection(new_sel);
196 					forced[gabbi_name] = callsign;
197 					UpdateFields(i);
198 				}
199 			}
200 		}
201 		if (noupdate_field >= 0 && !changed && in_type != TQSL_LOCATION_FIELD_BADZONE)
202 			continue;
203 		if (in_type == TQSL_LOCATION_FIELD_DDLIST || in_type == TQSL_LOCATION_FIELD_LIST) {
204 			// Update this list
205 			char gabbi_name[40];
206 			tqsl_getLocationFieldDataGABBI(loc, i, gabbi_name, sizeof gabbi_name);
207 			int selected;
208 			bool defaulted = false;
209 			tqsl_getLocationFieldIndex(loc, i, &selected);
210 			int new_sel = 0;
211 			wxString old_sel = (reinterpret_cast<wxComboBox *>(controls[i]))->GetStringSelection();
212 			if (old_sel.IsEmpty() && strcmp(gabbi_name, "CALL") == 0) {
213 				old_sel = (reinterpret_cast<TQSLWizard*>(GetParent()))->GetDefaultCallsign();
214 				if (!old_sel.IsEmpty())
215 					defaulted = true;		// Set from default
216 			}
217 			(reinterpret_cast<wxComboBox *>(controls[i]))->Clear();
218 			int nitems;
219 			tqsl_getNumLocationFieldListItems(loc, i, &nitems);
220 			for (int j = 0; j < nitems && j < 2000; j++) {
221 				char item[200];
222 				tqsl_getLocationFieldListItem(loc, i, j, item, sizeof(item));
223 				// Translate the first [None] entry if it exists
224 #ifdef tqsltranslate
225 				__("[None]");
226 #endif
227 				wxString item_text = wxString::FromUTF8(item);
228 				if (item_text == old_sel)
229 					new_sel = j;
230 				if (j == 0)
231 					item_text = wxGetTranslation(item_text);
232 				(reinterpret_cast<wxComboBox *>(controls[i]))->Append(item_text);
233 			}
234 			if (noupdate_field < 0 && !defaulted)
235 				new_sel = selected;
236 			if (nitems > new_sel)
237 				(reinterpret_cast<wxComboBox *>(controls[i]))->SetSelection(new_sel);
238 			tqsl_setLocationFieldIndex(loc, i, new_sel);
239 			if (nitems > new_sel)
240 				(reinterpret_cast<wxComboBox *>(controls[i]))->SetSelection(new_sel);
241 			(reinterpret_cast<wxComboBox *>(controls[i]))->Enable(nitems > 1);
242 		} else if (in_type == TQSL_LOCATION_FIELD_TEXT) {
243 			int len;
244 			tqsl_getLocationFieldDataLength(loc, i, &len);
245 			int w, h;
246 			(reinterpret_cast<wxTextCtrl *>(controls[i]))->GetSize(&w, &h);
247 			(reinterpret_cast<wxTextCtrl *>(controls[i]))->SetSize((len+1)*text_size.GetWidth(), h);
248 			if (noupdate_field < 0) {
249 				char buf[256];
250 				tqsl_getLocationFieldCharData(loc, i, buf, sizeof buf);
251 				(reinterpret_cast<wxTextCtrl *>(controls[i]))->SetValue(wxString::FromUTF8(buf));
252 			}
253 		} else if (in_type == TQSL_LOCATION_FIELD_BADZONE) {
254 			int len;
255 			tqsl_getLocationFieldDataLength(loc, i, &len);
256 			int w, h;
257 			(reinterpret_cast<wxStaticText *>(controls[i]))->GetSize(&w, &h);
258 			(reinterpret_cast<wxStaticText *>(controls[i]))->SetSize((len+1)*text_size.GetWidth(), h);
259 			char buf[256];
260 			tqsl_getLocationFieldCharData(loc, i, buf, sizeof buf);
261 			if (strlen(buf) > 0)
262 				valMsg = wxGetTranslation(wxString::FromUTF8(buf));
263 			else
264 				valMsg = wxT("");
265 			(reinterpret_cast<wxStaticText *>(controls[i]))->SetLabel(valMsg);
266 		}
267 	}
268 	if (noupdate_field >= 0)
269 		tqsl_updateStationLocationCapture(loc);
270 }
271 
272 void
OnComboBoxEvent(wxCommandEvent & event)273 TQSLWizCertPage::OnComboBoxEvent(wxCommandEvent& event) {
274 	tqslTrace("TQSLWizCertPage::OnComboBoxEvent", NULL);
275 	int control_idx = event.GetId() - TQSL_ID_LOW;
276 	if (control_idx < 0 || control_idx >= static_cast<int>(controls.size()))
277 		return;
278 	int in_type;
279 	tqsl_getLocationFieldInputType(loc, control_idx, &in_type);
280 	switch (in_type) {
281 		case TQSL_LOCATION_FIELD_DDLIST:
282 		case TQSL_LOCATION_FIELD_LIST:
283 			char gabbi_name[40];
284 			tqsl_getLocationFieldDataGABBI(loc, control_idx, gabbi_name, sizeof gabbi_name);
285 			tqsl_setLocationFieldIndex(loc, control_idx, event.GetInt());
286 			if (strcmp(gabbi_name, "CALL") == 0) {
287 				tqsl_getLocationFieldCharData(loc, control_idx, callsign, sizeof callsign);
288 			}
289 			UpdateFields(control_idx);
290 			break;
291 	}
292 }
293 
294 void
OnCheckBoxEvent(wxCommandEvent & event)295 TQSLWizCertPage::OnCheckBoxEvent(wxCommandEvent& event) {
296 	UpdateFields(-1);
297 }
298 
TQSLWizCertPage(TQSLWizard * parent,tQSL_Location locp)299 TQSLWizCertPage::TQSLWizCertPage(TQSLWizard *parent, tQSL_Location locp)
300 	: TQSLWizPage(parent, locp) {
301 	tqslTrace("TQSLWizCertPage::TQSLWizCertPage", "parent=0x%lx, locp=0x%lx", reinterpret_cast<void *>(parent), reinterpret_cast<void *>(locp));
302 	initialized = false;
303 	errlbl = NULL;
304 	wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
305 	int control_width = getTextSize(this).GetWidth() * 40;
306 
307 	valMsg = wxT("");
308 	invalidGrid = false;
309 	allowBadGrid = false;
310 	tqsl_getStationLocationCapturePage(loc, &loc_page);
311 	wxScreenDC sdc;
312 	int label_w = 0;
313 	int numf;
314 	tqsl_getNumLocationField(loc, &numf);
315 	for (int i = 0; i < numf; i++) {
316 		wxCoord w, h;
317 		char label[256];
318 		tqsl_getLocationFieldDataLabel(loc, i, label, sizeof label);
319 		wxString lbl = wxGetTranslation(wxString::FromUTF8(label));
320 		sdc.GetTextExtent(lbl, &w, &h);
321 		if (w > label_w)
322 			label_w = w;
323 	}
324 	wxCoord max_label_w, max_label_h;
325 	// Measure width of longest expected label string
326 	sdc.GetTextExtent(wxT("Longest label expected"), &max_label_w, &max_label_h);
327 	bool addCheckbox = false;
328 	wxString cbLabel;
329 	for (int i = 0; i < numf; i++) {
330 		char label[256];
331 		int in_type, flags;
332 		wxBoxSizer *hsizer;
333 		tqsl_getLocationFieldDataLabel(loc, i, label, sizeof label);
334 		wxString lbl = wxGetTranslation(wxString::FromUTF8(label));
335 		tqsl_getLocationFieldInputType(loc, i, &in_type);
336 		if (in_type != TQSL_LOCATION_FIELD_BADZONE) {
337 			hsizer = new wxBoxSizer(wxHORIZONTAL);
338 			hsizer->Add(new wxStaticText(this, -1, lbl, wxDefaultPosition,
339 				wxSize(label_w, -1), wxALIGN_RIGHT/*|wxST_NO_AUTORESIZE*/), 0, wxTOP, 5);
340 		}
341 		wxWindow *control_p = 0;
342 		char gabbi_name[256];
343 		tqsl_getLocationFieldDataGABBI(loc, i, gabbi_name, sizeof gabbi_name);
344 		tqsl_getLocationFieldFlags(loc, i, &flags);
345 		switch(in_type) {
346 			case TQSL_LOCATION_FIELD_DDLIST:
347 			case TQSL_LOCATION_FIELD_LIST:
348 				control_p = new wxComboBox(this, TQSL_ID_LOW+i, wxT(""), wxDefaultPosition, wxSize(control_width, -1),
349 					0, 0, wxCB_DROPDOWN|wxCB_READONLY);
350 				if (flags & TQSL_LOCATION_FIELD_SELNXT) {
351 					addCheckbox = true;
352 					cbLabel = lbl;
353 				}
354 				break;
355 			case TQSL_LOCATION_FIELD_TEXT:
356 				control_p = new wxTextCtrl(this, TQSL_ID_LOW+i, wxT(""), wxDefaultPosition, wxSize(control_width, -1));
357 				break;
358 			case TQSL_LOCATION_FIELD_BADZONE:
359 				wxCoord w, h;
360 				int tsize;
361 				tqsl_getLocationFieldDataLength(loc, i, &tsize);
362 				tsize /= 2;
363 				sdc.GetTextExtent(wxString::FromUTF8("X"), &w, &h);
364 				errlbl = new wxStaticText(this, -1, wxT(""), wxDefaultPosition,
365 					wxSize(w*tsize, -1), wxALIGN_LEFT|wxST_NO_AUTORESIZE);
366 				control_p = errlbl;
367 				break;
368 		}
369 		controls.push_back(control_p);
370 		if (in_type != TQSL_LOCATION_FIELD_BADZONE) {
371 			hsizer->Add(control_p, 0, wxLEFT|wxTOP, 5);
372 			sizer->Add(hsizer, 0, wxLEFT|wxRIGHT, 10);
373 		} else {
374 			sizer->Add(control_p, 0, wxEXPAND | wxLEFT| wxRIGHT, 10);
375 		}
376 	}
377 
378 	if (addCheckbox) {
379 		wxBoxSizer *hsizer = new wxBoxSizer(wxHORIZONTAL);
380 		okEmptyCB = new wxCheckBox(this, TQSL_ID_LOW+numf, _("Allow 'None' for ") + cbLabel, wxDefaultPosition, wxDefaultSize);
381 
382 		hsizer->Add(new wxStaticText(this, -1, wxT(""),
383 			wxDefaultPosition, wxSize(label_w, -1), wxALIGN_RIGHT|wxST_NO_AUTORESIZE), 0, wxTOP, 5);
384 		hsizer->Add(okEmptyCB, 0, wxLEFT|wxTOP, 5);
385 		sizer->Add(hsizer, 0, wxLEFT|wxRight, 10);
386 	} else {
387 		okEmptyCB = 0;
388 	}
389 	initialized = true;
390 	UpdateFields();
391 	AdjustPage(sizer, wxT("stnloc1.htm"));
392 }
393 
~TQSLWizCertPage()394 TQSLWizCertPage::~TQSLWizCertPage() {
395 }
396 
397 const char *
validate()398 TQSLWizCertPage::validate() {
399 	tqslTrace("TQSLWizCertPage::validate", NULL);
400 
401 	if (!initialized) return 0;
402 	valMsg = wxT("");
403 	tqsl_setStationLocationCapturePage(loc, loc_page);
404 	for (int i = 0; i < static_cast<int>(controls.size()); i++) {
405 		char gabbi_name[40];
406 		int in_type;
407 		int flags;
408 		tqsl_getLocationFieldDataGABBI(loc, i, gabbi_name, sizeof gabbi_name);
409 		tqsl_getLocationFieldInputType(loc, i, &in_type);
410 		tqsl_getLocationFieldFlags(loc, i, &flags);
411 		if (flags == TQSL_LOCATION_FIELD_SELNXT) {
412 			int index;
413 			tqsl_getLocationFieldIndex(loc, i, &index);
414 			if (index <= 0 && (okEmptyCB && !okEmptyCB->IsChecked())) {
415 				char label[256];
416 				tqsl_getLocationFieldDataLabel(loc, i, label, sizeof label);
417 				valMsg = wxString::Format(_("You must select a %hs"), label);
418 			}
419 			if (okEmptyCB) {
420 				if (index <= 0)
421 					okEmptyCB->Enable(true);
422 				else
423 					okEmptyCB->Enable(false);
424 			}
425 		} else if (strcmp(gabbi_name, "GRIDSQUARE") == 0) {
426 			tqsl_getLocationFieldCharData(loc, 0, callsign, sizeof callsign);
427 			wxString gridVal = (reinterpret_cast<wxTextCtrl *>(controls[i]))->GetValue();
428 			if (gridVal.size() == 0) {
429 				continue;
430 			}
431 			string gridlist;
432 			get_address_field(callsign, "grids", gridlist);
433 			wxString editedGrids = wxT("");
434 			wxStringTokenizer grids(gridVal, wxT(","));	// Comma-separated list of squares
435 			while (grids.HasMoreTokens()) {
436 				wxString grid = grids.GetNextToken().Trim().Trim(false);
437 				// Truncate to six character field
438 				grid = grid.Left(6);
439 				if (grid[0] <= 'z' && grid[0] >= 'a')
440 					grid[0] = grid[0] - 'a' + 'A';	// Upper case first two
441 				if (grid.size() > 1 && (grid[1] <= 'z' && grid[1] >= 'a'))
442 					grid[1] = grid[1] - 'a' + 'A';
443 				if (grid[0] < 'A' || grid[0] > 'R') {
444 					if (valMsg.IsEmpty())
445 						valMsg = wxString::Format(_("%s: Invalid Grid Square Field"), grid.c_str());
446 				}
447 				if (grid.size() > 1 && (grid[1] < 'A' || grid[1] > 'R')) {
448 					if (valMsg.IsEmpty())
449 						valMsg = wxString::Format(_("%s: Invalid Grid Square Field"), grid.c_str());
450 				}
451 				if (grid.size() > 2 && (grid[2] < '0' || grid[2] > '9')) {
452 					if (valMsg.IsEmpty())
453 						valMsg = wxString::Format(_("%s: Invalid Grid Square"), grid.c_str());
454 				}
455 				if (grid.size() < 4) {
456 					if (valMsg.IsEmpty())
457 						valMsg = wxString::Format(_("%s: Invalid Grid Square"), grid.c_str());
458 				}
459 				if (grid[3] < '0' || grid[3] > '9') {
460 					if (valMsg.IsEmpty())
461 						valMsg = wxString::Format(_("%s: Invalid Grid Square"), grid.c_str());
462 				}
463 
464 				if (grid.size() > 4 && (grid[4] <= 'Z' && grid[4] >= 'A'))
465 					grid[4] = grid[4] - 'A' + 'a';	// Lower case subsquare
466 				if (grid.size() > 5 && (grid[5] <= 'Z' && grid[5] >= 'A'))
467 					grid[5] = grid[5] - 'A' + 'a';
468 
469 				if (grid.size() > 4 && (grid[4] < 'a' || grid[4] > 'x')) {
470 					if (valMsg.IsEmpty())
471 						valMsg = wxString::Format(_("%s: Invalid Subsquare"), grid.c_str());
472 				}
473 				if (grid.size() > 5 && (grid[5] < 'a' || grid[5] > 'x')) {
474 					if (valMsg.IsEmpty())
475 						valMsg = wxString::Format(_("%s: Invalid Subsquare"), grid.c_str());
476 				}
477 				if (grid.size() != 6 && grid.size() != 4) {
478 					// Not long enough yet or too long.
479 					if (valMsg.IsEmpty())
480 						valMsg = wxString::Format(_("%s: Invalid Grid Square"), grid.c_str());
481 				}
482 				if (valMsg.IsEmpty() && !gridlist.empty()) {
483 					string probe = string(grid.Left(4).mb_str());
484 					if (gridlist.find(probe) == string::npos) {
485 						valMsg = wxString::Format(_("Grid %s is not correct for your QTH. Click 'Next' again to use it anyway."), grid.c_str());
486 						invalidGrid = true;
487 					} else {
488 						invalidGrid = false;
489 					}
490 				}
491 				if (!editedGrids.IsEmpty())
492 					editedGrids += wxT(",");
493 				editedGrids += grid;
494 				(reinterpret_cast<wxTextCtrl *>(controls[i]))->SetValue(editedGrids);
495 				tqsl_setLocationFieldCharData(loc, i, (reinterpret_cast<wxTextCtrl *>(controls[i]))->GetValue().ToUTF8());
496 			}
497 		} else if (in_type == TQSL_LOCATION_FIELD_BADZONE) {
498 // Possible errors, here for harvesting
499 #ifdef tqsltranslate
500 	static const char* verrs[] = {
501 		__("Invalid zone selections for state"),
502 		__("Invalid zone selections for province"),
503 		__("Invalid zone selections for oblast"),
504 		__("Invalid zone selections for DXCC entity");
505 };
506 #endif
507 			char buf[256];
508 			tqsl_getLocationFieldCharData(loc, i, buf, sizeof buf);
509 			if (strlen(buf) > 0)
510 				valMsg = wxGetTranslation(wxString::FromUTF8(buf));
511 			(reinterpret_cast<wxStaticText *>(controls[i]))->SetLabel(valMsg);
512 		}
513 	}
514 	if (errlbl) errlbl->SetLabel(valMsg);
515 	return 0;
516 }
517 
518 bool
TransferDataFromWindow()519 TQSLWizCertPage::TransferDataFromWindow() {
520 	tqslTrace("TQSLWizCertPage::TransferDataFromWindow", NULL);
521 
522 	tqsl_setStationLocationCapturePage(loc, loc_page);
523 	for (int i = 0; i < static_cast<int>(controls.size()); i++) {
524 		int in_type;
525 		tqsl_getLocationFieldInputType(loc, i, &in_type);
526 		switch(in_type) {
527 			case TQSL_LOCATION_FIELD_DDLIST:
528 			case TQSL_LOCATION_FIELD_LIST:
529 				break;
530 			case TQSL_LOCATION_FIELD_TEXT:
531 				tqsl_setLocationFieldCharData(loc, i, (reinterpret_cast<wxTextCtrl *>(controls[i]))->GetValue().ToUTF8());
532 				break;
533 		}
534 	}
535 	if (errlbl) errlbl->SetLabel(valMsg);
536 	return true;
537 }
538 void
OnPageChanging(wxWizardEvent & ev)539 TQSLWizCertPage::OnPageChanging(wxWizardEvent& ev) {
540 	tqslTrace("TQSLWizCertPage::OnPageChanging", "Direction=", ev.GetDirection());
541 
542 	validate();
543 	if (valMsg.Len() > 0 && ev.GetDirection()) {
544 		if (!allowBadGrid) {
545 			ev.Veto();
546 			allowBadGrid = true;		// Don't allow going forward once
547 		} else {
548 			allowBadGrid = false;
549 		}
550 		if (!invalidGrid) {
551 			wxMessageBox(valMsg, _("Error"), wxOK | wxICON_ERROR, this);
552 		}
553 	}
554 }
555 
BEGIN_EVENT_TABLE(TQSLWizFinalPage,TQSLWizPage)556 BEGIN_EVENT_TABLE(TQSLWizFinalPage, TQSLWizPage)
557 	EVT_LISTBOX(TQSL_ID_LOW, TQSLWizFinalPage::OnListbox)
558 	EVT_LISTBOX_DCLICK(TQSL_ID_LOW, TQSLWizFinalPage::OnListbox)
559 	EVT_TEXT(TQSL_ID_LOW+1, TQSLWizFinalPage::check_valid)
560 	EVT_WIZARD_PAGE_CHANGING(wxID_ANY, TQSLWizFinalPage::OnPageChanging)
561 END_EVENT_TABLE()
562 
563 void
564 TQSLWizFinalPage::OnListbox(wxCommandEvent &) {
565 	tqslTrace("TQSLWizFinalPage::OnListbox", NULL);
566 	if (namelist->GetSelection() >= 0) {
567 		const char *cp = (const char *)(namelist->GetClientData(namelist->GetSelection()));
568 		if (cp)
569 			newname->SetValue(wxString::FromUTF8(cp).Trim(true).Trim(false));
570 	}
571 }
572 
TQSLWizFinalPage(TQSLWizard * parent,tQSL_Location locp,TQSLWizPage * i_prev)573 TQSLWizFinalPage::TQSLWizFinalPage(TQSLWizard *parent, tQSL_Location locp, TQSLWizPage *i_prev)
574 	: TQSLWizPage(parent, locp), prev(i_prev) {
575 	tqslTrace("TQSLWizFinalPage::TQSLWizFinalPage", "parent=0x%lx, locp=0x%lx, i_prev=0x%lx", reinterpret_cast<void *>(parent), reinterpret_cast<void *>(locp), reinterpret_cast<void *>(i_prev));
576 	initialized = false;
577 	errlbl = NULL;
578 	valMsg = wxT("");
579 	wxSize text_size = getTextSize(this);
580 	int control_width = text_size.GetWidth()*40;
581 
582 	int y = text_size.GetHeight();
583 	sizer = new wxBoxSizer(wxVERTICAL);
584 
585 	wxStaticText *st = new wxStaticText(this, -1, _("Station Data input complete"));
586 	sizer->Add(st, 0, wxALIGN_CENTER|wxTOP, 10);
587 
588 	// Title
589 	st = new wxStaticText(this, -1, _("Select or enter name of this station location"));
590 	sizer->Add(st, 0, wxALIGN_CENTER|wxBOTTOM, 10);
591 
592 	// List of existing location names
593 	namelist = new wxListBox(this, TQSL_ID_LOW, wxDefaultPosition, wxSize(control_width, text_size.GetHeight()*10),
594 		0, 0, wxLB_SINGLE|wxLB_HSCROLL|wxLB_NEEDED_SB);
595 	sizer->Add(namelist, 0, wxEXPAND);
596 	int n;
597 	tqsl_getNumStationLocations(locp, &n);
598 	for (int i = 0; i < n; i++) {
599 		char buf[256];
600 		tqsl_getStationLocationName(loc, i, buf, sizeof buf);
601 		item_data.push_back(strdup(buf));
602 		char cbuf[256];
603 		tqsl_getStationLocationCallSign(loc, i, cbuf, sizeof cbuf);
604 		wxString s = wxString::FromUTF8(buf);
605 		s += (wxString(wxT(" (")) + wxString::FromUTF8(cbuf) + wxString(wxT(")")));
606 		const void *v = item_data.back();
607 		namelist->Append(s, const_cast<void *>(v));
608 	}
609 	if (namelist->GetCount() > 0)
610 		namelist->SetSelection(0, FALSE);
611 	// New name
612 	st = new wxStaticText(this, -1, _("Station Location Name"));
613 	sizer->Add(st, 0, wxALIGN_LEFT|wxTOP, 10);
614 	newname = new wxTextCtrl(this, TQSL_ID_LOW+1, wxT(""), wxPoint(0, y), wxSize(control_width, -1));
615 	sizer->Add(newname, 0, wxEXPAND);
616 	newname->SetValue(parent->GetLocationName());
617 	errlbl = new wxStaticText(this, -1, wxT(""), wxDefaultPosition, wxSize(control_width, -1),
618 				wxALIGN_LEFT/*|wxST_NO_AUTORESIZE*/);
619 	sizer->Add(errlbl, 0, wxTOP);
620 	initialized = true;
621 	AdjustPage(sizer, wxT("stnloc2.htm"));
622 }
623 
624 bool
TransferDataFromWindow()625 TQSLWizFinalPage::TransferDataFromWindow() {
626 	tqslTrace("TQSLWizFinalPage::TransferDataFromWindow", NULL);
627 	validate();
628 	if (valMsg.Len() > 0) // Must be a "back"
629 		return true;
630 	wxString s = newname->GetValue().Trim(true).Trim(false);
631 	(reinterpret_cast<TQSLWizard *>(GetParent()))->SetLocationName(s);
632 	return true;
633 }
634 
635 void
OnPageChanging(wxWizardEvent & ev)636 TQSLWizFinalPage::OnPageChanging(wxWizardEvent& ev) {
637 	tqslTrace("TQSLWizFinalPage::OnPageChanging", "Direction=", ev.GetDirection());
638 
639 	validate();
640 	if (valMsg.Len() > 0 && ev.GetDirection()) {
641 		ev.Veto();
642 		wxMessageBox(valMsg, _("Error"), wxOK | wxICON_ERROR, this);
643 	}
644 }
645 
646 const char *
validate()647 TQSLWizFinalPage::validate() {
648 	tqslTrace("TQSLWizFinalPage::validate", NULL);
649 	if (!initialized) return 0;
650 	wxString val = newname->GetValue().Trim(true).Trim(false);
651 	valMsg = wxT("");
652 
653 	if (val == wxT("")) {
654 		valMsg = wxGetTranslation(_("Station name must be provided"));
655 	}
656 	if (errlbl) errlbl->SetLabel(valMsg);
657 	return 0;
658 }
659 
~TQSLWizFinalPage()660 TQSLWizFinalPage::~TQSLWizFinalPage() {
661 	for (int i = 0; i < static_cast<int>(item_data.size()); i++) {
662 		free(item_data[i]);
663 	}
664 }
665