1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 // ModifyVariableDlg.cpp : implementation file
11 //
12 
13 #include "stdafx.h"
14 #include "FRED.h"
15 #include "ModifyVariableDlg.h"
16 #include "parse/sexp.h"
17 
18 #ifdef _DEBUG
19 #undef THIS_FILE
20 static char THIS_FILE[] = __FILE__;
21 #endif
22 
23 #define	NO_RESET_FOCUS	0
24 #define	RESET_FOCUS		1
25 
26 
27 /////////////////////////////////////////////////////////////////////////////
28 // CModifyVariableDlg dialog
29 
CModifyVariableDlg(CWnd * pParent)30 CModifyVariableDlg::CModifyVariableDlg(CWnd* pParent /*=NULL*/)
31 	: CDialog(CModifyVariableDlg::IDD, pParent)
32 {
33 	//{{AFX_DATA_INIT(CModifyVariableDlg)
34 	m_default_value = _T("");
35 	m_cur_variable_name = _T("");
36 	//}}AFX_DATA_INIT
37 }
38 
39 
DoDataExchange(CDataExchange * pDX)40 void CModifyVariableDlg::DoDataExchange(CDataExchange* pDX)
41 {
42 	CDialog::DoDataExchange(pDX);
43 	//{{AFX_DATA_MAP(CModifyVariableDlg)
44 	DDX_Text(pDX, IDC_MODIFY_DEFAULT_VALUE, m_default_value);
45 	DDV_MaxChars(pDX, m_default_value, 31);
46 	DDX_CBString(pDX, IDC_MODIFY_VARIABLE_NAME, m_cur_variable_name);
47 	DDV_MaxChars(pDX, m_cur_variable_name, 31);
48 	//}}AFX_DATA_MAP
49 }
50 
51 
BEGIN_MESSAGE_MAP(CModifyVariableDlg,CDialog)52 BEGIN_MESSAGE_MAP(CModifyVariableDlg, CDialog)
53 	//{{AFX_MSG_MAP(CModifyVariableDlg)
54 	ON_BN_CLICKED(ID_DELETE_VARIABLE, OnDeleteVariable)
55 	ON_BN_CLICKED(IDC_TYPE_STRING, OnTypeString)
56 	ON_BN_CLICKED(IDC_TYPE_NUMBER, OnTypeNumber)
57 	ON_BN_CLICKED(IDC_TYPE_PLAYER_PERSISTENT, OnTypePlayerPersistent)
58 	ON_BN_CLICKED(IDC_TYPE_CAMPAIGN_PERSISTENT, OnTypeCampaignPersistent)
59 	ON_BN_CLICKED(IDC_TYPE_NETWORK_VARIABLE, OnTypeNetworkVariable)
60 	ON_CBN_SELCHANGE(IDC_MODIFY_VARIABLE_NAME, OnSelchangeModifyVariableName)
61 	ON_CBN_EDITCHANGE(IDC_MODIFY_VARIABLE_NAME, OnEditchangeModifyVariableName)
62 	ON_EN_KILLFOCUS(IDC_MODIFY_DEFAULT_VALUE, OnKillfocusModifyDefaultValue)
63 	ON_CBN_DROPDOWN(IDC_MODIFY_VARIABLE_NAME, OnDropdownModifyVariableName)
64 	//}}AFX_MSG_MAP
65 END_MESSAGE_MAP()
66 
67 /////////////////////////////////////////////////////////////////////////////
68 // CModifyVariableDlg message handlers
69 
70 // Maybe delete variable
71 void CModifyVariableDlg::OnDeleteVariable()
72 {
73 	CString temp_name;
74 	int rval;
75 
76 	// Check for name change
77 	CComboBox *cbox = (CComboBox *) GetDlgItem(IDC_MODIFY_VARIABLE_NAME);
78 	cbox->GetWindowText(temp_name);
79 
80 	// Can't delete. Name has been changed
81 	if ( stricmp(Sexp_variables[get_sexp_var_index()].variable_name, temp_name) ) {
82 		MessageBox("Can not delete variable.  Name has been changed.");
83 		return;
84 	}
85 
86 	char message[128] = "Can not delete variable.";
87 	if (!IsChangeSafe(message))	{
88 		return;
89 	}
90 
91 	// maybe delete variable
92 	rval = MessageBox("This will permanantly delete the variable.  Do you want to continue?", NULL, MB_OKCANCEL);
93 
94 	if (rval == IDOK) {
95 		// delete variable and exit
96 		m_deleted = true;
97 		// next statement does UpdataData(TRUE);
98 		CDialog::OnOK();
99 	}
100 }
101 
102 // Karajorma - Checks whether it is safe to delete or modify this string
IsChangeSafe(char * message)103 bool CModifyVariableDlg::IsChangeSafe(char *message)
104 {
105 	// Can't as there are SEXPs using it.
106 	int num_counts = m_p_sexp_tree->get_variable_count(Sexp_variables[get_sexp_var_index()].variable_name);
107 	if (num_counts > 0) {
108 		char buffer[256];
109 		sprintf(buffer, "%s Used in %d SEXP(s).", message, num_counts);
110 		MessageBox(buffer);
111 		return false;
112 	}
113 
114 	// Can't as it is used in the team loadout
115 	num_counts = m_p_sexp_tree->get_loadout_variable_count(get_sexp_var_index());
116 	if (num_counts > 0) {
117 		char buffer[256];
118 		sprintf(buffer, "%s Used in %d location(s) in loadout.", message, num_counts);
119 		MessageBox(buffer);
120 		return false;
121 	}
122 
123 	return true;
124 }
125 
126 // Set type to string
OnTypeString()127 void CModifyVariableDlg::OnTypeString()
128 {
129 	// check if type actually modified
130 	if (m_type_number == true) {
131 
132 		// Don't allow type change if in use.
133 		char message[128] = "Can not modify variable type.";
134 		if (!IsChangeSafe(message))	{
135 			m_type_number = true;
136 			m_modified_type = false;
137 			set_variable_type();
138 			return;
139 		}
140 
141 		// keep track if type is really changed
142 		if (m_modified_type == true) {
143 			m_modified_type = false;
144 		} else {
145 			m_modified_type = true;
146 		}
147 	}
148 	m_type_number = false;
149 	set_variable_type();
150 }
151 
152 // Set type to number
OnTypeNumber()153 void CModifyVariableDlg::OnTypeNumber()
154 {
155 	// check if type actually modified
156 	if (m_type_number == false) {
157 
158 		// Don't allow type change if in use.
159 		char message[128] = "Can not modify variable type.";
160 		if (!IsChangeSafe(message))	{
161 			m_type_number = false;
162 			m_modified_type = false;
163 			set_variable_type();
164 			return;
165 		}
166 
167 		// keep track if type is really changed
168 		if (m_modified_type == true) {
169 			m_modified_type = false;
170 		} else {
171 			m_modified_type = true;
172 		}
173 	}
174 	m_type_number = true;
175 	set_variable_type();
176 }
177 
178 // set player persistence
OnTypePlayerPersistent()179 void CModifyVariableDlg::OnTypePlayerPersistent()
180 {
181 	m_type_player_persistent = ((CButton *) GetDlgItem(IDC_TYPE_PLAYER_PERSISTENT))->GetCheck() ? true : false;
182 
183 	// keep track if type is really changed (ugh - just force it to be always changed)
184 	m_modified_persistence = true;
185 
186 	if (m_type_player_persistent)
187 		m_type_campaign_persistent = false;
188 
189 	set_variable_type();
190 }
191 
192 // set campaign persistence
OnTypeCampaignPersistent()193 void CModifyVariableDlg::OnTypeCampaignPersistent()
194 {
195 	m_type_campaign_persistent = ((CButton *) GetDlgItem(IDC_TYPE_CAMPAIGN_PERSISTENT))->GetCheck() ? true : false;
196 
197 	// keep track if type is really changed (ugh - just force it to be always changed)
198 	m_modified_persistence = true;
199 
200 	if (m_type_campaign_persistent)
201 		m_type_player_persistent = false;
202 
203 	set_variable_type();
204 }
205 
OnTypeNetworkVariable()206 void CModifyVariableDlg::OnTypeNetworkVariable()
207 {
208 	m_type_network_variable = ((CButton *) GetDlgItem(IDC_TYPE_NETWORK_VARIABLE))->GetCheck() ? true : false;
209 
210 	m_modified_type = true;
211 
212 	set_variable_type();
213 }
214 
OnSelchangeModifyVariableName()215 void CModifyVariableDlg::OnSelchangeModifyVariableName()
216 {
217 	CComboBox *cbox = (CComboBox *) GetDlgItem(IDC_MODIFY_VARIABLE_NAME);
218 
219 	// get index of current selection
220 	int index = cbox->GetCurSel();
221 
222 	// check an item was actually selected, and not outside the box
223 	if (index == CB_ERR) {
224 		return;
225 	}
226 
227 	// check if another has been modified
228 	if (m_modified_type || m_modified_persistence || m_modified_name || m_modified_value) {
229 
230 		// Don't send message if changing to self
231 		if (index != m_combo_last_modified_index) {
232 			MessageBox("Can only modify one variable.");
233 		}
234 
235 		//reset focus to current
236 		cbox->SetCurSel(m_combo_last_modified_index);
237 		return;
238 	}
239 
240 	m_combo_last_modified_index = index;
241 
242 	// Get index into sexp_variables
243 	int sexp_variable_index = get_sexp_var_index();
244 
245 	// Set new type for selection
246 	m_type_number = ((Sexp_variables[sexp_variable_index].type & SEXP_VARIABLE_NUMBER) != 0) ? true : false;
247 	m_type_campaign_persistent = ((Sexp_variables[sexp_variable_index].type & SEXP_VARIABLE_CAMPAIGN_PERSISTENT) != 0) ? true : false;
248 	m_type_player_persistent = ((Sexp_variables[sexp_variable_index].type & SEXP_VARIABLE_PLAYER_PERSISTENT) != 0) ? true : false;
249 	m_type_network_variable = ((Sexp_variables[sexp_variable_index].type & SEXP_VARIABLE_NETWORK) != 0) ? true : false;
250 	set_variable_type();
251 
252 	// Set new default value for selection
253 	if (sexp_variable_index > -1) {
254 		CEdit *edit = (CEdit *) GetDlgItem(IDC_MODIFY_DEFAULT_VALUE);
255 		edit->SetWindowText(Sexp_variables[sexp_variable_index].text);
256 	}
257 }
258 
259 // Check if variable name has changed from Sexp_variables[].varaible name
OnEditchangeModifyVariableName()260 void CModifyVariableDlg::OnEditchangeModifyVariableName()
261 {
262 	// Do string compare to check for change
263 	CString temp_name;
264 
265 	// Get current variable name
266 	CComboBox *cbox = (CComboBox *) GetDlgItem(IDC_MODIFY_VARIABLE_NAME);
267 	cbox->GetWindowText(temp_name);
268 
269 	// Check if variable name is modified
270 	if ( strcmp(Sexp_variables[get_sexp_var_index()].variable_name, temp_name) ) {
271 		m_modified_name = true;
272 	} else {
273 		m_modified_name = false;
274 	}
275 }
276 
OnInitDialog()277 BOOL CModifyVariableDlg::OnInitDialog()
278 {
279 	CDialog::OnInitDialog();
280 
281 	int i, box_index;
282 	// Init combo box and translation table from combo box to sexp_varaibles
283 	CComboBox *cbox = (CComboBox *) GetDlgItem(IDC_MODIFY_VARIABLE_NAME);
284 	cbox->ResetContent();
285 
286 	for (i=0; i<MAX_SEXP_VARIABLES; i++) {
287 		m_translate_combo_to_sexp[i] = -1;
288 	}
289 
290 	// initialize list -- Box is set to *not* sort
291 	for (i=0; i<MAX_SEXP_VARIABLES; i++) {
292 		if ((Sexp_variables[i].type & SEXP_VARIABLE_SET) && !(Sexp_variables[i].type & SEXP_VARIABLE_BLOCK)){
293 			box_index = cbox->AddString(Sexp_variables[i].variable_name);
294 
295 			// check no error
296 			if ( !((box_index == CB_ERR) || (box_index == CB_ERRSPACE)) ) {
297 				m_translate_combo_to_sexp[box_index] = i;
298 			}
299 		}
300 	}
301 
302 	// Exit gracefully if nothing added to combo box
303 	if (cbox->GetCount() == 0) {
304 		Int3();	// this should not happen
305 		OnCancel();
306 	}
307 
308 	int last_modified = 0;
309 	// Set current variable
310 	if (m_start_index > -1) {
311 		for (i=0; i<MAX_SEXP_VARIABLES; i++) {
312 			if (m_translate_combo_to_sexp[i] == m_start_index) {
313 				last_modified = i;
314 				break;
315 			}
316 		}
317 	}
318 
319 	m_combo_last_modified_index = last_modified;
320 	cbox->SetCurSel(last_modified);
321 
322 	// Set the default value
323 	if (m_translate_combo_to_sexp[last_modified] > -1) {
324 		CEdit *edit = (CEdit *) GetDlgItem(IDC_MODIFY_DEFAULT_VALUE);
325 		edit->SetWindowText(Sexp_variables[m_translate_combo_to_sexp[last_modified]].text);
326 	}
327 
328 	// Set old variable name
329 	m_old_var_name = Sexp_variables[m_translate_combo_to_sexp[last_modified]].variable_name;
330 
331 	// Set type
332 	m_type_number = ((Sexp_variables[last_modified].type & SEXP_VARIABLE_NUMBER) != 0) ? true : false;
333 	m_type_campaign_persistent = ((Sexp_variables[last_modified].type & SEXP_VARIABLE_CAMPAIGN_PERSISTENT) != 0) ? true : false;
334 	m_type_player_persistent = ((Sexp_variables[last_modified].type & SEXP_VARIABLE_PLAYER_PERSISTENT) != 0) ? true : false;
335 	m_type_network_variable = ((Sexp_variables[last_modified].type & SEXP_VARIABLE_NETWORK) != 0) ? true : false;
336 	set_variable_type();
337 
338 	// keep track of changes
339 	m_modified_name  = false;
340 	m_modified_value = false;
341 	m_modified_type  = false;
342 	m_modified_persistence = false;
343 	m_deleted		  = false;
344 	m_do_modify		  = false;
345 
346 	m_data_validated		= false;
347 	m_var_name_validated = false;
348 
349 
350 	return TRUE;  // return TRUE unless you set the focus to a control
351 	              // EXCEPTION: OCX Property Pages should return FALSE
352 }
353 
set_variable_type()354 void CModifyVariableDlg::set_variable_type()
355 {
356 	// get buttons
357 	CButton *button_string = (CButton *) GetDlgItem(IDC_TYPE_STRING);
358 	CButton *button_number = (CButton *) GetDlgItem(IDC_TYPE_NUMBER);
359 
360 	// assign state
361 	button_number->SetCheck( m_type_number);
362 	button_string->SetCheck(!m_type_number);
363 
364 	((CButton *) GetDlgItem(IDC_TYPE_CAMPAIGN_PERSISTENT))->SetCheck(m_type_campaign_persistent);
365 	((CButton *) GetDlgItem(IDC_TYPE_PLAYER_PERSISTENT))->SetCheck(m_type_player_persistent);
366 	((CButton *) GetDlgItem(IDC_TYPE_NETWORK_VARIABLE))->SetCheck(m_type_network_variable);
367 }
368 
OnOK()369 void CModifyVariableDlg::OnOK()
370 {
371 	CString temp_data;
372 
373 	// Validate data
374 	CEdit *edit = (CEdit *) GetDlgItem(IDC_MODIFY_DEFAULT_VALUE);
375 	edit->GetWindowText(temp_data);
376 
377 	// validate data
378 	validate_data(temp_data, RESET_FOCUS);
379 	if (m_data_validated) {
380 		// Don't get OnKillfocusModifyDefaultValue when ok
381 		if (!m_modified_value) {
382 			if ( strcmp(Sexp_variables[get_sexp_var_index()].text, temp_data) ) {
383 				m_modified_value = true;
384 			}
385 		}
386 
387 		// validate variable name
388 		validate_var_name(RESET_FOCUS);
389 		if (m_var_name_validated) {
390 
391 			// maybe set m_do_modify -- this is needed. compare with OnCancel()
392 			if (m_modified_name || m_modified_persistence || m_modified_value || m_modified_type) {
393 				m_do_modify = true;
394 			}
395 			CDialog::OnOK();
396 		}
397 	}
398 }
399 
OnKillfocusModifyDefaultValue()400 void CModifyVariableDlg::OnKillfocusModifyDefaultValue()
401 {
402 	// Do string compare to check for change
403 	CString temp_data;
404 
405 	CEdit *edit = (CEdit *) GetDlgItem(IDC_MODIFY_DEFAULT_VALUE);
406 	edit->GetWindowText(temp_data);
407 
408 	if ( strcmp(Sexp_variables[get_sexp_var_index()].text, temp_data) ) {
409 		m_modified_value = true;
410 	} else {
411 		m_modified_value = false;
412 	}
413 }
414 
415 // validate data
416 // check (1)  zero length (2) invalid chars (3) value if numberf
validate_data(CString & temp_data,int set_focus)417 void CModifyVariableDlg::validate_data(CString &temp_data, int set_focus)
418 {
419 	// display invalid data message
420 	bool message = false;
421 	char message_text[256];
422 
423 	// check length > 0
424 	int length  = strlen(temp_data);
425 	if (length == 0) {
426 		strcpy_s(message_text, "Invalid  Default Value");
427 		message = true;
428 
429 	} else if (m_type_number) {
430 		// check if string and str(atoi(stri)) are same
431 		int temp_num = atoi(temp_data);
432 		char buf[TOKEN_LENGTH];
433 		sprintf(buf, "%d", temp_num);
434 
435 		if ( stricmp(buf, temp_data) ) {
436 			message = true;
437 			strcpy_s(message_text, "Invalid  Default Value");
438 		} else {
439 			message = false;
440 		}
441 	}
442 
443 	// check for invalid characters
444 	int rval = strcspn(temp_data, "@()");
445 	if (rval != length) {
446 		message = true;
447 		sprintf(message_text, "Invalid char '%c' in Default Value", temp_data[rval]);
448 	}
449 
450 	// display message
451 	if ( message ) {
452 		m_data_validated = false;
453 		MessageBox(message_text);
454 
455 		// reset focus
456 		if (set_focus == RESET_FOCUS) {
457 			CEdit *edit = (CEdit *) GetDlgItem(IDC_MODIFY_DEFAULT_VALUE);
458 			edit->SetFocus();
459 			edit->SetSel(0, -1);
460 		}
461 	}
462 
463 	// string always ok, numbers if no message
464 	m_data_validated = !message;
465 }
466 
467 // validate variable name
468 // check (1) zero length (2) invalid chars (3) already in use
validate_var_name(int set_focus)469 void CModifyVariableDlg::validate_var_name(int set_focus)
470 {
471 	CString temp_name;
472 	CComboBox *cbox = (CComboBox *) GetDlgItem(IDC_MODIFY_VARIABLE_NAME);
473 	cbox->GetWindowText(temp_name);
474 
475 	int cur_sel = cbox->GetCurSel();
476 	m_old_var_name = Sexp_variables[m_translate_combo_to_sexp[cur_sel]].variable_name;
477 
478 	// display invalid data message
479 	bool message = false;
480 	char message_text[256];
481 
482 	// check length > 0
483 	int length  = strlen(temp_name);
484 	if (length == 0) {
485 		strcpy_s(message_text, "Invalid Variable Name");
486 		message = true;
487 	} else {
488 
489 		// check for invalid characters
490 		int rval = strcspn(temp_name, "@()");
491 		if (rval != length) {
492 			message = true;
493 			sprintf(message_text, "Invalid char '%c' in Variable Name", temp_name[rval]);
494 		} else {
495 			int index = get_index_sexp_variable_name(temp_name);
496 
497 			// if not a new name and not start name
498 			if ( (index != -1) && (index != m_translate_combo_to_sexp[m_combo_last_modified_index]) ) {
499 				message = true;
500 				strcpy_s(message_text, "Variable Name already in use");
501 			}
502 		}
503 	}
504 
505 	// display message
506 	if ( message ) {
507 		MessageBox(message_text);
508 
509 		// reset focus
510 		if (set_focus == RESET_FOCUS) {
511 			cbox->SetFocus();
512 		}
513 	}
514 
515 	// set var_name_validated
516 	m_var_name_validated = !message;
517 }
518 
519 
get_sexp_var_index()520 int CModifyVariableDlg::get_sexp_var_index()
521 {
522 	int index = m_translate_combo_to_sexp[m_combo_last_modified_index];
523 	Assert( (index >= 0) && (index < MAX_SEXP_VARIABLES) );
524 
525 	return index;
526 }
527 
528 // Reset text in drop down list
OnDropdownModifyVariableName()529 void CModifyVariableDlg::OnDropdownModifyVariableName()
530 {
531 	CString temp_name;
532 
533 	// Get current variable name
534 	CComboBox *cbox = (CComboBox *) GetDlgItem(IDC_MODIFY_VARIABLE_NAME);
535 	cbox->GetWindowText(temp_name);
536 
537 	// Reset combo box text
538 	int rval;
539 	rval = cbox->InsertString(m_combo_last_modified_index, temp_name);
540 	if ( (rval == CB_ERR) || (rval == CB_ERRSPACE) ) {
541 		AfxMessageBox("An internal error has occured.");
542 		OnCancel();
543 	}
544 	cbox->DeleteString(m_combo_last_modified_index+1);
545 
546 	cbox->SetCurSel(m_combo_last_modified_index);
547 }
548