1 /*
2 * Author: William Chia-Wei Cheng (bill.cheng@acm.org)
3 *
4 * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5 *
6 * This file may be distributed under the terms of the Q Public License
7 * as defined by Trolltech AS of Norway and appearing in the file
8 * LICENSE.QPL included in the packaging of this file.
9 *
10 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12 * PURPOSE. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * @(#)$Header: /mm2/home/cvs/bc-src/tgif/cutpaste.c,v 1.63 2011/06/25 22:36:42 cvsps Exp $
19 */
20
21 #define _INCLUDE_FROM_CUTPASTE_C_
22
23 #include "tgifdefs.h"
24 #include "cmdids.h"
25
26 #include "arc.e"
27 #include "auxtext.e"
28 #include "attr.e"
29 #include "box.e"
30 #include "choice.e"
31 #include "choose.e"
32 #include "cmd.e"
33 #include "color.e"
34 #ifndef _NO_KINPUT
35 #include "convkinput.e"
36 #endif /* ~_NO_KINPUT */
37 #include "cutpaste.e"
38 #include "cursor.e"
39 #include "dialog.e"
40 #include "drawing.e"
41 #include "dup.e"
42 #include "file.e"
43 #include "font.e"
44 #include "grid.e"
45 #include "import.e"
46 #include "ini.e"
47 #include "mainloop.e"
48 #include "mark.e"
49 #include "menu.e"
50 #include "miniline.e"
51 #include "move.e"
52 #include "msg.e"
53 #include "names.e"
54 #ifndef _NO_NKF
55 #include "nkf.e"
56 #endif /* ~_NO_NKF */
57 #include "obj.e"
58 #include "oval.e"
59 #include "page.e"
60 #include "pattern.e"
61 #include "poly.e"
62 #include "polygon.e"
63 #include "raster.e"
64 #include "rcbox.e"
65 #include "remote.e"
66 #include "select.e"
67 #include "setup.e"
68 #include "special.e"
69 #include "stretch.e"
70 #include "strtbl.e"
71 #include "text.e"
72 #include "util.e"
73 #include "xbitmap.e"
74 #include "xpixmap.e"
75
76 int copyingToCutBuffer=FALSE;
77 int pastingFile=FALSE;
78
79 char gszFilesIniFile[MAXPATHLENGTH];
80 /* do not translate -- program constants */
81 char *gpszRecentFilesSec="Recent Files";
82 char *gpszRecentFilesCountKey="Count";
83
84 int cutBufferIsTgifObj=FALSE;
85 int cutBufferIsUTF8=FALSE;
86 struct DynStrRec dsCutBuffer;
87
88 Time startSelectionOwnershipTime=(Time)0;
89 Time endSelectionOwnershipTime=(Time)0;
90 int startSelectionOwnershipTimeValid=FALSE;
91 int endSelectionOwnershipTimeValid=FALSE;
92
93 SetCutBufferInfo gSetCutBufferInfo;
94
95 static int pasteFromXSelectionOnly=TRUE;
96 static int pasteFromSelectionTimeout=10;
97
98 static Atom gaCutBufferAtom[] = { XA_CUT_BUFFER0, XA_CUT_BUFFER1,
99 XA_CUT_BUFFER2, XA_CUT_BUFFER3, XA_CUT_BUFFER4, XA_CUT_BUFFER5,
100 XA_CUT_BUFFER6, XA_CUT_BUFFER7, (Atom)0 };
101
102 static Atom gaAllSelectionAtom[] = {
103 XA_PRIMARY,
104 /*
105 * It does not appear that you need to try anything other than XA_PRIMARY.
106 *
107 * XA_CUT_BUFFER0, XA_CUT_BUFFER1, XA_CUT_BUFFER2, XA_CUT_BUFFER3,
108 * XA_CUT_BUFFER4, XA_CUT_BUFFER5, XA_CUT_BUFFER6, XA_CUT_BUFFER7,
109 */
110 (Atom)0 };
111
112 static
ResetCutBufferInfo()113 void ResetCutBufferInfo()
114 {
115 UtilFree(gSetCutBufferInfo.tgif_dyn_str.s);
116 UtilFree(gSetCutBufferInfo.utf8_dyn_str.s);
117 UtilFree(gSetCutBufferInfo.text_dyn_str.s);
118 memset(&gSetCutBufferInfo, 0, sizeof(SetCutBufferInfo));
119 }
120
121 static
SetCutBuffer(buf,bytes_to_write,buf_is_simple_string,buf_is_utf8_string)122 void SetCutBuffer(buf, bytes_to_write, buf_is_simple_string, buf_is_utf8_string)
123 char *buf;
124 int bytes_to_write, buf_is_simple_string, buf_is_utf8_string;
125 /*
126 * if buf_is_simple_string is TRUE, this is for text
127 * otherwise, it's an object
128 */
129 {
130 FreeDynStrBuf(&dsCutBuffer);
131 memset(&dsCutBuffer, 0, sizeof(dsCutBuffer));
132
133 dsCutBuffer.s = (char*)malloc((bytes_to_write+1)*sizeof(char));
134 if (dsCutBuffer.s == NULL) FailAllocMessage();
135 memcpy(dsCutBuffer.s, buf, bytes_to_write);
136 dsCutBuffer.s[bytes_to_write] = '\0';
137 dsCutBuffer.sz = bytes_to_write+1;
138
139 cutBufferIsTgifObj = (buf_is_simple_string ? FALSE : TRUE);
140 cutBufferIsUTF8 = buf_is_utf8_string;
141
142 if (buf_is_simple_string) {
143 if (buf_is_utf8_string) {
144 DynStrSet(&gSetCutBufferInfo.utf8_dyn_str, dsCutBuffer.s);
145 gSetCutBufferInfo.utf8_valid = TRUE;
146 } else {
147 DynStrSet(&gSetCutBufferInfo.text_dyn_str, dsCutBuffer.s);
148 gSetCutBufferInfo.text_valid = TRUE;
149 }
150 } else {
151 DynStrSet(&gSetCutBufferInfo.tgif_dyn_str, dsCutBuffer.s);
152 gSetCutBufferInfo.tgif_valid = TRUE;
153 }
154 }
155
156 #ifdef _CALL_XSTOREBYTES_ALSO
157 static
WriteOldStyleCutBuffer()158 int WriteOldStyleCutBuffer()
159 {
160 int xstorebytes_failed=FALSE;
161
162 copyingToCutBuffer = TRUE;
163 XRotateBuffers(mainDisplay, 1);
164 XStoreBytes(mainDisplay, dsCutBuffer.s, dsCutBuffer.sz-1);
165
166 XSync(mainDisplay, False);
167 if (copyingToCutBuffer == INVALID) {
168 xstorebytes_failed = TRUE;
169 }
170 copyingToCutBuffer = FALSE;
171 return (!xstorebytes_failed);
172 }
173 #endif /* _CALL_XSTOREBYTES_ALSO */
174
WriteBufToCutBuffer(buf,bytes_to_write,buf_is_simple_string,buf_is_utf8_string,pscbi)175 int WriteBufToCutBuffer(buf, bytes_to_write, buf_is_simple_string,
176 buf_is_utf8_string, pscbi)
177 char *buf;
178 int bytes_to_write, buf_is_simple_string, buf_is_utf8_string;
179 SetCutBufferInfo *pscbi;
180 /*
181 * if buf_is_simple_string is TRUE, this is for text
182 * otherwise, it's an object
183 */
184 {
185 int copy_failed=FALSE, setselowner_failed=FALSE;
186
187 ClearSelection();
188 SetCutBuffer(buf, bytes_to_write, buf_is_simple_string, buf_is_utf8_string);
189 #ifdef _CALL_XSTOREBYTES_ALSO
190 if (!WriteOldStyleCutBuffer()) {
191 ClearSelection();
192 }
193 #endif /* _CALL_XSTOREBYTES_ALSO */
194 /*
195 * If use gSelectionMainAtom here, on Fedora 11, pasting anything copied
196 * from other tools ends up pasting from tgif!
197 * So, XA_PRIMARY is hard coded and gSelectionMainAtom is not used.
198 */
199 XSetSelectionOwner(mainDisplay, XA_PRIMARY, mainWindow,
200 lastKeyOrBtnEvInfo.time);
201 if (XGetSelectionOwner(mainDisplay, XA_PRIMARY) != mainWindow) {
202 setselowner_failed = TRUE;
203 sprintf(gszMsgBox, TgLoadString(STID_CANT_ACQUIRE_X_SELECTION));
204 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
205 } else {
206 startSelectionOwnershipTimeValid = TRUE;
207 endSelectionOwnershipTimeValid = FALSE;
208 startSelectionOwnershipTime = lastKeyOrBtnEvInfo.time;
209 endSelectionOwnershipTime = (Time)0;
210 }
211 return (!copy_failed);
212 }
213
ClearSelection()214 void ClearSelection()
215 {
216 /*
217 * XStoreBytes(mainDisplay, NULL, 0);
218 * XSetSelectionOwner(mainDisplay, XA_PRIMARY, None,
219 * lastKeyOrBtnEvInfo.time);
220 */
221
222 /*
223 * Does not appear to need to do this:
224 *
225 * int i=0;
226 *
227 * for (i=0; gaAllSelectionAtom[i] != (Atom)0; i++) {
228 * XSetSelectionOwner(mainDisplay, gaAllSelectionAtom[i], None,
229 * lastKeyOrBtnEvInfo.time);
230 * }
231 */
232 }
233
234 static
CopyObjectToCutBuffer(force)235 int CopyObjectToCutBuffer(force)
236 int force;
237 /* if force == TRUE, copy the TGIF object no matter what */
238 /* if force == FALSE, do not copy if the object is a simple text object, */
239 /* i.e., all with same font, size, color, etc */
240 /* returns FALSE if copying in text mode -- this is */
241 /* interpreted as an attempt to copy highlighted text */
242 {
243 FILE *fp=NULL;
244 char tmpfile[MAXSTRING], *cut_buffer=NULL;
245 struct stat stat;
246 unsigned char header=TGIF_HEADER;
247 struct ObjRec *partial_text_obj_ptr=NULL;
248
249 if (curChoice == DRAWTEXT) {
250 if (!textHighlight) {
251 return FALSE;
252 } else {
253 /* create a partial text object with only the minilines */
254 partial_text_obj_ptr = CreateTextObjFromHighLightedText();
255 if (partial_text_obj_ptr == NULL) {
256 return FALSE;
257 }
258 if (!force) {
259 struct TextRec *text_ptr=partial_text_obj_ptr->detail.t;
260 MiniLinesInfo *minilines=(&text_ptr->minilines);
261 MiniLineInfo *pMiniLine=minilines->first;
262 StrBlockInfo *pStrBlock=pMiniLine->first_block;
263 StrSegInfo *pStrSeg=pStrBlock->seg;
264 int sz_unit=pStrSeg->sz_unit, double_byte=pStrSeg->double_byte, font=pStrSeg->font, style=pStrSeg->style;
265 int underline_on=pStrSeg->underline_on, overline_on=pStrSeg->overline_on;
266 int color_index=INVALID;
267
268 if (SingleFontText(text_ptr, &sz_unit, &double_byte, &font, &style,
269 &underline_on, &overline_on) &&
270 SingleColorText(text_ptr, &color_index)) {
271 /* since it's a simple text object, don't copy it as a TGIF object */
272 return FALSE;
273 }
274 }
275 }
276 } else if (topSel == NULL) {
277 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
278 return TRUE;
279 }
280 if (MkTempFile(tmpfile, sizeof(tmpfile), tmpDir, TOOL_NAME) == NULL) {
281 return TRUE;
282 }
283 // Naehring: added b to the mode string.
284 if ((fp=fopen(tmpfile, "wb+")) == NULL) {
285 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_WRITING),
286 tmpfile);
287 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
288 return TRUE;
289 }
290 writeFileFailed = FALSE;
291 if (write(fileno(fp), (char*)(&header), 1) < 1) writeFileFailed = TRUE;
292
293 if (curChoice == DRAWTEXT) {
294 /* create a partial text object with only the minilines */
295 copyInDrawTextMode = TRUE;
296 Save(fp, partial_text_obj_ptr, 0, 1);
297 copyInDrawTextMode = FALSE;
298
299 FreeObj(partial_text_obj_ptr);
300 } else {
301 struct SelRec *sel_ptr=NULL;
302 struct ObjRec *top_obj=NULL, *bot_obj=NULL;
303
304 for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
305 struct ObjRec *obj_ptr=DupObj(sel_ptr->obj);
306
307 obj_ptr->prev = NULL;
308 obj_ptr->next = top_obj;
309
310 if (top_obj == NULL) {
311 bot_obj = obj_ptr;
312 } else {
313 top_obj->prev = obj_ptr;
314 }
315 top_obj = obj_ptr;
316 }
317 Save(fp, bot_obj, 0, 1);
318 while (top_obj != NULL) {
319 struct ObjRec *obj_ptr=top_obj->next;
320
321 FreeObj(top_obj);
322 top_obj = obj_ptr;
323 }
324 }
325 if (writeFileFailed) {
326 FailToWriteFileMessage(tmpfile);
327 fclose(fp);
328 unlink(tmpfile);
329 writeFileFailed = FALSE;
330 return TRUE;
331 }
332 fflush(fp);
333 if (fstat(fileno(fp), &stat) < 0) {
334 fclose(fp);
335 unlink(tmpfile);
336 sprintf(gszMsgBox, TgLoadString(STID_FAIL_TO_FSTAT_ABORT_COPY), tmpfile);
337 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
338 return TRUE;
339 }
340
341 if (cut_buffer != NULL) free(cut_buffer);
342 cut_buffer = (char*)malloc((stat.st_size+1)*sizeof(char));
343 if (cut_buffer == NULL) FailAllocMessage();
344
345 rewind(fp);
346 if (read(fileno(fp), cut_buffer, stat.st_size) < stat.st_size) {
347 sprintf(gszMsgBox, TgLoadString(STID_ERR_READING_FILE_COPY_ABORT),
348 tmpfile);
349 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
350 } else {
351 if (!WriteBufToCutBuffer(cut_buffer, stat.st_size, FALSE, FALSE, NULL)) {
352 sprintf(gszMsgBox, TgLoadString(STID_COPY_FAILED_OBJ_MAYBE_TOO_BIG));
353 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
354 } else {
355 sprintf(gszMsgBox, TgLoadString(STID_COPY_BUFFER_UPDATED));
356 Msg(gszMsgBox);
357 }
358 }
359 fclose(fp);
360 unlink(tmpfile);
361 UtilFree(cut_buffer);
362
363 return (curChoice != DRAWTEXT);
364 }
365
CopyToCutBuffer()366 int CopyToCutBuffer()
367 /* returns FALSE if copying in text mode -- this is */
368 /* interpreted as an attempt to copy highlighted text */
369 {
370 int rc=TRUE, handle_edit_text_size=FALSE;
371
372 ResetCutBufferInfo();
373 if (curChoice == DRAWTEXT) {
374 if (escPressed) {
375 escPressed = FALSE;
376 Msg(TgLoadString(STID_ESC_KEY_PRESS_IGNORED));
377 }
378 if (!textHighlight) {
379 MsgBox(TgLoadString(STID_NO_TEXT_SELECTED_FOR_COPY), TOOL_NAME,
380 INFO_MB);
381 return FALSE;
382 } else {
383 if (editTextSize != 0) {
384 handle_edit_text_size = TRUE;
385 if (RestoreEditTextSize(curTextObj, TRUE)) {
386 UpdTextBBox(curTextObj);
387 }
388 }
389 if (CanCopyHighLightedTextAsUTF8Strings(NULL)) {
390 XEvent ev;
391
392 if (handle_edit_text_size && editTextSize != 0) {
393 if (RestoreEditTextSize(curTextObj, FALSE)) {
394 UpdTextBBox(curTextObj);
395 }
396 }
397 copyInDrawTextMode = TRUE;
398 copyDoubleByteStringInDrawTextMode = TRUE;
399 ev.type = KeyPress;
400 DrawText(&ev);
401 copyDoubleByteStringInDrawTextMode = FALSE;
402 copyInDrawTextMode = FALSE;
403 } else if (CanCopyHighLightedTextAsStrings()) {
404 XEvent ev;
405
406 if (handle_edit_text_size && editTextSize != 0) {
407 if (RestoreEditTextSize(curTextObj, FALSE)) {
408 UpdTextBBox(curTextObj);
409 }
410 }
411 copyInDrawTextMode = TRUE;
412 ev.type = KeyPress;
413 DrawText(&ev);
414 copyInDrawTextMode = FALSE;
415 } else {
416 #ifdef NOT_DEFINED
417 char *cut_buffer=NULL;
418 int cut_buffer_size=0;
419
420 GatherHighLightedTextAsStrings(&cut_buffer, &cut_buffer_size);
421 if (cut_buffer == NULL) {
422 ClearSelection();
423 } else {
424 if (WriteBufToCutBuffer(cut_buffer, cut_buffer_size-1, TRUE,
425 FALSE, NULL)) {
426 sprintf(gszMsgBox, TgLoadString(STID_COPY_BUFFER_UPDATED));
427 } else {
428 sprintf(gszMsgBox, TgLoadString(STID_COPY_FAIL_SEL_STR_MAY_TOO_LNG));
429 }
430 Msg(gszMsgBox);
431 free(cut_buffer);
432 }
433 #endif /* NOT_DEFINED */
434 /*
435 * create a partial text object with only the minilines, this
436 * will be done in CopyObjectToCutBuffer() below
437 */
438 }
439 }
440 } else if (topSel == NULL) {
441 MsgBox(TgLoadString(STID_NO_OBJ_SELECTED_FOR_COPY), TOOL_NAME, INFO_MB);
442 return TRUE;
443 }
444 rc = CopyObjectToCutBuffer(FALSE);
445 if (handle_edit_text_size && editTextSize != 0) {
446 if (RestoreEditTextSize(curTextObj, FALSE)) {
447 UpdTextBBox(curTextObj);
448 }
449 }
450 return rc;
451 }
452
CopyPlainTextAsObject()453 int CopyPlainTextAsObject()
454 /* returns FALSE if copying in text mode -- this is */
455 /* interpreted as an attempt to copy highlighted text */
456 {
457 if (!(curChoice == DRAWTEXT && textHighlight)) {
458 return (curChoice != DRAWTEXT);
459 }
460 return CopyObjectToCutBuffer(TRUE);
461 }
462
CutToCutBuffer()463 void CutToCutBuffer()
464 {
465 if (curChoice == DRAWTEXT && textCursorShown) {
466 CopyToCutBuffer();
467 DelSelText();
468 }
469 if (curChoice == NOTHING && topSel != NULL) {
470 CopyToCutBuffer();
471 DelAllSelObj();
472 }
473 }
474
PasteString(CutBuffer,highlight,record_cmd)475 unsigned int PasteString(CutBuffer, highlight, record_cmd)
476 char *CutBuffer;
477 int highlight, record_cmd;
478 {
479 char *c_ptr=NULL, *dest_c_ptr=NULL;
480 int x, y, num_lines=0, char_count, root_x, root_y, grid_x, grid_y;
481 unsigned int status=0, button_pressed=0;
482 struct ObjRec *obj_ptr=NULL;
483 struct TextRec *text_ptr=NULL;
484 Window root_win=None, child_win=None;
485 MiniLineInfo *pFirstMiniLine=NULL, *pLastMiniLine=NULL;
486
487 if (*CutBuffer == '\0') {
488 MsgBox(TgLoadString(STID_CUT_BUFFER_EMPTY), TOOL_NAME, INFO_MB);
489 return 0;
490 }
491 TieLooseEnds();
492 SetCurChoice(NOTHING);
493 if (topSel!=NULL) { HighLightReverse(); RemoveAllSel(); }
494
495 XQueryPointer(mainDisplay, drawWindow, &root_win, &child_win,
496 &root_x, &root_y, &x, &y, &status);
497 GridXY(x, y, &grid_x, &grid_y);
498
499 obj_ptr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
500 if (obj_ptr == NULL) FailAllocMessage();
501 memset(obj_ptr, 0, sizeof(struct ObjRec));
502
503 text_ptr = (struct TextRec *)malloc(sizeof(struct TextRec));
504 if (text_ptr == NULL) FailAllocMessage();
505 memset(text_ptr, 0, sizeof(struct TextRec));
506
507 for (c_ptr=CutBuffer, num_lines = 0; *c_ptr != '\0'; num_lines++) {
508 MiniLineInfo *pMiniLine=NULL;
509 if (lengthLimit256InInsertChar) {
510 char s[MAXSTRING+1];
511
512 char_count = 0;
513 dest_c_ptr = s;
514 while (*c_ptr != '\0' && *c_ptr != '\n' && *c_ptr != '\r') {
515 *dest_c_ptr++ = *c_ptr++;
516 if (++char_count == MAXSTRING) {
517 sprintf(gszMsgBox,
518 TgLoadString(STID_STRING_LEN_EXCEEDS_AND_TRUNC),
519 MAXSTRING);
520 Msg(gszMsgBox);
521 while (*c_ptr != '\0' && *c_ptr != '\n' && *c_ptr != '\r') {
522 c_ptr++;
523 }
524 break;
525 }
526 }
527 *dest_c_ptr = '\0';
528 pMiniLine = CreateMiniLineFromString(s, &pFirstMiniLine,
529 &pLastMiniLine);
530 } else {
531 unsigned char *psz_CR=(unsigned char *)strchr(c_ptr, '\r');
532 unsigned char *psz_LF=(unsigned char *)strchr(c_ptr, '\n');
533 int use_CR=FALSE, use_LF=FALSE;
534
535 if (psz_CR == NULL) {
536 if (psz_LF != NULL) {
537 use_LF = TRUE;
538 }
539 } else if (psz_CR == NULL) {
540 use_CR = TRUE;
541 } else if (psz_CR > psz_LF) {
542 use_LF = TRUE;
543 } else {
544 use_CR = TRUE;
545 }
546 if (use_CR) {
547 *psz_CR = '\0';
548 pMiniLine = CreateMiniLineFromString(c_ptr, &pFirstMiniLine,
549 &pLastMiniLine);
550 *psz_CR = '\n';
551 c_ptr = (char*)psz_CR;
552 } else if (use_LF) {
553 *psz_LF = '\0';
554 pMiniLine = CreateMiniLineFromString(c_ptr, &pFirstMiniLine,
555 &pLastMiniLine);
556 *psz_LF = '\r';
557 c_ptr = (char*)psz_LF;
558 } else {
559 pMiniLine = CreateMiniLineFromString(c_ptr, &pFirstMiniLine,
560 &pLastMiniLine);
561 c_ptr += strlen(c_ptr);
562 }
563 }
564 if (*c_ptr == '\n') {
565 c_ptr++;
566 if (c_ptr[1] == '\r') c_ptr++;
567 } else if (*c_ptr == '\r') {
568 c_ptr++;
569 if (c_ptr[1] == '\n') c_ptr++;
570 }
571 }
572 text_ptr->lines = num_lines;
573 text_ptr->minilines.first = pFirstMiniLine;
574 text_ptr->minilines.last = pLastMiniLine;
575 text_ptr->baseline_y = grid_y+pFirstMiniLine->asc;
576
577 CopyCurInfoIntoTextPtr(obj_ptr, text_ptr);
578
579 obj_ptr->x = grid_x;
580 obj_ptr->y = grid_y;
581 obj_ptr->type = OBJ_TEXT;
582 obj_ptr->color = colorIndex;
583 if (mainDisplay != NULL) {
584 UtilStrCpyN(obj_ptr->color_str, sizeof(obj_ptr->color_str),
585 colorMenuItems[colorIndex]);
586 }
587 obj_ptr->id = objId++;;
588 obj_ptr->dirty = FALSE;
589 obj_ptr->rotation = 0;
590 obj_ptr->detail.t = text_ptr;
591 obj_ptr->fattr = obj_ptr->lattr = NULL;
592 obj_ptr->ctm = NULL;
593
594 RecalcTextMetrics(text_ptr, grid_x, text_ptr->baseline_y);
595 UpdTextBBox(obj_ptr);
596 AddObj(NULL, topObj, obj_ptr);
597 button_pressed = PlaceTopObj(obj_ptr, NULL, NULL);
598
599 if (highlight) SelectTopObj();
600 if (record_cmd) RecordNewObjCmd();
601 SetFileModified(TRUE);
602 justDupped = FALSE;
603
604 return button_pressed;
605 }
606
607 static
CreateTmpBoxObj(LtX,LtY,RbX,RbY)608 struct ObjRec *CreateTmpBoxObj(LtX, LtY, RbX, RbY)
609 int LtX, LtY, RbX, RbY;
610 {
611 register struct BoxRec *box_ptr;
612 register struct ObjRec *obj_ptr;
613
614 box_ptr = (struct BoxRec *)malloc(sizeof(struct BoxRec));
615 if (box_ptr == NULL) FailAllocMessage();
616 memset(box_ptr, 0, sizeof(struct BoxRec));
617 box_ptr->fill = NONEPAT;
618 box_ptr->width = 0;
619 box_ptr->pen = NONEPAT;
620 box_ptr->dash = 0;
621
622 obj_ptr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
623 if (obj_ptr == NULL) FailAllocMessage();
624 memset(obj_ptr, 0, sizeof(struct ObjRec));
625
626 obj_ptr->bbox.ltx = obj_ptr->obbox.ltx = obj_ptr->x = LtX;
627 obj_ptr->bbox.lty = obj_ptr->obbox.lty = obj_ptr->y = LtY;
628 obj_ptr->bbox.rbx = obj_ptr->obbox.rbx = RbX;
629 obj_ptr->bbox.rby = obj_ptr->obbox.rby = RbY;
630 obj_ptr->type = OBJ_BOX;
631 obj_ptr->color = colorIndex;
632 if (mainDisplay != NULL) {
633 UtilStrCpyN(obj_ptr->color_str, sizeof(obj_ptr->color_str),
634 colorMenuItems[colorIndex]);
635 }
636 obj_ptr->id = 0;
637 obj_ptr->dirty = FALSE;
638 obj_ptr->rotation = 0;
639 obj_ptr->detail.b = box_ptr;
640 obj_ptr->fattr = obj_ptr->lattr = NULL;
641 obj_ptr->ctm = NULL;
642 obj_ptr->invisible = FALSE;
643 obj_ptr->trans_pat = FALSE;
644
645 return obj_ptr;
646 }
647
AssignNewObjIds(ObjPtr)648 void AssignNewObjIds(ObjPtr)
649 struct ObjRec *ObjPtr;
650 {
651 register struct ObjRec *obj_ptr;
652 register struct AttrRec *attr_ptr;
653
654 ObjPtr->id = objId++;
655 switch (ObjPtr->type) {
656 case OBJ_GROUP:
657 case OBJ_SYM:
658 case OBJ_ICON:
659 case OBJ_PIN:
660 for (obj_ptr=ObjPtr->detail.r->first; obj_ptr != NULL;
661 obj_ptr=obj_ptr->next) {
662 AssignNewObjIds(obj_ptr);
663 }
664 break;
665 default: break;
666 }
667 for (attr_ptr=ObjPtr->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
668 AssignNewObjIds(attr_ptr->obj);
669 }
670 }
671
672 #define CBF_NON_TGIF 0
673 #define CBF_TGIF_STRING 1
674 #define CBF_TGIF_OBJ 2
675
676 static
CutBufferType(cut_buffer)677 int CutBufferType(cut_buffer)
678 char *cut_buffer;
679 {
680 unsigned char header=TGIF_HEADER;
681
682 if (((unsigned char)(*cut_buffer)) == header) {
683 if (strncmp(&cut_buffer[1], "%TGIF", 5) == 0) {
684 return CBF_TGIF_OBJ;
685 } else if (strncmp(&cut_buffer[1], "state(", 6) == 0) {
686 /* very old tgif format (even before tgif-2.12) */
687 return CBF_TGIF_OBJ;
688 }
689 return CBF_TGIF_STRING;
690 }
691 return CBF_NON_TGIF;
692 }
693
694 static
GetObjsFromCutBuffer(cut_buffer,len,pp_top_obj,pp_bot_obj)695 int GetObjsFromCutBuffer(cut_buffer, len, pp_top_obj, pp_bot_obj)
696 char *cut_buffer;
697 int len;
698 struct ObjRec **pp_top_obj, **pp_bot_obj;
699 /* the cut_buffer is the original cut buffer shifted one byte */
700 {
701 FILE *fp=NULL;
702 int read_status=0;
703 char tmpfile[MAXSTRING];
704 struct ObjRec *obj_ptr=NULL, *saved_top_obj=NULL, *saved_bot_obj=NULL;
705
706 (*pp_top_obj) = (*pp_bot_obj) = NULL;
707
708 if (MkTempFile(tmpfile, sizeof(tmpfile), tmpDir, TOOL_NAME) == NULL) {
709 return FALSE;
710 }
711 // Naehring: added b to the mode string.
712 if ((fp=fopen(tmpfile, "wb+")) == NULL) {
713 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_WRITING),
714 tmpfile);
715 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
716 return FALSE;
717 }
718 writeFileFailed = FALSE;
719 if (write(fileno(fp), cut_buffer, len) < len) {
720 fclose(fp);
721 unlink(tmpfile);
722 sprintf(gszMsgBox, TgLoadString(STID_ERR_WRITING_FILE_PASTE_ABORT),
723 tmpfile);
724 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
725 return FALSE;
726 }
727 fflush(fp);
728 rewind(fp);
729
730 SetWatchCursor(drawWindow);
731 SetWatchCursor(mainWindow);
732
733 saved_top_obj = topObj;
734 saved_bot_obj = botObj;
735 curPage->top = topObj = NULL;
736 curPage->bot = botObj = NULL;
737
738 importingFile = TRUE;
739 pastingFile = TRUE;
740 readingPageNum = loadedCurPageNum = 0;
741 foundGoodStateObject = FALSE;
742 while ((read_status=ReadObj(fp, &obj_ptr)) == TRUE) {
743 if (obj_ptr != NULL) {
744 AdjForOldVersion(obj_ptr);
745 UnlockAnObj(obj_ptr);
746 AssignNewObjIds(obj_ptr);
747 AddObj(NULL, topObj, obj_ptr);
748 }
749 }
750 fclose(fp);
751 if (!PRTGIF && colorLayers && needToRedrawColorWindow) {
752 RedrawColorWindow();
753 }
754 importingFile = FALSE;
755 pastingFile = FALSE;
756 unlink(tmpfile);
757 SetDefaultCursor(mainWindow);
758 ShowCursor();
759
760 if (read_status == INVALID) {
761 sprintf(gszMsgBox, TgLoadString(STID_FILEVER_TOO_LARGE_PASTE_ABORT),
762 fileVersion);
763 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
764 return FALSE;
765 }
766 (*pp_top_obj) = topObj;
767 (*pp_bot_obj) = botObj;
768
769 curPage->top = topObj = saved_top_obj;
770 curPage->bot = botObj = saved_bot_obj;
771
772 return TRUE;
773 }
774
FreeSelectionOrCutBuffer(cut_buffer,from_selection)775 void FreeSelectionOrCutBuffer(cut_buffer, from_selection)
776 char *cut_buffer;
777 int from_selection;
778 {
779 if (from_selection) {
780 UtilFree(cut_buffer);
781 } else {
782 if (cut_buffer != NULL) XFree(cut_buffer);
783 }
784 }
785
FetchSelectionOrCutBuffer(pnLen,pnFromSelection)786 char *FetchSelectionOrCutBuffer(pnLen, pnFromSelection)
787 int *pnLen, *pnFromSelection;
788 {
789 int len=0;
790 unsigned long uLen=0L;
791 char *cut_buffer=GetTextBytesFromSelection(FALSE, &uLen);
792
793 *pnLen = 0;
794 *pnFromSelection = FALSE;
795 if (cut_buffer == NULL || uLen == 0L) {
796 if (pasteFromXSelectionOnly) return NULL;
797
798 cut_buffer = (char*)XFetchBytes(mainDisplay, &len);
799 if (len == 0) {
800 return NULL;
801 }
802 } else {
803 *pnFromSelection = TRUE;
804 len = (int)uLen;
805 }
806 *pnLen = len;
807
808 return cut_buffer;
809 }
810
811 static int pastingUTF8String=FALSE;
812
PasteFromCutBuffer()813 int PasteFromCutBuffer()
814 /* returns FALSE if pasting in text mode and non-tgif bytes are */
815 /* in the cut buffer -- this is interpreted as an attempt to */
816 /* paste into the current text */
817 {
818 int len=0, ltx=0, lty=0, rbx=0, rby=0, dx=0, dy=0, from_selection=FALSE;
819 char *cut_buffer=NULL, *orig_cut_buffer=NULL;
820 struct ObjRec *obj_ptr=NULL, *tmp_obj=NULL;
821 struct ObjRec *saved_top_obj=NULL, *saved_bot_obj=NULL;
822 struct ObjRec *pasted_top_obj=NULL, *pasted_bot_obj=NULL;
823 struct ObjRec *tmp_top_obj=NULL, *tmp_bot_obj=NULL;
824 StrSegInfo ssi;
825
826 memset(&ssi, 0, sizeof(StrSegInfo));
827
828 if (curChoice == DRAWTEXT && textCursorShown &&
829 CanPasteUTF8StringIntoText(&ssi)) {
830 pastingUTF8String = TRUE;
831 }
832 cut_buffer = FetchSelectionOrCutBuffer(&len, &from_selection);
833 if (cut_buffer == NULL) {
834 MsgBox(TgLoadString(STID_CUT_BUFFER_EMPTY), TOOL_NAME, INFO_MB);
835 pastingUTF8String = FALSE;
836 return TRUE;
837 }
838 orig_cut_buffer = cut_buffer;
839
840 if (CutBufferType(cut_buffer) != CBF_TGIF_OBJ) {
841 if (curChoice == DRAWTEXT) {
842 XEvent ev;
843
844 FreeSelectionOrCutBuffer(cut_buffer, from_selection);
845 pasteInDrawTextMode = TRUE;
846 ev.type = KeyPress;
847 DrawText(&ev);
848 pastingUTF8String = FALSE;
849 return FALSE;
850 }
851 #ifndef _NO_KINPUT
852 if (copyAndPasteJIS) {
853 CvtJisToEuc(cut_buffer, cut_buffer);
854 }
855 #endif /* ~_NO_KINPUT */
856 Msg(TgLoadString(STID_PASTE_FROM_NON_TGIF));
857 PasteString(cut_buffer, TRUE, TRUE);
858 FreeSelectionOrCutBuffer(cut_buffer, from_selection);
859 pastingUTF8String = FALSE;
860
861 return TRUE;
862 }
863 if (curChoice == DRAWTEXT) {
864 SaveCursorPositionInCurText();
865 } else {
866 MakeQuiescent();
867 }
868 if (!GetObjsFromCutBuffer(&cut_buffer[1], len-1, &pasted_top_obj,
869 &pasted_bot_obj)) {
870 FreeSelectionOrCutBuffer(orig_cut_buffer, from_selection);
871 pastingUTF8String = FALSE;
872 return TRUE;
873 }
874 FreeSelectionOrCutBuffer(orig_cut_buffer, from_selection);
875
876 saved_top_obj = topObj;
877 saved_bot_obj = botObj;
878 curPage->top = topObj = pasted_top_obj;
879 curPage->bot = botObj = pasted_bot_obj;
880
881 if (curChoice == DRAWTEXT && textCursorShown && topObj != NULL &&
882 topObj == botObj && topObj->type == OBJ_TEXT) {
883 /* we are pasting minilines and not object */
884 struct ObjRec *partial_text_obj_ptr=topObj;
885
886 RestoreCursorPositionInCurText();
887 curPage->top = topObj = saved_top_obj;
888 curPage->bot = botObj = saved_bot_obj;
889
890 if (curStrBlock->type == SB_SUPSUB_CENTER) {
891 strcpy(gszMsgBox, TgLoadString(STID_CANNOT_PASTE_MIXED_TEXT));
892 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
893 } else {
894 Msg(TgLoadString(STID_STR_BLOCKS_PASTED_FROM_TGIF));
895 PasteMiniLinesAtCursor(partial_text_obj_ptr);
896 }
897 FreeObj(partial_text_obj_ptr);
898 pastingUTF8String = FALSE;
899
900 return FALSE;
901 }
902 if (curChoice == DRAWTEXT) {
903 /* we've made a mistake earlier on, should have MakeQuiescent() */
904 struct ObjRec *pasted_top_obj=topObj, *pasted_bot_obj=botObj;
905
906 curPage->top = topObj = saved_top_obj;
907 curPage->bot = botObj = saved_bot_obj;
908 RestoreCursorPositionInCurText();
909
910 MakeQuiescent();
911
912 saved_top_obj = topObj;
913 saved_bot_obj = botObj;
914 curPage->top = topObj = pasted_top_obj;
915 curPage->bot = botObj = pasted_bot_obj;
916 }
917 if (topObj != NULL) SetFileModified(TRUE);
918
919 ltx = topObj->obbox.ltx;
920 lty = topObj->obbox.lty;
921 rbx = topObj->obbox.rbx;
922 rby = topObj->obbox.rby;
923 for (obj_ptr = topObj->next; obj_ptr != NULL; obj_ptr = obj_ptr->next) {
924 if (obj_ptr->obbox.ltx < ltx) ltx = obj_ptr->obbox.ltx;
925 if (obj_ptr->obbox.lty < lty) lty = obj_ptr->obbox.lty;
926 if (obj_ptr->obbox.rbx > rbx) rbx = obj_ptr->obbox.rbx;
927 if (obj_ptr->obbox.rby > rby) rby = obj_ptr->obbox.rby;
928 }
929 tmp_obj = CreateTmpBoxObj(ltx, lty, rbx, rby);
930
931 tmp_top_obj = topObj;
932 tmp_bot_obj = botObj;
933 curPage->top = topObj = NULL;
934 curPage->bot = botObj = NULL;
935 PlaceTopObj(tmp_obj, saved_top_obj, saved_bot_obj);
936 curPage->top = topObj = tmp_top_obj;
937 curPage->bot = botObj = tmp_bot_obj;
938
939 dx = tmp_obj->obbox.ltx - ltx;
940 dy = tmp_obj->obbox.lty - lty;
941 FreeBoxObj(tmp_obj);
942
943 for (obj_ptr=topObj; obj_ptr != NULL; obj_ptr=obj_ptr->next) {
944 MoveObj(obj_ptr, dx, dy);
945 }
946
947 SelAllObj(FALSE, FALSE);
948
949 if (botObj != NULL) {
950 botObj->next = saved_top_obj;
951 } else {
952 curPage->top = topObj = saved_top_obj;
953 }
954
955 if (saved_top_obj != NULL) {
956 saved_top_obj->prev = botObj;
957 curPage->bot = botObj = saved_bot_obj;
958 }
959 RedrawDrawWindow(botObj);
960 PrepareToRecord(CMD_NEW, NULL, NULL, 0);
961 RecordCmd(CMD_NEW, NULL, topSel, botSel, numObjSelected);
962 HighLightForward();
963
964 Msg(TgLoadString(STID_OBJS_PASTED_FROM_TGIF));
965 pastingUTF8String = FALSE;
966 return TRUE;
967 }
968
PasteFromFile()969 int PasteFromFile()
970 /* returns FALSE if pasting in text mode and non-tgif bytes are */
971 /* in the cut buffer -- this is interpreted as an attempt to */
972 /* paste into the current text */
973 {
974 char file_name[MAXPATHLENGTH+1];
975 FILE *fp=NULL;
976 char inbuf[MAXSTRING+1], *cut_buffer=NULL;
977 int size=0, pos=0;
978
979 if (SelectFileNameToPaste(TgLoadString(STID_SEL_A_FILE_TO_PASTE_DOTS),
980 file_name) == INVALID) {
981 return TRUE;
982 } else if (FileIsRemote(file_name)) {
983 MsgBox(TgLoadString(STID_PASTING_REMOTE_FILE_NOT_SUP), TOOL_NAME,
984 INFO_MB);
985 return TRUE;
986 }
987 if (curChoice == DRAWTEXT) {
988 XEvent ev;
989
990 pasteInDrawTextMode = TRUE;
991 pasteFromFileInDrawTextMode = TRUE;
992 strcpy(pasteFromFileName, file_name);
993 ev.type = KeyPress;
994 DrawText(&ev);
995 return FALSE;
996 }
997 if ((fp=fopen(file_name, "r")) == NULL) {
998 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_READING),
999 file_name);
1000 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1001 return TRUE;
1002 }
1003 while (fgets(inbuf, MAXSTRING, fp) != NULL) size += strlen(inbuf);
1004 fclose(fp);
1005 if (size == 0) {
1006 sprintf(gszMsgBox, TgLoadString(STID_NAMED_FILE_IS_EMPTY), file_name);
1007 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1008 return TRUE;
1009 }
1010 cut_buffer = (char*)malloc((size+2)*sizeof(char));
1011 if (cut_buffer == NULL) {
1012 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_MALLOC_NUM_BYTES), size+2);
1013 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1014 return TRUE;
1015 }
1016 if ((fp=fopen(file_name, "r")) == NULL) {
1017 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_OPEN_FILE_FOR_READING),
1018 file_name);
1019 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1020 return TRUE;
1021 }
1022 while (fgets(&cut_buffer[pos], MAXSTRING, fp) != NULL) {
1023 pos += strlen(&cut_buffer[pos]);
1024 }
1025 fclose(fp);
1026 #ifndef _NO_NKF
1027 if (Tg_useNKF()) {
1028 char *out_buffer=(char*)malloc(size+2);
1029
1030 if (out_buffer == NULL) FailAllocMessage();
1031 Tg_do_kconv(cut_buffer, out_buffer, size+2);
1032 PasteString(out_buffer, TRUE, TRUE);
1033 free(out_buffer);
1034 } else {
1035 #ifndef _NO_KINPUT
1036 if (copyAndPasteJIS) {
1037 CvtJisToEuc(cut_buffer, cut_buffer);
1038 }
1039 #endif /* ~_NO_KINPUT */
1040 PasteString(cut_buffer, TRUE, TRUE);
1041 }
1042 #else /* _NO_NKF */
1043 PasteString(cut_buffer, TRUE, TRUE);
1044 #endif /* ~_NO_NKF */
1045
1046 return TRUE;
1047 }
1048
1049 #ifdef NOT_DEFINED
1050 static
WindowPropertyExists(dpy,win,property)1051 int WindowPropertyExists(dpy, win, property)
1052 Display *dpy;
1053 Window win;
1054 Atom property;
1055 {
1056 Atom type_atom=(Atom)0;
1057 unsigned long ulBytesLeft=0L, ulLen=0L;
1058 char *psz=NULL;
1059 int nFormat=0, rc=FALSE;
1060 unsigned long ulCurSize=0L, ulTotalLeft=0x10000L;
1061 int nStatus=XGetWindowProperty(dpy, win, property,
1062 ulCurSize, ulTotalLeft, False, AnyPropertyType,
1063 &type_atom, &nFormat, &ulLen, &ulBytesLeft,
1064 (unsigned char **)(&psz));
1065
1066 rc = (nStatus != None);
1067
1068 if (psz != NULL) XFree(psz);
1069
1070 return rc;
1071 }
1072 #endif /* NOT_DEFINED */
1073
1074 static
GetTextBytesFromWindowProperty(win,property,compound_text,pul_len,delete_prop)1075 char *GetTextBytesFromWindowProperty(win, property, compound_text, pul_len,
1076 delete_prop)
1077 Window win;
1078 Atom property;
1079 int compound_text, delete_prop;
1080 unsigned long *pul_len;
1081 {
1082 int actual_format=0;
1083 unsigned long long_offset=0L, bytes_after=0L, nitems=0L, total=0L;
1084 char *cut_buffer=NULL, *psz=NULL;
1085 Atom actual_type=(Atom)0;
1086
1087 /*
1088 * Accorind to the documentation for XGetWindowProperty(), if it is called
1089 * with AnyPropertyType, the following is true:
1090 * N = actual length of the stored property in bytes
1091 * (even if the format is 16 or 32)
1092 * I = 4 * long_offset
1093 * T = N - I
1094 * L = MINIMUM(T, 4 * long_length)
1095 * A = N - (I + L)
1096 * We use a fixed long_legnth of 0x4000L
1097 * L is nitems
1098 * A is bytes_after
1099 */
1100 if (debugCopyPaste > 1) {
1101 char *atom_name=NULL;
1102
1103 atom_name = XGetAtomName(mainDisplay, property);
1104 fprintf(stderr, "Property name is '%s'.\n", atom_name);
1105 XFree(atom_name);
1106 }
1107 while (XGetWindowProperty(mainDisplay, win, property,
1108 long_offset, 0x4000L, delete_prop, AnyPropertyType,
1109 &actual_type, &actual_format, &nitems, &bytes_after,
1110 (unsigned char **)(&psz)) == Success) {
1111 if (debugCopyPaste) {
1112 static int n=0;
1113 fprintf(stderr, "[%1d] actual_format = %1d, nitems = %1d\n", ++n,
1114 (int)actual_format, (int)nitems);
1115 }
1116 if (psz != NULL && nitems > 0) {
1117 unsigned int bytes_per_item=(actual_format>>3);
1118 unsigned int bytes_got=(bytes_per_item==1 ? nitems :
1119 (bytes_per_item*nitems));
1120
1121 total += bytes_got;
1122 if (cut_buffer == NULL) {
1123 cut_buffer = (char*)malloc(total+1);
1124 } else {
1125 cut_buffer = (char*)realloc(cut_buffer, total+1);
1126 }
1127 if (cut_buffer == NULL) FailAllocMessage();
1128 memcpy(&cut_buffer[long_offset<<2], psz, bytes_got);
1129 cut_buffer[total] = '\0';
1130 long_offset += (bytes_got>>2);
1131 }
1132 if (psz != NULL) XFree(psz);
1133
1134 if (nitems == 0 || bytes_after == 0L) {
1135 break;
1136 }
1137 }
1138 *pul_len = total;
1139
1140 return cut_buffer;
1141 }
1142
1143 static
GetTextBytesFromGivenSelection(compound_text,pulLen,which_selection,paste_utf8_string,pssi,pn_timeout_msg_displayed)1144 char *GetTextBytesFromGivenSelection(compound_text, pulLen, which_selection,
1145 paste_utf8_string, pssi, pn_timeout_msg_displayed)
1146 int compound_text, which_selection, paste_utf8_string;
1147 int *pn_timeout_msg_displayed;
1148 unsigned long *pulLen;
1149 StrSegInfo *pssi;
1150 /* the returned string should be freed by calling UtilFree() */
1151 {
1152 int done=FALSE, need_to_try_text=FALSE, need_to_try_utf8=FALSE;
1153 char *cut_buffer=NULL;
1154 time_t tloc, endtime;
1155 Window selection_owner_win=None;
1156 XEvent ev;
1157
1158 selection_owner_win = XGetSelectionOwner(mainDisplay, which_selection);
1159 if (selection_owner_win == None) {
1160 return NULL;
1161 }
1162 if (compound_text) {
1163 XConvertSelection(mainDisplay, which_selection, compoundTextAtom,
1164 tmpSelectionAtom, mainWindow, lastKeyOrBtnEvInfo.time);
1165 } else {
1166 if (paste_utf8_string) {
1167 /* try tgif object first, then try utf8, then try text */
1168 need_to_try_utf8 = TRUE;
1169 } else {
1170 /* try tgif object then try text */
1171 need_to_try_text = TRUE;
1172 }
1173 XConvertSelection(mainDisplay, which_selection, tgifProtocolAtom,
1174 tmpSelectionAtom, mainWindow, lastKeyOrBtnEvInfo.time);
1175 }
1176 if (XCheckMaskEvent(mainDisplay, ExposureMask, &ev) ||
1177 XCheckMaskEvent(mainDisplay, VisibilityChangeMask, &ev)) {
1178 ExposeEventHandler(&ev, TRUE);
1179 }
1180 XFlush(mainDisplay);
1181
1182 time(&tloc);
1183 endtime = tloc + pasteFromSelectionTimeout;
1184
1185 SaveStatusStrings();
1186 sprintf(gszMsgBox, TgLoadString(STID_CONVERTING_GIVEN_DOTS),
1187 (compound_text ? "COMPOUND_TEXT" : "TEXT"));
1188 SetStringStatus(gszMsgBox);
1189 while (!done) {
1190 if (XPending(mainDisplay)) {
1191 XNextEvent(mainDisplay, &ev);
1192 if (ev.type == SelectionNotify) {
1193 XSelectionEvent *xselectionev=(&ev.xselection);
1194
1195 if (xselectionev->property == None) {
1196 /* conversion has been refused */
1197 if (paste_utf8_string) {
1198 if (need_to_try_utf8) {
1199 need_to_try_utf8 = FALSE;
1200 need_to_try_text = TRUE;
1201 XConvertSelection(mainDisplay, which_selection,
1202 utf8StringAtom, tmpSelectionAtom, mainWindow,
1203 lastKeyOrBtnEvInfo.time);
1204 continue;
1205 } else if (need_to_try_text) {
1206 need_to_try_text = FALSE;
1207 XConvertSelection(mainDisplay, which_selection,
1208 textAtom, tmpSelectionAtom, mainWindow,
1209 lastKeyOrBtnEvInfo.time);
1210 continue;
1211 }
1212 } else {
1213 if (need_to_try_text) {
1214 need_to_try_text = FALSE;
1215 need_to_try_utf8 = TRUE;
1216 XConvertSelection(mainDisplay, which_selection,
1217 textAtom, tmpSelectionAtom, mainWindow,
1218 lastKeyOrBtnEvInfo.time);
1219 continue;
1220 } else if (need_to_try_utf8) {
1221 need_to_try_utf8 = FALSE;
1222 XConvertSelection(mainDisplay, which_selection,
1223 utf8StringAtom, tmpSelectionAtom, mainWindow,
1224 lastKeyOrBtnEvInfo.time);
1225 continue;
1226 }
1227 }
1228 if (pasteFromXSelectionOnly) {
1229 Msg(TgLoadString(STID_SELECTION_CONV_REFUSED));
1230 } else {
1231 TwoLineMsg(TgLoadString(STID_SELECTION_CONV_REFUSED),
1232 TgLoadString(STID_TRY_PASTE_WITH_OLD_X_MECH));
1233 }
1234 } else {
1235 cut_buffer = GetTextBytesFromWindowProperty(
1236 ev.xselection.requestor,
1237 ev.xselection.property, compound_text, pulLen, True);
1238 if (cut_buffer == NULL || (pulLen != NULL && *pulLen == 0L)) {
1239 if (paste_utf8_string) {
1240 if (need_to_try_utf8) {
1241 need_to_try_utf8 = FALSE;
1242 need_to_try_text = TRUE;
1243 XConvertSelection(mainDisplay, which_selection,
1244 utf8StringAtom, tmpSelectionAtom, mainWindow,
1245 lastKeyOrBtnEvInfo.time);
1246 continue;
1247 } else if (need_to_try_text) {
1248 need_to_try_text = FALSE;
1249 XConvertSelection(mainDisplay, which_selection,
1250 textAtom, tmpSelectionAtom, mainWindow,
1251 lastKeyOrBtnEvInfo.time);
1252 continue;
1253 }
1254 } else {
1255 if (need_to_try_text) {
1256 need_to_try_text = FALSE;
1257 need_to_try_utf8 = TRUE;
1258 XConvertSelection(mainDisplay, which_selection,
1259 textAtom, tmpSelectionAtom, mainWindow,
1260 lastKeyOrBtnEvInfo.time);
1261 continue;
1262 } else if (need_to_try_utf8) {
1263 need_to_try_utf8 = FALSE;
1264 XConvertSelection(mainDisplay, which_selection,
1265 utf8StringAtom, tmpSelectionAtom, mainWindow,
1266 lastKeyOrBtnEvInfo.time);
1267 continue;
1268 }
1269 }
1270 }
1271 }
1272 done = TRUE;
1273 } else if (ev.type == SelectionRequest) {
1274 HandleSelectionRequest(&ev);
1275 }
1276 } else {
1277 MillisecondSleep(100);
1278 }
1279 time(&tloc);
1280 if (tloc >= endtime) break;
1281 }
1282 RestoreStatusStrings();
1283
1284 if (!done) {
1285 if (*pn_timeout_msg_displayed) {
1286 /* don't display the timeout message again */
1287 } else {
1288 *pn_timeout_msg_displayed = TRUE;
1289 sprintf(gszMsgBox, TgLoadString(STID_TIMEOUT_CONVERT_GIVEN),
1290 (compound_text ? "COMPOUND_TEXT" : "TEXT"));
1291 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1292 }
1293 UtilFree(cut_buffer);
1294
1295 return NULL;
1296 }
1297 if (cut_buffer != NULL) {
1298 if (paste_utf8_string && CutBufferType(cut_buffer) != CBF_TGIF_OBJ) {
1299 if (!ConvertToOrFromUTF8(CONVERT_FROM_UTF8,
1300 (canvasFontDoubleByte ? curFont : pssi->font), &cut_buffer)) {
1301 UtilFree(cut_buffer);
1302 return NULL;
1303 }
1304 } else {
1305 #ifndef _NO_KINPUT
1306 if (cut_buffer) CvtCompoundTextToEuc(cut_buffer, cut_buffer);
1307 #endif /* ~_NO_KINPUT */
1308 }
1309 }
1310 return cut_buffer;
1311 }
1312
GetTextBytesFromSelection(compound_text,pulLen)1313 char *GetTextBytesFromSelection(compound_text, pulLen)
1314 int compound_text;
1315 unsigned long *pulLen;
1316 /* the returned string should be freed by calling UtilFree() */
1317 {
1318 int i=0, paste_utf8_string=FALSE, timeout_msg_displayed=FALSE;
1319 char *cut_buffer=NULL;
1320 StrSegInfo ssi;
1321
1322 if (pulLen != NULL) *pulLen = 0L;
1323
1324 memset(&ssi, 0, sizeof(StrSegInfo));
1325 if (curChoice == DRAWTEXT && textCursorShown && pastingUTF8String) {
1326 if (!textHighlight) {
1327 if (canvasFontDoubleByte && CanPasteUTF8StringIntoText(&ssi)) {
1328 if (ssi.double_byte) {
1329 SetCopyUTF8FontInfo(&ssi, TRUE);
1330 }
1331 paste_utf8_string = TRUE;
1332 } else if (CanFindDoubleByteFontAtCursor(&ssi)) {
1333 if (ssi.double_byte) {
1334 SetCopyUTF8FontInfo(&ssi, TRUE);
1335 }
1336 paste_utf8_string = TRUE;
1337 }
1338 } else if (CanPasteUTF8StringIntoText(&ssi)) {
1339 if (ssi.double_byte) {
1340 SetCopyUTF8FontInfo(&ssi, TRUE);
1341 }
1342 paste_utf8_string = TRUE;
1343 }
1344 }
1345 SaveStatusStrings();
1346 sprintf(gszMsgBox, TgLoadString(STID_CONVERTING_GIVEN_DOTS),
1347 (compound_text ? "COMPOUND_TEXT" : "TEXT"));
1348 SetStringStatus(gszMsgBox);
1349 for (i=0; gaAllSelectionAtom[i] != (Atom)0; i++) {
1350 cut_buffer = GetTextBytesFromGivenSelection(compound_text, pulLen,
1351 gaAllSelectionAtom[i], paste_utf8_string, &ssi,
1352 &timeout_msg_displayed);
1353 if (cut_buffer == NULL || (pulLen != NULL && *pulLen == 0L)) {
1354 continue;
1355 } else {
1356 return cut_buffer;
1357 }
1358 }
1359 RestoreStatusStrings();
1360 /*
1361 * If nothing else worked, go back to the the old way of getting data from
1362 * the root window.
1363 */
1364 if (!timeout_msg_displayed) {
1365 cut_buffer = GetTextBytesFromWindowProperty(rootWindow, XA_CUT_BUFFER0,
1366 compound_text, pulLen, False);
1367 if (cut_buffer != NULL) {
1368 if (paste_utf8_string && CutBufferType(cut_buffer) != CBF_TGIF_OBJ) {
1369 if (!ConvertToOrFromUTF8(CONVERT_FROM_UTF8,
1370 (canvasFontDoubleByte ? curFont: ssi.font), &cut_buffer)) {
1371 UtilFree(cut_buffer);
1372 return NULL;
1373 }
1374 } else {
1375 #ifndef _NO_KINPUT
1376 if (cut_buffer) CvtCompoundTextToEuc(cut_buffer, cut_buffer);
1377 #endif /* ~_NO_KINPUT */
1378 }
1379 }
1380 }
1381 return cut_buffer;
1382 }
1383
PasteCompoundText()1384 int PasteCompoundText()
1385 {
1386 unsigned long uLen=0L;
1387 char *cut_buffer=NULL;
1388
1389 if (curChoice == DRAWTEXT) {
1390 XEvent ev;
1391
1392 pasteInDrawTextMode = TRUE;
1393 pasteCompoundTextInDrawTextMode = TRUE;
1394 ev.type = KeyPress;
1395 DrawText(&ev);
1396 return FALSE;
1397 }
1398 cut_buffer = GetTextBytesFromSelection(TRUE, &uLen);
1399 if (cut_buffer == NULL || uLen == 0L) {
1400 return TRUE;
1401 }
1402 Msg(TgLoadString(STID_PASTE_COMP_TEXT_FROM_NON_TGIF));
1403 PasteString(cut_buffer, TRUE, TRUE);
1404 UtilFree(cut_buffer);
1405
1406 return TRUE;
1407 }
1408
CopyDoubleByteString()1409 int CopyDoubleByteString()
1410 /* returns FALSE if copying in text mode -- this is */
1411 /* interpreted as an attempt to copy highlighted text */
1412 {
1413 int handle_edit_text_size=FALSE;
1414
1415 if (curChoice == DRAWTEXT) {
1416 if (escPressed) {
1417 escPressed = FALSE;
1418 Msg(TgLoadString(STID_ESC_KEY_PRESS_IGNORED));
1419 }
1420 if (!textHighlight) {
1421 MsgBox(TgLoadString(STID_NO_TEXT_SELECTED_FOR_COPY), TOOL_NAME,
1422 INFO_MB);
1423 return FALSE;
1424 } else {
1425 if (editTextSize != 0) {
1426 handle_edit_text_size = TRUE;
1427 if (RestoreEditTextSize(curTextObj, TRUE)) {
1428 UpdTextBBox(curTextObj);
1429 }
1430 }
1431 if (CanCopyHighLightedTextAsUTF8Strings(NULL)) {
1432 XEvent ev;
1433
1434 if (handle_edit_text_size && editTextSize != 0) {
1435 if (RestoreEditTextSize(curTextObj, FALSE)) {
1436 UpdTextBBox(curTextObj);
1437 }
1438 }
1439 copyInDrawTextMode = TRUE;
1440 copyDoubleByteStringInDrawTextMode = TRUE;
1441 ev.type = KeyPress;
1442 DrawText(&ev);
1443 copyDoubleByteStringInDrawTextMode = FALSE;
1444 copyInDrawTextMode = FALSE;
1445
1446 return FALSE;
1447 }
1448 }
1449 }
1450 return TRUE;
1451 }
1452
PasteDoubleByteString()1453 int PasteDoubleByteString()
1454 {
1455 int rc=0;
1456
1457 pastingUTF8String = TRUE;
1458 rc = PasteFromCutBuffer();
1459 pastingUTF8String = FALSE;
1460
1461 return rc;
1462 }
1463
CleanUpCutBuffer()1464 void CleanUpCutBuffer()
1465 {
1466 copyingToCutBuffer = FALSE;
1467 }
1468
1469 /* ----------------------- Properties ----------------------- */
1470
1471 static
SkipIntProp(lWhich,plSkip)1472 void SkipIntProp(lWhich, plSkip)
1473 long lWhich, *plSkip;
1474 {
1475 (*plSkip) |= lWhich;
1476 }
1477
1478 static
TestStringProp(n1,n2,psz1,psz2,lWhich,plSkip)1479 void TestStringProp(n1, n2, psz1, psz2, lWhich, plSkip)
1480 int n1, n2;
1481 char *psz1, *psz2; /* psz2 cannot be NULL */
1482 long lWhich, *plSkip;
1483 {
1484 if (n1 != n2 ||
1485 ((psz1 == NULL || *psz1 == '\0') && *psz2 != '\0') ||
1486 ((psz1 != NULL && *psz1 != '\0') && strcmp(psz1, psz2) != 0)) {
1487 SkipIntProp(lWhich, plSkip);
1488 }
1489 }
1490
1491 static
SetStringProp(n1,pn2,psz1,psz2)1492 void SetStringProp(n1, pn2, psz1, psz2)
1493 int n1, *pn2;
1494 char *psz1, *psz2; /* psz2 cannot be NULL */
1495 {
1496 *pn2 = n1;
1497 if (psz1 == NULL) {
1498 *psz2 = '\0';
1499 } else {
1500 strcpy(psz2, psz1);
1501 }
1502 }
1503
1504 static
TestIntProp(n1,n2,lWhich,plSkip)1505 void TestIntProp(n1, n2, lWhich, plSkip)
1506 int n1, n2;
1507 long lWhich, *plSkip;
1508 {
1509 if (n1 != n2) SkipIntProp(lWhich, plSkip);
1510 }
1511
1512 static
TestFontProp(nDoubleByte1,nFont1,nStyle1,nDoubleByte2,nFont2,nStyle2,lWhich,plSkip)1513 void TestFontProp(nDoubleByte1, nFont1, nStyle1, nDoubleByte2, nFont2,
1514 nStyle2, lWhich, plSkip)
1515 int nDoubleByte1, nFont1, nStyle1;
1516 int nDoubleByte2, nFont2, nStyle2;
1517 long lWhich, *plSkip;
1518 {
1519 if (nStyle1 != nStyle2) {
1520 SkipIntProp(lWhich, plSkip);
1521 } else if (nDoubleByte1 != nDoubleByte2) {
1522 SkipIntProp(lWhich, plSkip);
1523 } else if (nDoubleByte1) {
1524 if (nFont1 != nFont2) {
1525 SkipIntProp(lWhich, plSkip);
1526 }
1527 } else {
1528 if (nFont1 != nFont2) {
1529 SkipIntProp(lWhich, plSkip);
1530 }
1531 }
1532 }
1533
1534 static
TestCTMProp(ctm1,transformed,ctm2,lWhich,plSkip)1535 void TestCTMProp(ctm1, transformed, ctm2, lWhich, plSkip)
1536 struct XfrmMtrxRec *ctm1, *ctm2;
1537 int transformed;
1538 long lWhich, *plSkip;
1539 {
1540 if ((ctm1 == NULL && transformed) ||
1541 (ctm1 != NULL && (!transformed ||
1542 ctm1->m[0] != ctm2->m[0] ||
1543 ctm1->m[1] != ctm2->m[1] ||
1544 ctm1->m[2] != ctm2->m[2] ||
1545 ctm1->m[3] != ctm2->m[3] ||
1546 ctm1->t[0] != ctm2->t[0] ||
1547 ctm1->t[1] != ctm2->t[1]))) {
1548 SkipIntProp(lWhich, plSkip);
1549 }
1550 }
1551
SetIntPropertyMask(lWhich,nValue,pszValue,plMask,plSkip,pProp)1552 void SetIntPropertyMask(lWhich, nValue, pszValue, plMask, plSkip, pProp)
1553 long lWhich, *plMask, *plSkip;
1554 int nValue;
1555 char *pszValue;
1556 struct PropertiesRec *pProp;
1557 {
1558 if (((*plSkip) & lWhich) == lWhich) {
1559 /*
1560 * this property is inconsistent, continue skipping it
1561 */
1562 } else if (((*plMask) & lWhich) == lWhich) {
1563 /*
1564 * this property was set before, if it's not the same, skip/invalidate it
1565 */
1566 switch (lWhich) {
1567 case PROP_MASK_COLOR:
1568 TestStringProp(nValue, pProp->color, pszValue, pProp->color_str,
1569 lWhich, plSkip);
1570 break;
1571 case PROP_MASK_WIDTH:
1572 TestStringProp(nValue, pProp->width, pszValue, pProp->width_spec,
1573 lWhich, plSkip);
1574 break;
1575 case PROP_MASK_AW:
1576 TestStringProp(nValue, pProp->aw, pszValue, pProp->aw_spec,
1577 lWhich, plSkip);
1578 break;
1579 case PROP_MASK_AH:
1580 TestStringProp(nValue, pProp->ah, pszValue, pProp->ah_spec,
1581 lWhich, plSkip);
1582 break;
1583 case PROP_MASK_TRANSPAT:
1584 TestIntProp(nValue, pProp->trans_pat, lWhich, plSkip);
1585 break;
1586 case PROP_MASK_FILL:
1587 TestIntProp(nValue, pProp->fill, lWhich, plSkip);
1588 break;
1589 case PROP_MASK_PEN:
1590 TestIntProp(nValue, pProp->pen, lWhich, plSkip);
1591 break;
1592 case PROP_MASK_DASH:
1593 TestIntProp(nValue, pProp->dash, lWhich, plSkip);
1594 break;
1595 case PROP_MASK_ARROW_STYLE:
1596 TestIntProp(nValue, pProp->arrow_style, lWhich, plSkip);
1597 break;
1598 case PROP_MASK_CURVED:
1599 TestIntProp(nValue, pProp->curved, lWhich, plSkip);
1600 break;
1601 case PROP_MASK_RCB_RADIUS:
1602 TestIntProp(nValue, pProp->rcb_radius, lWhich, plSkip);
1603 break;
1604 case PROP_MASK_TEXT_JUST:
1605 TestIntProp(nValue, pProp->text_just, lWhich, plSkip);
1606 break;
1607 case PROP_MASK_TEXT_SZ_UNIT:
1608 TestIntProp(nValue, pProp->text_sz_unit, lWhich, plSkip);
1609 break;
1610 case PROP_MASK_UNDERLINE_ON:
1611 TestIntProp(nValue, pProp->underline_on, lWhich, plSkip);
1612 break;
1613 case PROP_MASK_OVERLINE_ON:
1614 TestIntProp(nValue, pProp->overline_on, lWhich, plSkip);
1615 break;
1616 }
1617 } else {
1618 /* this property is never set, go set it */
1619 (*plMask) |= lWhich;
1620 switch (lWhich) {
1621 case PROP_MASK_COLOR:
1622 SetStringProp(nValue, &pProp->color, pszValue, pProp->color_str);
1623 break;
1624 case PROP_MASK_WIDTH:
1625 SetStringProp(nValue, &pProp->width, pszValue, pProp->width_spec);
1626 break;
1627 case PROP_MASK_AW:
1628 SetStringProp(nValue, &pProp->aw, pszValue, pProp->aw_spec);
1629 break;
1630 case PROP_MASK_AH:
1631 SetStringProp(nValue, &pProp->ah, pszValue, pProp->ah_spec);
1632 break;
1633 case PROP_MASK_TRANSPAT: pProp->trans_pat = nValue; break;
1634 case PROP_MASK_FILL: pProp->fill = nValue; break;
1635 case PROP_MASK_PEN: pProp->pen = nValue; break;
1636 case PROP_MASK_DASH: pProp->dash = nValue; break;
1637 case PROP_MASK_ARROW_STYLE: pProp->arrow_style = nValue; break;
1638 case PROP_MASK_CURVED: pProp->curved = nValue; break;
1639 case PROP_MASK_RCB_RADIUS: pProp->rcb_radius = nValue; break;
1640 case PROP_MASK_TEXT_JUST: pProp->text_just = nValue; break;
1641 case PROP_MASK_TEXT_SZ_UNIT: pProp->text_sz_unit = nValue; break;
1642 case PROP_MASK_VSPACE: pProp->v_space = nValue; break;
1643 case PROP_MASK_UNDERLINE_ON: pProp->underline_on = nValue; break;
1644 case PROP_MASK_OVERLINE_ON: pProp->overline_on = nValue; break;
1645 }
1646 }
1647 }
1648
SetFontPropertyMask(nDoubleByte,nFont,nStyle,plMask,plSkip,pProp)1649 void SetFontPropertyMask(nDoubleByte, nFont, nStyle, plMask, plSkip, pProp)
1650 int nDoubleByte, nFont, nStyle;
1651 long *plMask, *plSkip;
1652 struct PropertiesRec *pProp;
1653 {
1654 if (((*plSkip) & PROP_MASK_TEXT_FONT) == PROP_MASK_TEXT_FONT) {
1655 /*
1656 * this property is inconsistent, continue skipping it
1657 */
1658 } else if (((*plMask) & PROP_MASK_TEXT_FONT) == PROP_MASK_TEXT_FONT) {
1659 /*
1660 * this property was set before, if it's not the same, skip/invalidate it
1661 */
1662 TestFontProp(nDoubleByte, nFont, nStyle, pProp->double_byte,
1663 pProp->text_font, pProp->text_style, PROP_MASK_TEXT_FONT, plSkip);
1664 } else {
1665 /* this property is never set, go set it */
1666 (*plMask) |= PROP_MASK_TEXT_FONT;
1667 pProp->double_byte = nDoubleByte;
1668 pProp->text_font = nFont;
1669 pProp->text_style = nStyle;
1670 }
1671 }
1672
SetCTMPropertyMask(ctm,plMask,plSkip,pProp)1673 void SetCTMPropertyMask(ctm, plMask, plSkip, pProp)
1674 struct XfrmMtrxRec *ctm;
1675 long *plMask, *plSkip;
1676 struct PropertiesRec *pProp;
1677 {
1678 if (((*plSkip) & PROP_MASK_CTM) == PROP_MASK_CTM) {
1679 /*
1680 * this property is inconsistent, continue skipping it
1681 */
1682 } else if (((*plMask) & PROP_MASK_CTM) == PROP_MASK_CTM) {
1683 /*
1684 * this property was set before, if it's not the same, skip/invalidate it
1685 */
1686 TestCTMProp(ctm, pProp->transformed, &pProp->ctm, PROP_MASK_CTM, plSkip);
1687 } else {
1688 /* this property is never set, go set it */
1689 (*plMask) |= PROP_MASK_CTM;
1690 if (ctm == NULL) {
1691 pProp->transformed = FALSE;
1692 } else {
1693 pProp->transformed = TRUE;
1694 memcpy(&pProp->ctm, ctm, sizeof(struct XfrmMtrxRec));
1695 }
1696 }
1697 }
1698
SetTextPropMask(ObjPtr,plMask,plSkip,pProp)1699 void SetTextPropMask(ObjPtr, plMask, plSkip, pProp)
1700 struct ObjRec *ObjPtr;
1701 long *plMask, *plSkip;
1702 struct PropertiesRec *pProp;
1703 {
1704 struct TextRec *text_ptr=ObjPtr->detail.t;
1705 int sz_unit=INVALID, double_byte=INVALID, font=INVALID, style=INVALID;
1706 int underline_on=FALSE, overline_on=FALSE;
1707
1708 SetCTMPropertyMask(ObjPtr->ctm, plMask, plSkip, pProp);
1709
1710 SetIntPropertyMask(PROP_MASK_COLOR, ObjPtr->color,
1711 colorMenuItems[ObjPtr->color], plMask, plSkip, pProp);
1712
1713 SetIntPropertyMask(PROP_MASK_TRANSPAT, ObjPtr->trans_pat, NULL,
1714 plMask, plSkip, pProp);
1715 SetIntPropertyMask(PROP_MASK_FILL, text_ptr->fill, NULL,
1716 plMask, plSkip, pProp);
1717 SetIntPropertyMask(PROP_MASK_PEN, text_ptr->pen, NULL,
1718 plMask, plSkip, pProp);
1719 SetIntPropertyMask(PROP_MASK_TEXT_JUST, text_ptr->minilines.just, NULL,
1720 plMask, plSkip, pProp);
1721 SetIntPropertyMask(PROP_MASK_VSPACE, text_ptr->minilines.v_space, NULL,
1722 plMask, plSkip, pProp);
1723
1724 if (SingleFontText(text_ptr, &sz_unit, &double_byte, &font, &style,
1725 &underline_on, &overline_on)) {
1726 SetIntPropertyMask(PROP_MASK_TEXT_SZ_UNIT, sz_unit, NULL,
1727 plMask, plSkip, pProp);
1728 SetIntPropertyMask(PROP_MASK_UNDERLINE_ON, underline_on, NULL,
1729 plMask, plSkip, pProp);
1730 SetIntPropertyMask(PROP_MASK_OVERLINE_ON, overline_on, NULL,
1731 plMask, plSkip, pProp);
1732 SetFontPropertyMask(double_byte, font, style, plMask, plSkip, pProp);
1733 }
1734 }
1735
1736 static
SetPropMask(ObjPtr,plMask,plSkip,pProp)1737 void SetPropMask(ObjPtr, plMask, plSkip, pProp)
1738 struct ObjRec *ObjPtr;
1739 long *plMask, *plSkip;
1740 struct PropertiesRec *pProp;
1741 {
1742 if (curChoice == DRAWTEXT) {
1743 if (textCursorShown && textHighlight) {
1744 SetIntPropertyMask(PROP_MASK_TRANSPAT, transPat, NULL,
1745 plMask, plSkip, pProp);
1746 SetIntPropertyMask(PROP_MASK_FILL, objFill, NULL,
1747 plMask, plSkip, pProp);
1748 SetIntPropertyMask(PROP_MASK_PEN, penPat, NULL,
1749 plMask, plSkip, pProp);
1750
1751 SetIntPropertyMask(PROP_MASK_TEXT_JUST, textJust, NULL,
1752 plMask, plSkip, pProp);
1753 SetIntPropertyMask(PROP_MASK_VSPACE, textVSpace, NULL,
1754 plMask, plSkip, pProp);
1755
1756 if (HighlightedTextHasSameProperty(PROP_MASK_COLOR,
1757 curStrBlock->seg->color, TRUE)) {
1758 SetIntPropertyMask(PROP_MASK_COLOR, colorIndex,
1759 colorMenuItems[colorIndex], plMask, plSkip, pProp);
1760 }
1761 if (HighlightedTextHasSameProperty(PROP_MASK_TEXT_SZ_UNIT,
1762 curStrBlock->seg->sz_unit, TRUE)) {
1763 SetIntPropertyMask(PROP_MASK_TEXT_SZ_UNIT, GetCurSzUnit(), NULL,
1764 plMask, plSkip, pProp);
1765 }
1766 if (HighlightedTextHasSameProperty(PROP_MASK_UNDERLINE_ON,
1767 curStrBlock->seg->underline_on, TRUE)) {
1768 SetIntPropertyMask(PROP_MASK_UNDERLINE_ON, curUnderlineOn, NULL,
1769 plMask, plSkip, pProp);
1770 }
1771 if (HighlightedTextHasSameProperty(PROP_MASK_OVERLINE_ON,
1772 curStrBlock->seg->overline_on, TRUE)) {
1773 SetIntPropertyMask(PROP_MASK_OVERLINE_ON, curOverlineOn, NULL,
1774 plMask, plSkip, pProp);
1775 }
1776 if (HighlightedTextHasSameProperty(PROP_MASK_TEXT_FONT,
1777 curStrBlock->seg->font, TRUE) &&
1778 HighlightedTextHasSameProperty(PROP_MASK_TEXT_STYLE,
1779 curStrBlock->seg->style, TRUE)) {
1780 SetFontPropertyMask(canvasFontDoubleByte, curFont, curStyle, plMask,
1781 plSkip, pProp);
1782 }
1783 } else {
1784 SetIntPropertyMask(PROP_MASK_TRANSPAT, transPat, NULL,
1785 plMask, plSkip, pProp);
1786 SetIntPropertyMask(PROP_MASK_FILL, objFill, NULL,
1787 plMask, plSkip, pProp);
1788 SetIntPropertyMask(PROP_MASK_PEN, penPat, NULL,
1789 plMask, plSkip, pProp);
1790
1791 SetIntPropertyMask(PROP_MASK_TEXT_JUST, textJust, NULL,
1792 plMask, plSkip, pProp);
1793 SetIntPropertyMask(PROP_MASK_VSPACE, textVSpace, NULL,
1794 plMask, plSkip, pProp);
1795
1796 SetIntPropertyMask(PROP_MASK_COLOR, colorIndex,
1797 colorMenuItems[colorIndex], plMask, plSkip, pProp);
1798 SetIntPropertyMask(PROP_MASK_TEXT_SZ_UNIT, GetCurSzUnit(), NULL,
1799 plMask, plSkip, pProp);
1800 SetIntPropertyMask(PROP_MASK_UNDERLINE_ON, curUnderlineOn, NULL,
1801 plMask, plSkip, pProp);
1802 SetIntPropertyMask(PROP_MASK_OVERLINE_ON, curOverlineOn, NULL,
1803 plMask, plSkip, pProp);
1804 SetFontPropertyMask(canvasFontDoubleByte, curFont, curStyle, plMask,
1805 plSkip, pProp);
1806 }
1807 } else if (ObjPtr == NULL) {
1808 double radian=((double)(textRotation))*M_PI/180.0/64.0;
1809 double sin_val=sin(radian);
1810 double cos_val=cos(radian);
1811 struct XfrmMtrxRec ctm;
1812
1813 ctm.m[CTM_SX] = ctm.m[CTM_SY] = ((double)1000)*cos_val;
1814 ctm.m[CTM_SIN] = ((double)1000)*sin_val;
1815 ctm.m[CTM_MSIN] = (-ctm.m[CTM_SIN]);
1816 ctm.t[CTM_TX] = ctm.t[CTM_TY] = 0;
1817 SetCTMPropertyMask(&ctm, plMask, plSkip, pProp);
1818
1819 SetIntPropertyMask(PROP_MASK_COLOR, colorIndex,
1820 colorMenuItems[colorIndex], plMask, plSkip, pProp);
1821 SetIntPropertyMask(PROP_MASK_WIDTH, curWidthOfLine[lineWidth],
1822 curWidthOfLineSpec[lineWidth],
1823 plMask, plSkip, pProp);
1824 SetIntPropertyMask(PROP_MASK_AW, curArrowHeadW[lineWidth],
1825 curArrowHeadWSpec[lineWidth],
1826 plMask, plSkip, pProp);
1827 SetIntPropertyMask(PROP_MASK_AH, curArrowHeadH[lineWidth],
1828 curArrowHeadHSpec[lineWidth],
1829 plMask, plSkip, pProp);
1830
1831 SetIntPropertyMask(PROP_MASK_TRANSPAT, transPat, NULL,
1832 plMask, plSkip, pProp);
1833 SetIntPropertyMask(PROP_MASK_FILL, objFill, NULL,
1834 plMask, plSkip, pProp);
1835 SetIntPropertyMask(PROP_MASK_PEN, penPat, NULL,
1836 plMask, plSkip, pProp);
1837 SetIntPropertyMask(PROP_MASK_DASH, curDash, NULL,
1838 plMask, plSkip, pProp);
1839 SetIntPropertyMask(PROP_MASK_CURVED, curSpline, NULL,
1840 plMask, plSkip, pProp);
1841 SetIntPropertyMask(PROP_MASK_ARROW_STYLE, lineStyle, NULL,
1842 plMask, plSkip, pProp);
1843 SetIntPropertyMask(PROP_MASK_RCB_RADIUS, rcbRadius, NULL,
1844 plMask, plSkip, pProp);
1845
1846 SetIntPropertyMask(PROP_MASK_TEXT_JUST, textJust, NULL,
1847 plMask, plSkip, pProp);
1848 SetIntPropertyMask(PROP_MASK_TEXT_SZ_UNIT, GetCurSzUnit(), NULL,
1849 plMask, plSkip, pProp);
1850 SetIntPropertyMask(PROP_MASK_VSPACE, textVSpace, NULL,
1851 plMask, plSkip, pProp);
1852 SetIntPropertyMask(PROP_MASK_UNDERLINE_ON, curUnderlineOn, NULL,
1853 plMask, plSkip, pProp);
1854 SetIntPropertyMask(PROP_MASK_OVERLINE_ON, curOverlineOn, NULL,
1855 plMask, plSkip, pProp);
1856
1857 SetFontPropertyMask(canvasFontDoubleByte, curFont, curStyle, plMask,
1858 plSkip, pProp);
1859 } else {
1860 struct ObjRec *obj_ptr=NULL;
1861
1862 switch (ObjPtr->type) {
1863 case OBJ_POLY: SetPolyPropMask(ObjPtr, plMask, plSkip, pProp); break;
1864 case OBJ_BOX: SetBoxPropMask(ObjPtr, plMask, plSkip, pProp); break;
1865 case OBJ_OVAL: SetOvalPropMask(ObjPtr, plMask, plSkip, pProp); break;
1866 case OBJ_TEXT: SetTextPropMask(ObjPtr, plMask, plSkip, pProp); break;
1867 case OBJ_POLYGON:
1868 SetPolygonPropMask(ObjPtr, plMask, plSkip, pProp);
1869 break;
1870 case OBJ_ARC: SetArcPropMask(ObjPtr, plMask, plSkip, pProp); break;
1871 case OBJ_RCBOX: SetRCBoxPropMask(ObjPtr, plMask, plSkip, pProp); break;
1872 case OBJ_XBM: SetXBmPropMask(ObjPtr, plMask, plSkip, pProp); break;
1873 case OBJ_XPM: SetXPmPropMask(ObjPtr, plMask, plSkip, pProp); break;
1874
1875 case OBJ_GROUP:
1876 case OBJ_ICON:
1877 case OBJ_SYM:
1878 case OBJ_PIN:
1879 for (obj_ptr=ObjPtr->detail.r->first; obj_ptr != NULL;
1880 obj_ptr=obj_ptr->next) {
1881 SetPropMask(obj_ptr, plMask, plSkip, pProp);
1882 }
1883 break;
1884 }
1885 }
1886 }
1887
1888 static
GetAngleFromCTM(ctm)1889 int GetAngleFromCTM(ctm)
1890 struct XfrmMtrxRec *ctm;
1891 /* returned angle is degree*64 */
1892 {
1893 double sin_val=(double)(ctm->m[CTM_SIN]/((double)1000));
1894 double cos_val=(double)(ctm->m[CTM_SX]/((double)1000));
1895 double radian=(double)0;
1896 int angle=0;
1897
1898 if (fabs(sin_val) < EQ_TOL) {
1899 if (cos_val > 0) {
1900 radian = (double)0;
1901 } else {
1902 radian = (double)M_PI;
1903 }
1904 } else if (fabs(cos_val) < EQ_TOL) {
1905 if (sin_val> 0) {
1906 radian = (double)(M_PI/2.0);
1907 } else {
1908 radian = (double)(M_PI*3.0/2.0);
1909 }
1910 } else {
1911 radian = (double)atan(sin_val/cos_val);
1912 if (radian >= 0) {
1913 if (sin_val < 0) {
1914 radian += (double)M_PI;
1915 }
1916 } else {
1917 if (cos_val > 0) {
1918 radian += (double)(M_PI*2.0);
1919 } else {
1920 radian += (double)M_PI;
1921 }
1922 }
1923 }
1924 angle = (int)(radian*((double)180)*((double)64)/M_PI);
1925 return angle;
1926 }
1927
1928 static
DoPasteAProperty(lWhich,pProp)1929 void DoPasteAProperty(lWhich, pProp)
1930 long lWhich;
1931 struct PropertiesRec *pProp;
1932 {
1933 char szBuf[MAXSTRING];
1934 int index=0, new_alloc=FALSE;
1935
1936 switch (lWhich) {
1937 case PROP_MASK_COLOR:
1938 index = QuickFindColorIndex(NULL, pProp->color_str, &new_alloc, FALSE);
1939 if (index == INVALID) {
1940 sprintf(gszMsgBox, TgLoadString(STID_FAIL_ALLOC_NAMED_COLOR),
1941 pProp->color_str);
1942 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1943 return;
1944 } else {
1945 ChangeAllSelColor(index, TRUE);
1946 }
1947 break;
1948 case PROP_MASK_WIDTH:
1949 ChangeAllSelRealLineWidth(CHANGE_WIDTH, pProp->width, (-1), (-1),
1950 pProp->width_spec, NULL, NULL, TRUE);
1951 break;
1952 case PROP_MASK_AW:
1953 ChangeAllSelRealLineWidth(CHANGE_AW, (-1), pProp->aw, (-1),
1954 NULL, pProp->aw_spec, NULL, TRUE);
1955 break;
1956 case PROP_MASK_AH:
1957 ChangeAllSelRealLineWidth(CHANGE_AH, (-1), (-1), pProp->ah,
1958 NULL, NULL, pProp->ah_spec, TRUE);
1959 break;
1960
1961 case PROP_MASK_TRANSPAT: ChangeAllSelTransPat(pProp->trans_pat, TRUE); break;
1962 case PROP_MASK_FILL: ChangeAllSelFill(pProp->fill, TRUE); break;
1963 case PROP_MASK_PEN: ChangeAllSelPen(pProp->pen, TRUE); break;
1964 case PROP_MASK_DASH: ChangeAllSelLineDash(pProp->dash, TRUE); break;
1965 case PROP_MASK_ARROW_STYLE:
1966 ChangeAllSelLineStyle(pProp->arrow_style, TRUE);
1967 break;
1968 case PROP_MASK_CURVED: ChangeAllSelLineType(pProp->curved, TRUE); break;
1969 case PROP_MASK_RCB_RADIUS: ChangeAllSelRCBRadius(pProp->rcb_radius); break;
1970 case PROP_MASK_TEXT_JUST: ChangeFontJust(pProp->text_just); break;
1971 case PROP_MASK_TEXT_SZ_UNIT:
1972 sprintf(szBuf, "%1d", SzUnitToFontSize(pProp->text_sz_unit));
1973 SetSelFontSize(szBuf);
1974 break;
1975 case PROP_MASK_VSPACE: ChangeVSpace(pProp->v_space); break;
1976 case PROP_MASK_UNDERLINE_ON: ChangeFontUnderline(pProp->underline_on); break;
1977 case PROP_MASK_OVERLINE_ON: ChangeFontOverline(pProp->overline_on); break;
1978
1979 case PROP_MASK_TEXT_FONT:
1980 ChangeFont(pProp->text_font, TRUE);
1981 ChangeFontStyle(pProp->text_style);
1982 break;
1983
1984 case PROP_MASK_CTM:
1985 if (topSel == NULL) {
1986 if (pProp->transformed) {
1987 int angle=GetAngleFromCTM(&pProp->ctm);
1988
1989 FormatAngle(angle, szBuf);
1990 } else {
1991 strcpy(szBuf, "0");
1992 }
1993 SetTextRotation(szBuf);
1994 } else {
1995 SetSelCTM(pProp->transformed, &pProp->ctm);
1996 }
1997 break;
1998 }
1999 }
2000
2001 static
DoGetAProperty(lWhich,pProp)2002 void DoGetAProperty(lWhich, pProp)
2003 long lWhich;
2004 struct PropertiesRec *pProp;
2005 {
2006 char szBuf[MAXSTRING];
2007 int index=0, new_alloc=FALSE;
2008
2009 switch (lWhich) {
2010 case PROP_MASK_COLOR:
2011 index = QuickFindColorIndex(NULL, pProp->color_str, &new_alloc, FALSE);
2012 if (index == INVALID) {
2013 sprintf(gszMsgBox, TgLoadString(STID_FAIL_ALLOC_NAMED_COLOR),
2014 pProp->color_str);
2015 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2016 return;
2017 } else {
2018 ChangeAllSelColor(index, TRUE);
2019 }
2020 break;
2021 case PROP_MASK_WIDTH_INDEX:
2022 ChangeAllSelLineWidth(pProp->width_index, TRUE);
2023 break;
2024 case PROP_MASK_WIDTH:
2025 ChangeAllSelRealLineWidth(CHANGE_WIDTH, pProp->width, (-1), (-1),
2026 pProp->width_spec, NULL, NULL, TRUE);
2027 break;
2028 case PROP_MASK_AW:
2029 ChangeAllSelRealLineWidth(CHANGE_AW, (-1), pProp->aw, (-1),
2030 NULL, pProp->aw_spec, NULL, TRUE);
2031 break;
2032 case PROP_MASK_AH:
2033 ChangeAllSelRealLineWidth(CHANGE_AH, (-1), (-1), pProp->ah,
2034 NULL, NULL, pProp->ah_spec, TRUE);
2035 break;
2036
2037 case PROP_MASK_TRANSPAT: ChangeAllSelTransPat(pProp->trans_pat, TRUE); break;
2038 case PROP_MASK_FILL: ChangeAllSelFill(pProp->fill, TRUE); break;
2039 case PROP_MASK_PEN: ChangeAllSelPen(pProp->pen, TRUE); break;
2040 case PROP_MASK_DASH: ChangeAllSelLineDash(pProp->dash, TRUE); break;
2041 case PROP_MASK_ARROW_STYLE:
2042 ChangeAllSelLineStyle(pProp->arrow_style, TRUE);
2043 break;
2044 case PROP_MASK_CURVED: ChangeAllSelLineType(pProp->curved, TRUE); break;
2045 case PROP_MASK_RCB_RADIUS: ChangeAllSelRCBRadius(pProp->rcb_radius); break;
2046 case PROP_MASK_TEXT_JUST: ChangeFontJust(pProp->text_just); break;
2047 case PROP_MASK_TEXT_SZ_UNIT:
2048 sprintf(szBuf, "%1d", SzUnitToFontSize(pProp->text_sz_unit));
2049 SetSelFontSize(szBuf);
2050 break;
2051 case PROP_MASK_VSPACE: ChangeVSpace(pProp->v_space); break;
2052 case PROP_MASK_UNDERLINE_ON: ChangeFontUnderline(pProp->underline_on); break;
2053 case PROP_MASK_OVERLINE_ON: ChangeFontOverline(pProp->overline_on); break;
2054
2055 case PROP_MASK_TEXT_FONT:
2056 ChangeFont(pProp->text_font, TRUE);
2057 ChangeFontStyle(pProp->text_style);
2058 break;
2059
2060 case PROP_MASK_CTM:
2061 if (topSel == NULL) {
2062 if (pProp->transformed) {
2063 int angle=GetAngleFromCTM(&pProp->ctm);
2064
2065 FormatAngle(angle, szBuf);
2066 } else {
2067 strcpy(szBuf, "0");
2068 }
2069 SetTextRotation(szBuf);
2070 } else {
2071 SetSelCTM(pProp->transformed, &pProp->ctm);
2072 }
2073 break;
2074 }
2075 }
2076
2077 static char gszPropIniFile[MAXPATHLENGTH];
2078
2079 static char gszCopyPasteSec[MAXSTRING];
2080 static char gszCopyPasteBackupSec[MAXSTRING];
2081 static char gszPropSetSec[MAXSTRING];
2082 static char gszPropProfilePrefix[MAXSTRING];
2083
2084 struct PropInfoRec {
2085 long bit;
2086 int checked;
2087 char *key;
2088 char *desc;
2089 };
2090
2091 static struct PropInfoRec gstPropInfo[] = {
2092 { PROP_MASK_AH, FALSE, NULL, NULL },
2093 { PROP_MASK_AW, FALSE, NULL, NULL },
2094 { PROP_MASK_ARROW_STYLE, FALSE, NULL, NULL },
2095 { PROP_MASK_COLOR, FALSE, NULL, NULL },
2096 { PROP_MASK_DASH, FALSE, NULL, NULL },
2097 { PROP_MASK_WIDTH, FALSE, NULL, NULL },
2098 { PROP_MASK_TRANSPAT, FALSE, NULL, NULL },
2099 { PROP_MASK_FILL, FALSE, NULL, NULL },
2100 { PROP_MASK_PEN, FALSE, NULL, NULL },
2101 { PROP_MASK_RCB_RADIUS, FALSE, NULL, NULL },
2102 { PROP_MASK_CURVED, FALSE, NULL, NULL },
2103 { PROP_MASK_TEXT_FONT, FALSE, NULL, NULL },
2104 { PROP_MASK_TEXT_STYLE, FALSE, NULL, NULL },
2105 { PROP_MASK_TEXT_JUST, FALSE, NULL, NULL },
2106 { PROP_MASK_TEXT_SZ_UNIT, FALSE, NULL, NULL },
2107 { PROP_MASK_VSPACE, FALSE, NULL, NULL },
2108 { PROP_MASK_UNDERLINE_ON, FALSE, NULL, NULL },
2109 { PROP_MASK_OVERLINE_ON, FALSE, NULL, NULL },
2110 { PROP_MASK_CTM, FALSE, NULL, NULL },
2111 { PROP_MASK_WIDTH_INDEX, FALSE, NULL, NULL },
2112 { 0L, FALSE, NULL, NULL }
2113 };
2114
2115 static struct PropInfoRec gstCompatPropInfo[] = {
2116 /*
2117 * do not translate -- program constants
2118 *
2119 * These are used for compatibility reasons. In an earlier version,
2120 * the keys in "cutpaste.ini" are these strings. In the current
2121 * version, hex numbers are used. gstCompatPropInfo are only used
2122 * by UpdateSavedPropKeys() to update the old keys to new ones.
2123 */
2124 { PROP_MASK_AH, FALSE, NULL, "arrow height" },
2125 { PROP_MASK_AW, FALSE, NULL, "arrow width" },
2126 { PROP_MASK_ARROW_STYLE, FALSE, NULL, "arrow style" },
2127 { PROP_MASK_COLOR, FALSE, NULL, "color" },
2128 { PROP_MASK_DASH, FALSE, NULL, "dash" },
2129 { PROP_MASK_WIDTH, FALSE, NULL, "line width" },
2130 { PROP_MASK_TRANSPAT, FALSE, NULL, "pattern transparency" },
2131 { PROP_MASK_FILL, FALSE, NULL, "fill" },
2132 { PROP_MASK_PEN, FALSE, NULL, "pen" },
2133 { PROP_MASK_RCB_RADIUS, FALSE, NULL, "rcbox radius" },
2134 { PROP_MASK_CURVED, FALSE, NULL, "spline" },
2135 { PROP_MASK_TEXT_FONT, FALSE, NULL, "text font" },
2136 { PROP_MASK_TEXT_STYLE, FALSE, NULL, "text style (no use, part of text font)" },
2137 { PROP_MASK_TEXT_JUST, FALSE, NULL, "text justification" },
2138 { PROP_MASK_TEXT_SZ_UNIT, FALSE, NULL, "text size" },
2139 { PROP_MASK_VSPACE, FALSE, NULL, "text vertical spacing" },
2140 { PROP_MASK_UNDERLINE_ON, FALSE, NULL, "text underline" },
2141 { PROP_MASK_CTM, FALSE, NULL, "transformation matrix" },
2142 { 0L, FALSE, NULL, NULL }
2143 };
2144
2145 static
WriteIntProp(pszSec,pszKey,nValue)2146 void WriteIntProp(pszSec, pszKey, nValue)
2147 char *pszSec, *pszKey;
2148 int nValue;
2149 {
2150 sprintf(gszMsgBox, "%1d", nValue);
2151 tgWriteProfileString(pszSec, pszKey, gszMsgBox, gszPropIniFile);
2152 }
2153
2154 static
WriteStringProp(pszSec,pszKey,nValue,pszValue)2155 void WriteStringProp(pszSec, pszKey, nValue, pszValue)
2156 char *pszSec, *pszKey;
2157 int nValue;
2158 char *pszValue;
2159 {
2160 sprintf(gszMsgBox, "%1d,%s", nValue, (pszValue==NULL ? "" : pszValue));
2161 tgWriteProfileString(pszSec, pszKey, gszMsgBox, gszPropIniFile);
2162 }
2163
2164 static
WriteFontProp(pszSec,pszKey,nFont,nStyle)2165 void WriteFontProp(pszSec, pszKey, nFont, nStyle)
2166 char *pszSec, *pszKey;
2167 int nFont, nStyle;
2168 {
2169 char font_str[MAXSTRING];
2170
2171 *font_str = '\0';
2172 GetPSFontStr(nFont, nStyle, font_str);
2173 /* font_str starts with the '/' character */
2174 sprintf(gszMsgBox, "%1d,%s", nStyle, &font_str[1]);
2175 tgWriteProfileString(pszSec, pszKey, gszMsgBox, gszPropIniFile);
2176 }
2177
2178 static
WriteCTMProp(pszSec,pszKey,nTransformed,ctm)2179 void WriteCTMProp(pszSec, pszKey, nTransformed, ctm)
2180 char *pszSec, *pszKey;
2181 int nTransformed;
2182 struct XfrmMtrxRec *ctm;
2183 {
2184 if (nTransformed) {
2185 sprintf(gszMsgBox, "%1d,%g,%g,%g,%g,%1d,%1d", nTransformed,
2186 ctm->m[CTM_SX], ctm->m[CTM_SIN], ctm->m[CTM_MSIN], ctm->m[CTM_SY],
2187 ctm->t[CTM_TX], ctm->t[CTM_TY]);
2188 } else {
2189 sprintf(gszMsgBox, "%1d,%g,%g,%g,%g,%1d,%1d", nTransformed,
2190 (double)1000, (double)0, (double)0, (double)1000, 0, 0);
2191 }
2192 tgWriteProfileString(pszSec, pszKey, gszMsgBox, gszPropIniFile);
2193 }
2194
2195 static
ParseIntProp(pszBuf,pnValue)2196 int ParseIntProp(pszBuf, pnValue)
2197 char *pszBuf;
2198 int *pnValue;
2199 {
2200 return (sscanf(pszBuf, "%d", pnValue) == 1);
2201 }
2202
2203 static
ParseStringProp(pszBuf,pnValue,pszValue)2204 int ParseStringProp(pszBuf, pnValue, pszValue)
2205 char *pszBuf;
2206 int *pnValue;
2207 char *pszValue;
2208 {
2209 char *psz1=strtok(pszBuf, ","), *psz2=NULL;
2210
2211 if (psz1 == NULL) return FALSE;
2212 psz2 = strtok(NULL, ",");
2213 if (psz2 == NULL) return FALSE;
2214
2215 if (sscanf(psz1, "%d", pnValue) != 1) return FALSE;
2216 strcpy(pszValue, psz2);
2217
2218 return TRUE;
2219 }
2220
2221 static
ParseFontSzUnitProp(pszBuf,pnSzUnit)2222 int ParseFontSzUnitProp(pszBuf, pnSzUnit)
2223 char *pszBuf;
2224 int *pnSzUnit;
2225 {
2226 int i, sz_unit=0;
2227
2228 if (sscanf(pszBuf, "%d", &sz_unit) != 1) return FALSE;
2229 for (i=0; i < numFontSizes; i++) {
2230 if (sz_unit == fontSzUnits[i]) {
2231 *pnSzUnit = sz_unit;
2232 return TRUE;
2233 }
2234 }
2235 if (topSel == NULL) {
2236 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_FIND_SIZE_USE_ALT),
2237 SzUnitToFontSize(sz_unit), defaultFontSize);
2238 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2239 *pnSzUnit = FontSizeToSzUnit(defaultFontSize);
2240 } else {
2241 *pnSzUnit = sz_unit;
2242 }
2243 return TRUE;
2244 }
2245
2246 static
ParseFontProp(pszBuf,pnDoubleByte,pnFont,pnStyle)2247 int ParseFontProp(pszBuf, pnDoubleByte, pnFont, pnStyle)
2248 char *pszBuf;
2249 int *pnDoubleByte, *pnFont, *pnStyle;
2250 {
2251 char font_str[MAXSTRING], *psz=NULL;
2252
2253 *font_str = '\0';
2254 psz = strchr(pszBuf, ',');
2255 if (psz == NULL) return FALSE;
2256
2257 *psz = '\0';
2258 if (sscanf(pszBuf, "%d", pnStyle) != 1) {
2259 *psz = ',';
2260 return FALSE;
2261 }
2262 *psz++ = ',';
2263 strcpy(font_str, psz);
2264 *pnFont = GetFontIndex(font_str, *pnStyle, TRUE);
2265 *pnDoubleByte = FALSE;
2266 if (*pnFont == INVALID) {
2267 sprintf(gszMsgBox, TgLoadString(STID_CANNOT_FIND_FONT_USE_ALT), font_str,
2268 "Times");
2269 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2270 *pnDoubleByte = FALSE;
2271 *pnFont = FONT_TIM;
2272 }
2273 return TRUE;
2274 }
2275
2276 static
ParseCTMProp(pszBuf,pnTransformed,ctm)2277 int ParseCTMProp(pszBuf, pnTransformed, ctm)
2278 char *pszBuf;
2279 int *pnTransformed;
2280 struct XfrmMtrxRec *ctm;
2281 {
2282 struct PropInfoRec *ppir=NULL;
2283 char *psz=strchr(pszBuf, ',');
2284
2285 if (psz == NULL) return FALSE;
2286 *psz = '\0';
2287 if (sscanf(pszBuf, "%d", pnTransformed) != 1) {
2288 *psz = ',';
2289 return FALSE;
2290 }
2291 *psz++ = ',';
2292 if (sscanf(psz, "%lg , %lg , %lg, %lg , %d , %d",
2293 &ctm->m[CTM_SX], &ctm->m[CTM_SIN], &ctm->m[CTM_MSIN], &ctm->m[CTM_SY],
2294 &ctm->t[CTM_TX], &ctm->t[CTM_TY]) != 6) {
2295 return FALSE;
2296 }
2297 if (topSel != NULL) {
2298 struct SelRec *sel_ptr=NULL;
2299
2300 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
2301 switch (sel_ptr->obj->type) {
2302 case OBJ_GROUP:
2303 case OBJ_ICON:
2304 case OBJ_SYM:
2305 case OBJ_PIN:
2306 for (ppir=gstPropInfo; ppir->bit != 0L; ppir++) {
2307 if (ppir->bit == PROP_MASK_CTM) {
2308 sprintf(gszMsgBox,
2309 TgLoadString(STID_CANNOT_PASTE_COMPOUND_OBJ),
2310 ppir->desc, ppir->desc);
2311 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2312 break;
2313 }
2314 }
2315 return FALSE;
2316 }
2317 }
2318 } else if (topSel == NULL && (*pnTransformed)) {
2319 if ((fabs(ctm->m[CTM_SX]-ctm->m[CTM_SY]) < EQ_TOL) &&
2320 (fabs(ctm->m[CTM_SIN]+ctm->m[CTM_MSIN]) < EQ_TOL)) {
2321 return TRUE;
2322 }
2323 for (ppir=gstPropInfo; ppir->bit != 0L; ppir++) {
2324 if (ppir->bit == PROP_MASK_CTM) {
2325 sprintf(gszMsgBox, TgLoadString(STID_CUT_BUF_HAS_NON_ROT_COMP),
2326 ppir->desc);
2327 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2328 break;
2329 }
2330 }
2331 *pnTransformed = FALSE;
2332 }
2333 return TRUE;
2334 }
2335
2336 static
WritePropToIni(lWhich,pszSec,pszKey,pProp)2337 void WritePropToIni(lWhich, pszSec, pszKey, pProp)
2338 long lWhich;
2339 char *pszSec, *pszKey;
2340 struct PropertiesRec *pProp;
2341 {
2342 switch (lWhich) {
2343 case PROP_MASK_AH:
2344 WriteStringProp(pszSec, pszKey, pProp->ah, pProp->ah_spec);
2345 break;
2346 case PROP_MASK_AW:
2347 WriteStringProp(pszSec, pszKey, pProp->aw, pProp->aw_spec);
2348 break;
2349 case PROP_MASK_ARROW_STYLE:
2350 WriteIntProp(pszSec, pszKey, pProp->arrow_style);
2351 break;
2352 case PROP_MASK_COLOR:
2353 WriteStringProp(pszSec, pszKey, pProp->color, pProp->color_str);
2354 break;
2355
2356 case PROP_MASK_DASH: WriteIntProp(pszSec, pszKey, pProp->dash); break;
2357 case PROP_MASK_WIDTH:
2358 WriteStringProp(pszSec, pszKey, pProp->width, pProp->width_spec);
2359 break;
2360 case PROP_MASK_TRANSPAT:
2361 WriteIntProp(pszSec, pszKey, pProp->trans_pat);
2362 break;
2363 case PROP_MASK_FILL: WriteIntProp(pszSec, pszKey, pProp->fill); break;
2364 case PROP_MASK_PEN: WriteIntProp(pszSec, pszKey, pProp->pen); break;
2365 case PROP_MASK_RCB_RADIUS:
2366 WriteIntProp(pszSec, pszKey, pProp->rcb_radius);
2367 break;
2368 case PROP_MASK_CURVED: WriteIntProp(pszSec, pszKey, pProp->curved); break;
2369 case PROP_MASK_TEXT_FONT:
2370 WriteFontProp(pszSec, pszKey, pProp->text_font, pProp->text_style);
2371 break;
2372 case PROP_MASK_TEXT_JUST:
2373 WriteIntProp(pszSec, pszKey, pProp->text_just);
2374 break;
2375 case PROP_MASK_TEXT_SZ_UNIT:
2376 WriteIntProp(pszSec, pszKey, pProp->text_sz_unit);
2377 break;
2378 case PROP_MASK_UNDERLINE_ON:
2379 WriteIntProp(pszSec, pszKey, pProp->underline_on);
2380 break;
2381 case PROP_MASK_OVERLINE_ON:
2382 WriteIntProp(pszSec, pszKey, pProp->overline_on);
2383 break;
2384 case PROP_MASK_VSPACE: WriteIntProp(pszSec, pszKey, pProp->v_space); break;
2385 case PROP_MASK_CTM:
2386 WriteCTMProp(pszSec, pszKey, pProp->transformed, &pProp->ctm);
2387 break;
2388 }
2389 }
2390
2391 static
ParseAProp(lWhich,pszBuf,pProp)2392 int ParseAProp(lWhich, pszBuf, pProp)
2393 long lWhich;
2394 char *pszBuf;
2395 struct PropertiesRec *pProp;
2396 {
2397 switch (lWhich) {
2398 case PROP_MASK_AH:
2399 return ParseStringProp(pszBuf, &pProp->ah, pProp->ah_spec);
2400 case PROP_MASK_AW:
2401 return ParseStringProp(pszBuf, &pProp->aw, pProp->aw_spec);
2402 case PROP_MASK_ARROW_STYLE: return ParseIntProp(pszBuf, &pProp->arrow_style);
2403 case PROP_MASK_COLOR:
2404 return ParseStringProp(pszBuf, &pProp->color, pProp->color_str);
2405 case PROP_MASK_DASH: return ParseIntProp(pszBuf, &pProp->dash);
2406 case PROP_MASK_WIDTH:
2407 return ParseStringProp(pszBuf, &pProp->width, pProp->width_spec);
2408 case PROP_MASK_TRANSPAT: return ParseIntProp(pszBuf, &pProp->trans_pat);
2409 case PROP_MASK_FILL: return ParseIntProp(pszBuf, &pProp->fill);
2410 case PROP_MASK_PEN: return ParseIntProp(pszBuf, &pProp->pen);
2411 case PROP_MASK_RCB_RADIUS: return ParseIntProp(pszBuf, &pProp->rcb_radius);
2412 case PROP_MASK_CURVED: return ParseIntProp(pszBuf, &pProp->curved);
2413 case PROP_MASK_TEXT_FONT:
2414 return ParseFontProp(pszBuf, &pProp->double_byte, &pProp->text_font,
2415 &pProp->text_style);
2416 case PROP_MASK_TEXT_JUST: return ParseIntProp(pszBuf, &pProp->text_just);
2417 case PROP_MASK_TEXT_SZ_UNIT:
2418 return ParseFontSzUnitProp(pszBuf, &pProp->text_sz_unit);
2419 case PROP_MASK_UNDERLINE_ON:
2420 return ParseIntProp(pszBuf, &pProp->underline_on);
2421 case PROP_MASK_OVERLINE_ON: return ParseIntProp(pszBuf, &pProp->overline_on);
2422 case PROP_MASK_VSPACE: return ParseIntProp(pszBuf, &pProp->v_space);
2423 case PROP_MASK_CTM:
2424 return ParseCTMProp(pszBuf, &pProp->transformed, &pProp->ctm);
2425 }
2426 return FALSE;
2427 }
2428
2429 static
ReadPropFromIni(pszSec,plMask,pCheckArray,pProp)2430 int ReadPropFromIni(pszSec, plMask, pCheckArray, pProp)
2431 /*
2432 * This routine sets *plMask according to what's in the ini file.
2433 * All associated fields in pProp are filled in.
2434 * This routine sets pCheckArray->num_cols and pCheckArray->num_rows;
2435 * pCheckArray->value is set to NULL.
2436 */
2437 char *pszSec;
2438 long *plMask;
2439 struct CheckArrayRec *pCheckArray;
2440 struct PropertiesRec *pProp;
2441 {
2442 struct PropInfoRec *ppir=NULL;
2443 char *pszKey=NULL;
2444 char *pszKeys=tgGetProfileString(pszSec, NULL, gszPropIniFile);
2445
2446 *plMask = 0L;
2447 for (ppir=gstPropInfo; ppir->bit != 0L; ppir++) ppir->checked = FALSE;
2448 pCheckArray->num_cols = 1;
2449
2450 if (pszKeys == NULL) {
2451 strcpy(gszMsgBox, TgLoadString(STID_NO_PROPERTY_TO_PASTE));
2452 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2453 return FALSE;
2454 }
2455 for (pszKey=pszKeys; *pszKey != '\0'; pszKey++) {
2456 for (ppir=gstPropInfo; ppir->bit != 0L; ppir++) {
2457 if (strcmp(pszKey, ppir->key) == 0) {
2458 break;
2459 }
2460 }
2461 if (ppir != NULL) {
2462 char *pszValue=tgGetProfileString(pszSec, pszKey, gszPropIniFile);
2463
2464 if (topSel == NULL && (ppir->bit == PROP_MASK_WIDTH ||
2465 ppir->bit == PROP_MASK_AW || ppir->bit == PROP_MASK_AH)) {
2466 } else {
2467 if (ParseAProp(ppir->bit, ((pszValue==NULL)?"":pszValue), pProp)) {
2468 ppir->checked = TRUE;
2469 pCheckArray->num_rows++;
2470 *plMask |= ppir->bit;
2471 }
2472 }
2473 if (pszValue != NULL) tgFreeProfileString(pszValue);
2474 } else {
2475 sprintf(gszMsgBox, TgLoadString(STID_INVALID_KEY_IN_SEC_OF_INIFILE),
2476 pszKey, pszSec, gszPropIniFile);
2477 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2478 }
2479 pszKey += strlen(pszKey);
2480 }
2481 tgFreeProfileString(pszKeys);
2482 return TRUE;
2483 }
2484
2485 #define COPY_BUTTON 101
2486 #define PASTE_BUTTON 102
2487 #define SAVE_BUTTON 103
2488 #define RESTORE_BUTTON 104
2489
CleanUpProperties()2490 void CleanUpProperties()
2491 {
2492 struct PropInfoRec *ppir=NULL;
2493
2494 for (ppir=gstPropInfo; ppir->bit != 0L; ppir++) {
2495 UtilFree(ppir->desc);
2496 UtilFree(ppir->key);
2497 ppir->desc = ppir->key = NULL;
2498 }
2499 }
2500
2501 static
UpdateSavedPropKeys()2502 void UpdateSavedPropKeys()
2503 {
2504 char *pszName=NULL;
2505 char *pszNames=tgGetProfileString(gszPropSetSec, NULL, gszPropIniFile);
2506 int already_updated=FALSE;
2507
2508 if (pszNames == NULL) return;
2509
2510 for (pszName=pszNames; !already_updated && *pszName != '\0'; pszName++) {
2511 char szPropSetSec[MAXSTRING], *pszKeys=NULL;
2512
2513 sprintf(szPropSetSec, "%s: %s", gszPropProfilePrefix, pszName);
2514
2515 pszKeys = tgGetProfileString(szPropSetSec, NULL, gszPropIniFile);
2516 if (pszKeys != NULL) {
2517 char *pszKey=NULL;
2518
2519 for (pszKey=pszKeys; *pszKey != '\0'; pszKey++) {
2520 if (pszKey[0] == '0' && pszKey[1] == 'x') {
2521 /* already updated */
2522 already_updated = TRUE;
2523 break;
2524 } else {
2525 char *pszValue=tgGetProfileString(szPropSetSec, pszKey,
2526 gszPropIniFile);
2527
2528 if (pszValue != NULL) {
2529 struct PropInfoRec *ppir_compat=NULL, *ppir=NULL;
2530
2531 for (ppir_compat=gstCompatPropInfo, ppir=gstPropInfo;
2532 ppir_compat->bit != 0L;
2533 ppir_compat++, ppir++) {
2534 if (strcmp(ppir_compat->desc, pszKey) == 0) {
2535 tgWriteProfileString(szPropSetSec, ppir->key, pszValue,
2536 gszPropIniFile);
2537 tgWriteProfileString(szPropSetSec, pszKey, NULL,
2538 gszPropIniFile);
2539 break;
2540 }
2541 }
2542 tgFreeProfileString(pszValue);
2543 }
2544 }
2545 pszKey += strlen(pszKey);
2546 }
2547 tgFreeProfileString(pszKeys);
2548 }
2549 pszName += strlen(pszName);
2550 }
2551 tgFreeProfileString(pszNames);
2552
2553 if (!already_updated) {
2554 tgWriteProfileString(NULL, NULL, NULL, gszPropIniFile);
2555 }
2556 }
2557
InitProperties()2558 void InitProperties()
2559 {
2560 struct PropInfoRec *ppir=NULL;
2561
2562 /* do not translate -- program constants */
2563 sprintf(gszPropIniFile, "%s%ccutpaste.ini", tgifDir, DIR_SEP);
2564
2565 strcpy(gszCopyPasteSec, "Copy/Paste Properties");
2566 strcpy(gszCopyPasteBackupSec, "Copy/Paste Properties - Backup");
2567 strcpy(gszPropSetSec, "Property Set Names");
2568 strcpy(gszPropProfilePrefix, "Property Profile");
2569
2570 for (ppir=gstPropInfo; ppir->bit != 0L; ppir++) {
2571 if (ppir->key != NULL) return;
2572
2573 ppir->desc = UtilStrDup(PropLoadString(ppir->bit));
2574 if (ppir->desc == NULL) FailAllocMessage();
2575
2576 sprintf(gszMsgBox, "0x%08lx", ppir->bit);
2577 ppir->key = UtilStrDup(gszMsgBox);
2578 if (ppir->key == NULL) FailAllocMessage();
2579 }
2580 UpdateSavedPropKeys();
2581 }
2582
2583 static
FormatPropForDisplay(lWhich,pProp,ppir,pszBuf)2584 void FormatPropForDisplay(lWhich, pProp, ppir, pszBuf)
2585 long lWhich;
2586 struct PropertiesRec *pProp;
2587 struct PropInfoRec *ppir;
2588 char *pszBuf;
2589 {
2590 char font_str[MAXSTRING];
2591 int nLen=0;
2592
2593 sprintf(pszBuf, "%s: ", ppir->desc);
2594 nLen = strlen(pszBuf);
2595
2596 switch (lWhich) {
2597 case PROP_MASK_CTM: strcat(pszBuf, "..."); break;
2598
2599 case PROP_MASK_COLOR: strcat(pszBuf, pProp->color_str); break;
2600 case PROP_MASK_WIDTH_INDEX:
2601 sprintf(&pszBuf[nLen], "%1d", pProp->width_index);
2602 break;
2603 case PROP_MASK_WIDTH: strcat(pszBuf, pProp->width_spec); break;
2604 case PROP_MASK_AW: strcat(pszBuf, pProp->aw_spec); break;
2605 case PROP_MASK_AH: strcat(pszBuf, pProp->ah_spec); break;
2606
2607 case PROP_MASK_TRANSPAT:
2608 sprintf(&pszBuf[nLen], "%1d", pProp->trans_pat);
2609 break;
2610 case PROP_MASK_FILL: sprintf(&pszBuf[nLen], "%1d", pProp->fill); break;
2611 case PROP_MASK_PEN: sprintf(&pszBuf[nLen], "%1d", pProp->pen); break;
2612 case PROP_MASK_DASH: sprintf(&pszBuf[nLen], "%1d", pProp->dash); break;
2613 case PROP_MASK_ARROW_STYLE:
2614 sprintf(&pszBuf[nLen], "%1d", pProp->arrow_style);
2615 break;
2616 case PROP_MASK_CURVED: sprintf(&pszBuf[nLen], "%1d", pProp->curved); break;
2617 case PROP_MASK_RCB_RADIUS:
2618 sprintf(&pszBuf[nLen], "%1d", pProp->rcb_radius);
2619 break;
2620 case PROP_MASK_TEXT_JUST:
2621 sprintf(&pszBuf[nLen], "%1d", pProp->text_just);
2622 break;
2623 case PROP_MASK_TEXT_SZ_UNIT:
2624 if (showFontSizeInPoints) {
2625 sprintf(&pszBuf[nLen], "%1dpt",
2626 SzUnitToPointSize(pProp->text_sz_unit));
2627 } else {
2628 sprintf(&pszBuf[nLen], "%1d", SzUnitToFontSize(pProp->text_sz_unit));
2629 }
2630 break;
2631 case PROP_MASK_VSPACE: sprintf(&pszBuf[nLen], "%1d", pProp->v_space); break;
2632 case PROP_MASK_UNDERLINE_ON:
2633 sprintf(&pszBuf[nLen], "%1d", pProp->underline_on);
2634 break;
2635 case PROP_MASK_OVERLINE_ON:
2636 sprintf(&pszBuf[nLen], "%1d", pProp->overline_on);
2637 break;
2638
2639 case PROP_MASK_TEXT_FONT:
2640 *font_str = '\0';
2641 GetPSFontStr(pProp->text_font, pProp->text_style, font_str);
2642 /* font_str starts with the '/' character */
2643 strcat(pszBuf, &font_str[1]);
2644 break;
2645 }
2646 }
2647
2648 static
GetPropSelection(pp_dsp_ptr,ppsz_entries,pn_num_entries,pn_marked_index,pp_check_array,cur_buf,p_void)2649 int GetPropSelection(pp_dsp_ptr, ppsz_entries, pn_num_entries, pn_marked_index,
2650 pp_check_array, cur_buf, p_void)
2651 DspList **pp_dsp_ptr;
2652 char ***ppsz_entries, *cur_buf;
2653 int *pn_num_entries, *pn_marked_index;
2654 struct CheckArrayRec **pp_check_array;
2655 void *p_void;
2656 {
2657 struct PropertiesRec *pProp=(struct PropertiesRec *)p_void;
2658 struct PropInfoRec *ppir=NULL;
2659 int num_rows=0;
2660 char **ppsz=NULL;
2661
2662 for (ppir=gstPropInfo; ppir->bit != 0L; ppir++) {
2663 if (ppir->checked) {
2664 num_rows++;
2665 }
2666 }
2667 *ppsz_entries = (char**)malloc(num_rows*sizeof(char*));
2668 if (*ppsz_entries == NULL) FailAllocMessage();
2669 memset(*ppsz_entries, 0, num_rows*sizeof(char*));
2670
2671 for (ppir=gstPropInfo, ppsz=(*ppsz_entries); ppir->bit != 0L; ppir++) {
2672 if (ppir->checked) {
2673 char szBuf[MAXSTRING];
2674
2675 *szBuf = '\0';
2676 FormatPropForDisplay(ppir->bit, pProp, ppir, szBuf);
2677 *ppsz = UtilStrDup(szBuf);
2678 if ((*ppsz) == NULL) FailAllocMessage();
2679 ppsz++;
2680 }
2681 }
2682 *pn_num_entries = num_rows;
2683 return TRUE;
2684 }
2685
2686 static
DoCopyProperties(pCheckArray,pProp)2687 int DoCopyProperties(pCheckArray, pProp)
2688 /*
2689 * Returns FALSE if nothing copied.
2690 */
2691 struct CheckArrayRec *pCheckArray;
2692 struct PropertiesRec *pProp;
2693 {
2694 struct PropInfoRec *ppir=NULL;
2695 int index=0, count=0;
2696 char *pszKeys=NULL;
2697
2698 tgWriteProfileString(gszCopyPasteSec, NULL, NULL, gszPropIniFile);
2699 for (ppir=gstPropInfo; ppir->bit != 0L; ppir++) {
2700 if (ppir->checked) {
2701 if (pCheckArray->value[0][index]) {
2702 WritePropToIni(ppir->bit, gszCopyPasteSec, ppir->key, pProp);
2703 count++;
2704 }
2705 index++;
2706 }
2707 }
2708 tgWriteProfileString(NULL, NULL, NULL, gszPropIniFile);
2709 if (count == 0) {
2710 strcpy(gszMsgBox, TgLoadString(STID_NO_PROPERTY_TO_COPY));
2711 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2712 return FALSE;
2713 }
2714 pszKeys = tgGetProfileString(gszCopyPasteSec, NULL, gszPropIniFile);
2715 if (pszKeys != NULL) {
2716 int total=(strlen(gszCopyPasteSec)+4), offset=0;
2717 char *pszKey=NULL;
2718 char *buf=(char*)malloc(total+1); /* sizeof buf is always total+1 */
2719
2720 if (buf == NULL) FailAllocMessage();
2721 memset(buf, 0, total+1);
2722 *buf = TGIF_HEADER;
2723 sprintf(&buf[1], "[%s]", gszCopyPasteSec);
2724 offset = total;
2725
2726 for (pszKey=pszKeys; *pszKey != '\0'; pszKey++) {
2727 int key_len=strlen(pszKey);
2728 char *pszValue=tgGetProfileString(gszCopyPasteSec, pszKey,
2729 gszPropIniFile);
2730
2731 if (pszValue != NULL) {
2732 int value_len=strlen(pszValue);
2733
2734 buf = (char*)realloc(buf, total+key_len+value_len+3);
2735 if (buf == NULL) FailAllocMessage();
2736 sprintf(&buf[offset], "%s=%s", pszKey, pszValue);
2737
2738 offset += key_len+value_len+2;
2739 total += key_len+value_len+2;
2740
2741 tgFreeProfileString(pszValue);
2742 } else {
2743 buf = (char*)realloc(buf, total+key_len+3);
2744 if (buf == NULL) FailAllocMessage();
2745 sprintf(&buf[offset], "%s=", pszKey);
2746
2747 offset += key_len+2;
2748 total += key_len+2;
2749 }
2750 pszKey += key_len;
2751 }
2752 buf[total] = '\0';
2753 tgFreeProfileString(pszKeys);
2754
2755 if (!WriteBufToCutBuffer(buf, total+1, TRUE, FALSE, NULL)) {
2756 strcpy(gszMsgBox, TgLoadString(STID_COPY_FAILED_OBJ_MAYBE_TOO_BIG));
2757 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2758 } else {
2759 strcpy(gszMsgBox, TgLoadString(STID_COPY_BUFFER_UPDATED));
2760 Msg(gszMsgBox);
2761 }
2762 free(buf);
2763 }
2764 return TRUE;
2765 }
2766
2767 static
PropSetExists(pszPropSet)2768 int PropSetExists(pszPropSet)
2769 char *pszPropSet;
2770 {
2771 int nReturn=FALSE;
2772 char *pszKeys=tgGetProfileString(gszPropSetSec, NULL, gszPropIniFile);
2773
2774 if (pszKeys != NULL) {
2775 char *pszKey=NULL;
2776
2777 for (pszKey=pszKeys; *pszKey != '\0'; pszKey++) {
2778 if (UtilStrICmp(pszPropSet, pszKey) == 0) {
2779 nReturn = TRUE;
2780 break;
2781 }
2782 pszKey += strlen(pszKey);
2783 }
2784 tgFreeProfileString(pszKeys);
2785 }
2786 return nReturn;
2787 }
2788
2789 static
DoSaveProperties(pCheckArray,pProp)2790 int DoSaveProperties(pCheckArray, pProp)
2791 /*
2792 * Returns FALSE if nothing saved.
2793 */
2794 struct CheckArrayRec *pCheckArray;
2795 struct PropertiesRec *pProp;
2796 {
2797 char szPropSet[MAXSTRING], szPropSetSec[MAXSTRING];
2798 struct PropInfoRec *ppir=NULL;
2799 int index=0, count=0;
2800
2801 *szPropSet = *szPropSetSec = '\0';
2802 strcpy(gszMsgBox, TgLoadString(STID_ENTER_NAME_FOR_PROP_SET));
2803 if (Dialog(gszMsgBox, NULL, szPropSet) == INVALID) return FALSE;
2804 UtilTrimBlanks(szPropSet);
2805 if (*szPropSet == '\0') return FALSE;
2806 if (PropSetExists(szPropSet)) {
2807 sprintf(gszMsgBox, TgLoadString(STID_PROP_SET_EXISTS_OVERWRITE_YNC),
2808 szPropSet);
2809 if (MsgBox(gszMsgBox, TOOL_NAME, YNC_MB) != MB_ID_YES) {
2810 return FALSE;
2811 }
2812 }
2813 sprintf(szPropSetSec, "%s: %s", gszPropProfilePrefix, szPropSet);
2814 tgWriteProfileString(gszPropSetSec, szPropSet, "", gszPropIniFile);
2815 tgWriteProfileString(szPropSetSec, NULL, NULL, gszPropIniFile);
2816 for (ppir=gstPropInfo; ppir->bit != 0L; ppir++) {
2817 if (ppir->checked) {
2818 if (pCheckArray->value[0][index]) {
2819 WritePropToIni(ppir->bit, szPropSetSec, ppir->key, pProp);
2820 count++;
2821 }
2822 index++;
2823 }
2824 }
2825 tgWriteProfileString(NULL, NULL, NULL, gszPropIniFile);
2826 if (count == 0) {
2827 strcpy(gszMsgBox, TgLoadString(STID_NO_PROP_TO_SAVE));
2828 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2829 return FALSE;
2830 }
2831 return TRUE;
2832 }
2833
2834 static
DoPasteProperties(pCheckArray,pProp)2835 int DoPasteProperties(pCheckArray, pProp)
2836 /*
2837 * Returns FALSE if nothing pasted.
2838 */
2839 struct CheckArrayRec *pCheckArray;
2840 struct PropertiesRec *pProp;
2841 {
2842 struct PropInfoRec *ppir=NULL;
2843 int index=0, count=0;
2844 int paste_sel=FALSE;
2845
2846 if ((curChoice == NOTHING || curChoice == VERTEXMODE ||
2847 curChoice == ROTATEMODE)) {
2848 paste_sel = (topSel != NULL);
2849 }
2850 for (ppir=gstPropInfo; ppir->bit != 0L; ppir++) {
2851 if (ppir->checked) {
2852 if (pCheckArray->value[0][index]) {
2853 count++;
2854 }
2855 index++;
2856 }
2857 }
2858 if (count == 0) {
2859 strcpy(gszMsgBox, TgLoadString(STID_NO_PROPERTY_TO_PASTE));
2860 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2861 return FALSE;
2862 }
2863 if (paste_sel) {
2864 HighLightReverse();
2865 StartCompositeCmd();
2866 }
2867 for (ppir=gstPropInfo, index=0; ppir->bit != 0L; ppir++) {
2868 if (ppir->checked) {
2869 if (pCheckArray->value[0][index]) {
2870 DoPasteAProperty(ppir->bit, pProp);
2871 }
2872 index++;
2873 }
2874 }
2875 if (paste_sel) {
2876 EndCompositeCmd();
2877 HighLightForward();
2878 }
2879 return TRUE;
2880 }
2881
2882 #define COPY_PROP 0
2883 #define PASTE_PROP 1
2884 #define SAVE_PROP 2
2885 #define RESTORE_PROP 3
2886
2887 static
FreePropSelection(pp_dsp_ptr,ppsz_entries,pn_num_entries,pn_marked_index,pp_check_array,cur_buf,btn_id,selected_index,p_void)2888 int FreePropSelection(pp_dsp_ptr, ppsz_entries, pn_num_entries, pn_marked_index,
2889 pp_check_array, cur_buf, btn_id, selected_index, p_void)
2890 DspList **pp_dsp_ptr;
2891 char ***ppsz_entries, *cur_buf;
2892 int *pn_num_entries, *pn_marked_index, btn_id, selected_index;
2893 struct CheckArrayRec **pp_check_array;
2894 void *p_void;
2895 {
2896 struct PropertiesRec *pProp=(struct PropertiesRec *)p_void;
2897 struct PropInfoRec *ppir=NULL;
2898 int nReturn=TRUE;
2899
2900 switch ((int)(long)(pProp->userdata)) {
2901 case COPY_PROP:
2902 if (btn_id == COPY_BUTTON) {
2903 nReturn = !DoCopyProperties(*pp_check_array, pProp);
2904 }
2905 break;
2906 case SAVE_PROP:
2907 if (btn_id == SAVE_BUTTON) {
2908 nReturn = !DoSaveProperties(*pp_check_array, pProp);
2909 }
2910 break;
2911 case PASTE_PROP:
2912 if (btn_id == PASTE_BUTTON) {
2913 nReturn = !DoPasteProperties(*pp_check_array, pProp);
2914 }
2915 break;
2916 case RESTORE_PROP:
2917 if (btn_id == RESTORE_BUTTON) {
2918 nReturn = !DoPasteProperties(*pp_check_array, pProp);
2919 }
2920 break;
2921 }
2922 if (*ppsz_entries != NULL) {
2923 char **ppsz=(*ppsz_entries);
2924
2925 for (ppir=gstPropInfo; ppir->bit != 0L; ppir++) {
2926 if (ppir->checked) {
2927 UtilFree(*ppsz);
2928 ppsz++;
2929 }
2930 }
2931 free(*ppsz_entries);
2932 *ppsz_entries = NULL;
2933 }
2934 return nReturn;
2935 }
2936
2937 static
PropSelectionCheckUpdate(pp_dsp_ptr,ppsz_entries,pn_num_entries,pn_marked_index,pp_check_array,cur_buf,col,row,p_void)2938 int PropSelectionCheckUpdate(pp_dsp_ptr, ppsz_entries, pn_num_entries,
2939 pn_marked_index, pp_check_array, cur_buf, col, row, p_void)
2940 DspList **pp_dsp_ptr;
2941 char ***ppsz_entries, *cur_buf;
2942 int *pn_num_entries, *pn_marked_index, col, row;
2943 struct CheckArrayRec **pp_check_array;
2944 void *p_void;
2945 {
2946 struct PropertiesRec *pProp=(struct PropertiesRec *)p_void;
2947 char *psz=NULL, saved_ch='\0', *buf=NULL;
2948 int checked=FALSE;
2949
2950 if (ppsz_entries == NULL || *ppsz_entries == NULL ||
2951 (*ppsz_entries)[row] == NULL || pp_check_array == NULL ||
2952 (*pp_check_array) == NULL || (*pp_check_array)->value == NULL) {
2953 return FALSE;
2954 }
2955 buf = (*ppsz_entries)[row];
2956 checked = (*pp_check_array)->value[0][row];
2957
2958 psz = strchr(buf, ':');
2959 if (psz != NULL) {
2960 saved_ch = *psz;
2961 *psz = '\0';
2962 switch ((int)(long)(pProp->userdata)) {
2963 case COPY_PROP:
2964 sprintf(gszMsgBox, TgLoadString(checked ? STID_WILL_COPY_NAMED_PROP :
2965 STID_WILL_NOT_COPY_NAMED_PROP), buf);
2966 break;
2967 case SAVE_PROP:
2968 sprintf(gszMsgBox, TgLoadString(checked ? STID_WILL_SAVE_NAMED_PROP :
2969 STID_WILL_NOT_SAVE_NAMED_PROP), buf);
2970 break;
2971 case PASTE_PROP:
2972 sprintf(gszMsgBox, TgLoadString(checked ? STID_WILL_PASTE_NAMED_PROP :
2973 STID_WILL_NOT_PASTE_NAMED_PROP), buf);
2974 break;
2975 case RESTORE_PROP:
2976 sprintf(gszMsgBox, TgLoadString(checked ?
2977 STID_WILL_RESTORE_NAMED_PROP : STID_WILL_NOT_RESTORE_NAMED_PROP),
2978 buf);
2979 break;
2980 }
2981 *psz = saved_ch;
2982 }
2983 SetStringStatus(gszMsgBox);
2984
2985 return TRUE;
2986 }
2987
2988 static
SelectProperties(pszTitle,nWhich,pCheckArray,pProp)2989 void SelectProperties(pszTitle, nWhich, pCheckArray, pProp)
2990 char *pszTitle;
2991 int nWhich;
2992 struct CheckArrayRec *pCheckArray;
2993 struct PropertiesRec *pProp;
2994 {
2995 char win_name[128];
2996
2997 ResetNamesInfo();
2998
2999 NamesSetTitle(pszTitle);
3000 switch (nWhich) {
3001 case COPY_PROP:
3002 NamesAddButton(TgLoadCachedString(CSTID_COPY), COPY_BUTTON);
3003 NamesAddButton(TgLoadCachedString(CSTID_CANCEL), BUTTON_CANCEL);
3004 /* ignore double-click and <CR> */
3005 NamesSetDefaultBtnId(COPY_BUTTON, INVALID);
3006 NamesSetEntries(NULL, NULL, 0, pCheckArray, TRUE, INVALID, 0);
3007 NamesSetStyle(NAMES_SIMPLE_SELECT_NAME, NAMES_LOOP_MANY);
3008 NamesSetCallback((GetEntriesFunc*)GetPropSelection,
3009 (AfterLoopFunc*)FreePropSelection,
3010 (CheckUpdateFunc*)PropSelectionCheckUpdate);
3011 sprintf(win_name, TgLoadString(STID_TOOL_COPY_PROP), TOOL_NAME);
3012 break;
3013 case SAVE_PROP:
3014 NamesAddButton(TgLoadCachedString(CSTID_SAVE), SAVE_BUTTON);
3015 NamesAddButton(TgLoadCachedString(CSTID_CANCEL), BUTTON_CANCEL);
3016 /* ignore double-click and <CR> */
3017 NamesSetDefaultBtnId(SAVE_BUTTON, INVALID);
3018 NamesSetEntries(NULL, NULL, 0, pCheckArray, TRUE, INVALID, 0);
3019 NamesSetStyle(NAMES_SIMPLE_SELECT_NAME, NAMES_LOOP_MANY);
3020 NamesSetCallback((GetEntriesFunc*)GetPropSelection,
3021 (AfterLoopFunc*)FreePropSelection,
3022 (CheckUpdateFunc*)PropSelectionCheckUpdate);
3023 sprintf(win_name, TgLoadString(STID_TOOL_SAVE_PROP), TOOL_NAME);
3024 break;
3025 case PASTE_PROP:
3026 NamesAddButton(TgLoadCachedString(CSTID_PASTE), PASTE_BUTTON);
3027 NamesAddButton(TgLoadCachedString(CSTID_CANCEL), BUTTON_CANCEL);
3028 /* ignore double-click and <CR> */
3029 NamesSetDefaultBtnId(PASTE_BUTTON, INVALID);
3030 NamesSetEntries(NULL, NULL, 0, pCheckArray, TRUE, INVALID, 0);
3031 NamesSetStyle(NAMES_SIMPLE_SELECT_NAME, NAMES_LOOP_MANY);
3032 NamesSetCallback((GetEntriesFunc*)GetPropSelection,
3033 (AfterLoopFunc*)FreePropSelection,
3034 (CheckUpdateFunc*)PropSelectionCheckUpdate);
3035 sprintf(win_name, TgLoadString(STID_TOOL_PASTE_PROP), TOOL_NAME);
3036 break;
3037 case RESTORE_PROP:
3038 NamesAddButton(TgLoadCachedString(CSTID_RESTORE), RESTORE_BUTTON);
3039 NamesAddButton(TgLoadCachedString(CSTID_CANCEL), BUTTON_CANCEL);
3040 /* ignore double-click and <CR> */
3041 NamesSetDefaultBtnId(RESTORE_BUTTON, INVALID);
3042 NamesSetEntries(NULL, NULL, 0, pCheckArray, TRUE, INVALID, 0);
3043 NamesSetStyle(NAMES_SIMPLE_SELECT_NAME, NAMES_LOOP_MANY);
3044 NamesSetCallback((GetEntriesFunc*)GetPropSelection,
3045 (AfterLoopFunc*)FreePropSelection,
3046 (CheckUpdateFunc*)PropSelectionCheckUpdate);
3047 sprintf(win_name, TgLoadString(STID_TOOL_RESTORE_PROP), TOOL_NAME);
3048 break;
3049 }
3050 Names(win_name, NULL, NULL, 0, pProp);
3051 }
3052
3053 static
PrepareToCopyProperties(pProp,lMask,lSkip,pCheckArray)3054 int PrepareToCopyProperties(pProp, lMask, lSkip, pCheckArray)
3055 struct PropertiesRec *pProp;
3056 long lMask, lSkip;
3057 struct CheckArrayRec *pCheckArray;
3058 {
3059 struct PropInfoRec *ppir=NULL;
3060 int index=0, num_rows=0;
3061
3062 for (ppir=gstPropInfo; ppir->bit != 0L; ppir++) {
3063 ppir->checked = FALSE;
3064 if ((lMask & ppir->bit) != 0L && (lSkip & ppir->bit) == 0) {
3065 num_rows++;
3066 }
3067 }
3068 pCheckArray->num_cols = 1;
3069 pCheckArray->num_rows = num_rows;
3070
3071 pCheckArray->value = (int**)malloc(sizeof(int*));
3072 if (pCheckArray->value == NULL) FailAllocMessage();
3073 memset(pCheckArray->value, 0, sizeof(int*));
3074
3075 pCheckArray->value[0] = (int*)malloc(num_rows*sizeof(int));
3076 if (pCheckArray->value[0] == NULL) FailAllocMessage();
3077 memset(pCheckArray->value[0], 0, num_rows*sizeof(int));
3078
3079 for (ppir=gstPropInfo, index=0; ppir->bit != 0L; ppir++) {
3080 long bit=ppir->bit;
3081
3082 if ((lMask & bit) != 0L && (lSkip & bit) == 0) {
3083 ppir->checked = TRUE;
3084 pCheckArray->value[0][index++] = TRUE;
3085 }
3086 }
3087 return TRUE;
3088 }
3089
3090 static
PrepareToPasteProperties(pszSec,plMask,pCheckArray,pProp)3091 int PrepareToPasteProperties(pszSec, plMask, pCheckArray, pProp)
3092 char *pszSec;
3093 struct PropertiesRec *pProp;
3094 long *plMask;
3095 struct CheckArrayRec *pCheckArray;
3096 {
3097 struct PropInfoRec *ppir=NULL;
3098 int index=0, num_rows=0;
3099
3100 for (ppir=gstPropInfo; ppir->bit != 0L; ppir++) {
3101 ppir->checked = FALSE;
3102 }
3103 if (!ReadPropFromIni(pszSec, plMask, pCheckArray, pProp)) {
3104 return FALSE;
3105 }
3106 num_rows = pCheckArray->num_rows;
3107
3108 pCheckArray->value = (int**)malloc(sizeof(int*));
3109 if (pCheckArray->value == NULL) FailAllocMessage();
3110 memset(pCheckArray->value, 0, sizeof(int*));
3111
3112 pCheckArray->value[0] = (int*)malloc(num_rows*sizeof(int));
3113 if (pCheckArray->value[0] == NULL) FailAllocMessage();
3114 memset(pCheckArray->value[0], 0, num_rows*sizeof(int));
3115
3116 for (ppir=gstPropInfo, index=0; ppir->bit != 0L; ppir++) {
3117 long bit=ppir->bit;
3118
3119 if (((*plMask) & bit) != 0L) {
3120 ppir->checked = TRUE;
3121 pCheckArray->value[0][index++] = TRUE;
3122 }
3123 }
3124 return TRUE;
3125 }
3126
3127 static
SetupProperties(pProp,plMask,plSkip,pCheckArray,nWhich)3128 int SetupProperties(pProp, plMask, plSkip, pCheckArray, nWhich)
3129 struct PropertiesRec *pProp;
3130 long *plMask, *plSkip;
3131 struct CheckArrayRec *pCheckArray;
3132 int nWhich;
3133 {
3134 int copy_sel=FALSE;
3135
3136 pProp->userdata = (void*)(long)nWhich;
3137 if ((curChoice == NOTHING || curChoice == VERTEXMODE ||
3138 curChoice == ROTATEMODE)) {
3139 if (topSel == NULL) {
3140 copy_sel = FALSE;
3141 } else if (topSel == botSel) {
3142 copy_sel = TRUE;
3143 } else {
3144 switch (nWhich) {
3145 case COPY_PROP:
3146 strcpy(gszMsgBox, TgLoadString(STID_SEL_ONLY_ONE_FOR_COPY_PROP));
3147 break;
3148 case SAVE_PROP:
3149 strcpy(gszMsgBox, TgLoadString(STID_SEL_ONLY_ONE_FOR_SAVE_PROP));
3150 break;
3151 }
3152 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3153 return FALSE;
3154 }
3155 }
3156 if (copy_sel) {
3157 SetPropMask(topSel->obj, plMask, plSkip, pProp);
3158 } else {
3159 SetPropMask(NULL, plMask, plSkip, pProp);
3160 }
3161 /* shouldn't do this if we support multiple objects */
3162 *plSkip = ~((*plMask) | PROP_MASK_WIDTH_INDEX);
3163
3164 if (pCheckArray != NULL) {
3165 return PrepareToCopyProperties(pProp, *plMask, *plSkip, pCheckArray);
3166 }
3167 return TRUE;
3168 }
3169
3170 static
FixMasksForGetProperty(pProp,plMask,plSkip)3171 void FixMasksForGetProperty(pProp, plMask, plSkip)
3172 struct PropertiesRec *pProp;
3173 long *plMask, *plSkip;
3174 {
3175 long lMask=(*plMask);
3176
3177 *plSkip |= PROP_MASK_CTM;
3178
3179 if ((lMask & PROP_MASK_WIDTH) == PROP_MASK_WIDTH) {
3180 int i=0;
3181 char *width_spec=pProp->width_spec;
3182
3183 if (((lMask & PROP_MASK_AW) == PROP_MASK_AW) &&
3184 ((lMask & PROP_MASK_AH) == PROP_MASK_AH)) {
3185 char *aw_spec=pProp->aw_spec;
3186 char *ah_spec=pProp->ah_spec;
3187
3188 *plSkip |= (PROP_MASK_WIDTH | PROP_MASK_AW | PROP_MASK_AH);
3189 for (i=0; i < maxLineWidths; i++) {
3190 if (strcmp(width_spec, curWidthOfLineSpec[i]) == 0 &&
3191 strcmp(aw_spec, curArrowHeadWSpec[i]) == 0 &&
3192 strcmp(ah_spec, curArrowHeadHSpec[i]) == 0) {
3193 pProp->width_index = i;
3194 *plMask |= PROP_MASK_WIDTH_INDEX;
3195 break;
3196 }
3197 }
3198 } else {
3199 *plSkip |= (PROP_MASK_WIDTH);
3200 for (i=0; i < maxLineWidths; i++) {
3201 if (strcmp(width_spec, curWidthOfLineSpec[i]) == 0) {
3202 pProp->width_index = i;
3203 *plMask |= PROP_MASK_WIDTH_INDEX;
3204 break;
3205 }
3206 }
3207 }
3208 }
3209 }
3210
DoGetProperty(target_index)3211 void DoGetProperty(target_index)
3212 int target_index;
3213 {
3214 struct PropertiesRec properties;
3215 struct PropInfoRec *ppir=NULL;
3216 long lMask=0L, lSkip=0L;
3217 int index=0;
3218 struct SelRec *saved_top_sel=NULL, *saved_bot_sel=NULL;
3219
3220 memset(&properties, 0, sizeof(struct PropertiesRec));
3221 if (!SetupProperties(&properties, &lMask, &lSkip, NULL, COPY_PROP)) {
3222 return;
3223 }
3224 FixMasksForGetProperty(&properties, &lMask, &lSkip);
3225
3226 HighLightReverse();
3227 saved_top_sel = topSel;
3228 saved_bot_sel = botSel;
3229 topSel = botSel = NULL;
3230 UpdSelBBox();
3231 for (ppir=gstPropInfo; ppir->bit != 0L; ppir++) {
3232 if ((lMask & ppir->bit) != 0L && (lSkip & ppir->bit) == 0) {
3233 if (index == target_index) {
3234 /* do something */
3235 DoGetAProperty(ppir->bit, &properties);
3236 break;
3237 }
3238 index++;
3239 }
3240 }
3241 topSel = saved_top_sel;
3242 botSel = saved_bot_sel;
3243 UpdSelBBox();
3244 HighLightReverse();
3245 }
3246
CreateGetPropertyInfo()3247 EditAttrInfo *CreateGetPropertyInfo()
3248 {
3249 struct PropertiesRec properties;
3250 struct PropInfoRec *ppir=NULL;
3251 EditAttrInfo *pEditAttrInfo=NULL;
3252 long lMask=0L, lSkip=0L;
3253 int index=0, num_attrs=0;
3254 char **attr_strings=NULL, **status_strings=NULL;
3255
3256 pEditAttrInfo = (EditAttrInfo*)malloc(sizeof(EditAttrInfo));
3257 if (pEditAttrInfo == NULL) FailAllocMessage();
3258 memset(pEditAttrInfo, 0, sizeof(EditAttrInfo));
3259
3260 memset(&properties, 0, sizeof(struct PropertiesRec));
3261 if (!SetupProperties(&properties, &lMask, &lSkip, NULL, COPY_PROP)) {
3262 return NULL;
3263 }
3264 FixMasksForGetProperty(&properties, &lMask, &lSkip);
3265
3266 for (ppir=gstPropInfo; ppir->bit != 0L; ppir++) {
3267 ppir->checked = FALSE;
3268 if ((lMask & ppir->bit) != 0L && (lSkip & ppir->bit) == 0) {
3269 num_attrs++;
3270 }
3271 }
3272 attr_strings = (char**)malloc(num_attrs*sizeof(char*));
3273 status_strings = (char**)malloc(num_attrs*sizeof(char*));
3274 if (attr_strings == NULL || status_strings == NULL) FailAllocMessage();
3275 memset(attr_strings, 0, num_attrs*sizeof(char*));
3276 memset(status_strings, 0, num_attrs*sizeof(char*));
3277
3278 for (ppir=gstPropInfo, index=0; ppir->bit != 0L; ppir++) {
3279 long bit=ppir->bit;
3280
3281 if ((lMask & bit) != 0L && (lSkip & bit) == 0) {
3282 char *psz=NULL, szBuf[MAXSTRING];
3283
3284 *szBuf = '\0';
3285 FormatPropForDisplay(ppir->bit, &properties, ppir, szBuf);
3286 attr_strings[index] = UtilStrDup(szBuf);
3287 if (attr_strings[index] == NULL) FailAllocMessage();
3288 if ((psz=strchr(szBuf, ':')) != NULL) {
3289 *psz++ = '\0';
3290 UtilTrimBlanks(psz);
3291 sprintf(gszMsgBox,
3292 TgLoadCachedString(CSTID_GET_NAMED_PROP_FROM_SEL_OBJ), szBuf);
3293 status_strings[index] = UtilStrDup(gszMsgBox);
3294 if (status_strings[index] == NULL) FailAllocMessage();
3295 }
3296 ppir->checked = TRUE;
3297 index++;
3298 }
3299 }
3300 pEditAttrInfo->num_attrs = num_attrs;
3301 pEditAttrInfo->fore_colors = NULL;
3302 pEditAttrInfo->attr_indices = NULL;
3303 pEditAttrInfo->attr_names = NULL;
3304 pEditAttrInfo->attr_values = NULL;
3305 pEditAttrInfo->attr_strings = attr_strings;
3306 pEditAttrInfo->status_strings = status_strings;
3307
3308 return pEditAttrInfo;
3309 }
3310
CopyProperties(nPrompt)3311 void CopyProperties(nPrompt)
3312 int nPrompt;
3313 {
3314 struct PropertiesRec properties;
3315 long lMask=0L, lSkip=0L;
3316 struct CheckArrayRec check_array;
3317
3318 memset(&properties, 0, sizeof(struct PropertiesRec));
3319 memset(&check_array, 0, sizeof(struct CheckArrayRec));
3320 if (!SetupProperties(&properties, &lMask, &lSkip, &check_array, COPY_PROP)) {
3321 return;
3322 }
3323 tgWriteProfileString(gszCopyPasteSec, NULL, NULL, gszPropIniFile);
3324 tgWriteProfileString(NULL, NULL, NULL, gszPropIniFile);
3325 if (nPrompt) {
3326 SelectProperties(TgLoadString(STID_UNCHECK_PROP_FOR_COPY_DOTS),
3327 COPY_PROP, &check_array, &properties);
3328 } else {
3329 DoCopyProperties(&check_array, &properties);
3330 }
3331 CleanUpCheckArray(&check_array);
3332 }
3333
SaveProperties()3334 void SaveProperties()
3335 {
3336 struct PropertiesRec properties;
3337 long lMask=0L, lSkip=0L;
3338 struct CheckArrayRec check_array;
3339
3340 memset(&properties, 0, sizeof(struct PropertiesRec));
3341 memset(&check_array, 0, sizeof(struct CheckArrayRec));
3342 if (!SetupProperties(&properties, &lMask, &lSkip, &check_array, SAVE_PROP)) {
3343 return;
3344 }
3345 SelectProperties(TgLoadString(STID_UNCHECK_PROP_FOR_SAVE_DOTS),
3346 SAVE_PROP, &check_array, &properties);
3347 CleanUpCheckArray(&check_array);
3348 }
3349
3350 static
WriteBufToIni(buf,ini_fname)3351 int WriteBufToIni(buf, ini_fname)
3352 char *buf, *ini_fname;
3353 {
3354 char *pszSec=buf, *pszKey=NULL, *pszKeyStart=NULL;
3355 int len=strlen(pszSec);
3356
3357 pszKeyStart = (&buf[len+1]);
3358 if (*pszSec == '[' && pszSec[len-1] == ']') {
3359 pszSec[len-1] = '\0';
3360 pszSec++;
3361 }
3362 tgWriteProfileString(pszSec, NULL, NULL, ini_fname);
3363
3364 for (pszKey=pszKeyStart; *pszKey != '\0'; pszKey++) {
3365 char *psz=strchr(pszKey, '=');
3366
3367 if (psz == NULL) {
3368 tgWriteProfileString(pszSec, NULL, NULL, ini_fname);
3369 tgWriteProfileString(NULL, NULL, NULL, ini_fname);
3370 return FALSE;
3371 }
3372 *psz = '\0';
3373 tgWriteProfileString(pszSec, pszKey, &psz[1], ini_fname);
3374 *psz = '=';
3375
3376 pszKey += strlen(pszKey);
3377 }
3378 tgWriteProfileString(NULL, NULL, NULL, ini_fname);
3379
3380 return TRUE;
3381 }
3382
PasteProperties(nPrompt)3383 void PasteProperties(nPrompt)
3384 int nPrompt;
3385 {
3386 struct PropertiesRec properties;
3387 long lMask=0L, lSkip=0L;
3388 struct CheckArrayRec check_array;
3389 int len=0, from_selection=FALSE;
3390 char *cut_buffer=NULL;
3391
3392 cut_buffer = FetchSelectionOrCutBuffer(&len, &from_selection);
3393 if (cut_buffer == NULL) {
3394 MsgBox(TgLoadString(STID_CUT_BUFFER_EMPTY), TOOL_NAME, INFO_MB);
3395 return;
3396 }
3397 sprintf(gszMsgBox, "[%s]", gszCopyPasteSec);
3398 if (((unsigned char)(*cut_buffer)) != TGIF_HEADER ||
3399 strcmp(&cut_buffer[1], gszMsgBox) != 0) {
3400 FreeSelectionOrCutBuffer(cut_buffer, from_selection);
3401 MsgBox(TgLoadString(STID_COPY_PROP_BEFORE_PASTE), TOOL_NAME, INFO_MB);
3402 return;
3403 }
3404 if (!WriteBufToIni(&cut_buffer[1], gszPropIniFile)) {
3405 strcpy(gszMsgBox, TgLoadString(STID_MALFORMED_CUT_BUF_WHILE_PASTE));
3406 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3407
3408 FreeSelectionOrCutBuffer(cut_buffer, from_selection);
3409 return;
3410 }
3411 FreeSelectionOrCutBuffer(cut_buffer, from_selection);
3412
3413 memset(&check_array, 0, sizeof(struct CheckArrayRec));
3414 memset(&properties, 0, sizeof(struct PropertiesRec));
3415 properties.userdata = (void*)PASTE_PROP;
3416 if (!PrepareToPasteProperties(gszCopyPasteSec, &lMask, &check_array,
3417 &properties)) {
3418 return;
3419 }
3420 lSkip = (~lMask);
3421
3422 if (nPrompt) {
3423 SelectProperties(TgLoadString(STID_UNCHECK_PROP_FOR_PASTE_DOTS),
3424 PASTE_PROP, &check_array, &properties);
3425 } else {
3426 DoPasteProperties(&check_array, &properties);
3427 }
3428 CleanUpCheckArray(&check_array);
3429 }
3430
3431 static
GetPropSetNames(pp_dsp_ptr,ppsz_entries,pn_num_entries,pn_marked_index,pp_check_array,cur_buf,p_void)3432 int GetPropSetNames(pp_dsp_ptr, ppsz_entries, pn_num_entries, pn_marked_index,
3433 pp_check_array, cur_buf, p_void)
3434 DspList **pp_dsp_ptr;
3435 char ***ppsz_entries, *cur_buf;
3436 int *pn_num_entries, *pn_marked_index;
3437 struct CheckArrayRec **pp_check_array;
3438 void *p_void;
3439 {
3440 int num_rows=0;
3441 char **ppsz=NULL, *pszName=NULL;
3442 char *pszNames=tgGetProfileString(gszPropSetSec, NULL, gszPropIniFile);
3443
3444 if (pszNames == NULL) {
3445 strcpy(gszMsgBox, TgLoadString(STID_NO_PROP_SETS_TO_RESTORE));
3446 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3447 return FALSE;
3448 }
3449 for (pszName=pszNames; *pszName != '\0'; pszName++, num_rows++) {
3450 pszName += strlen(pszName);
3451 }
3452 if (num_rows == 0) {
3453 tgWriteProfileString(gszPropSetSec, NULL, NULL, gszPropIniFile);
3454 tgWriteProfileString(NULL, NULL, NULL, gszPropIniFile);
3455 strcpy(gszMsgBox, TgLoadString(STID_NO_PROP_SETS_TO_RESTORE));
3456 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3457 return FALSE;
3458 }
3459 *ppsz_entries = (char**)malloc(num_rows*sizeof(char*));
3460 if (*ppsz_entries == NULL) FailAllocMessage();
3461 memset(*ppsz_entries, 0, num_rows*sizeof(char*));
3462
3463 for (pszName=pszNames, ppsz=(*ppsz_entries); *pszName != '\0'; pszName++) {
3464 *ppsz = UtilStrDup(pszName);
3465 if ((*ppsz) == NULL) FailAllocMessage();
3466 ppsz++;
3467
3468 pszName += strlen(pszName);
3469 }
3470 tgFreeProfileString(pszNames);
3471 *pn_num_entries = num_rows;
3472 return TRUE;
3473 }
3474
3475 static
FreePropSetNames(pp_dsp_ptr,ppsz_entries,pn_num_entries,pn_marked_index,pp_check_array,cur_buf,btn_id,selected_index,p_void)3476 int FreePropSetNames(pp_dsp_ptr, ppsz_entries, pn_num_entries, pn_marked_index,
3477 pp_check_array, cur_buf, btn_id, selected_index, p_void)
3478 DspList **pp_dsp_ptr;
3479 char ***ppsz_entries, *cur_buf;
3480 int *pn_num_entries, *pn_marked_index, btn_id, selected_index;
3481 struct CheckArrayRec **pp_check_array;
3482 void *p_void;
3483 {
3484 int nReturn=TRUE;
3485
3486 if (btn_id == BUTTON_OK) {
3487 nReturn = FALSE;
3488 }
3489 if (*ppsz_entries != NULL) {
3490 char **ppsz=(*ppsz_entries);
3491 int i=0;
3492
3493 for (i=0; i < *pn_num_entries; i++) {
3494 UtilFree(*ppsz);
3495 ppsz++;
3496 }
3497 free(*ppsz_entries);
3498 *ppsz_entries = NULL;
3499 }
3500 return nReturn;
3501 }
3502
3503 static
SelectPropSetForRestore(pszTitle,pszPropSet,nPropSetSize)3504 int SelectPropSetForRestore(pszTitle, pszPropSet, nPropSetSize)
3505 char *pszTitle, *pszPropSet;
3506 int nPropSetSize;
3507 {
3508 char win_name[128];
3509
3510 ResetNamesInfo();
3511
3512 NamesSetTitle(pszTitle);
3513 NamesAddButton(TgLoadCachedString(CSTID_OK), BUTTON_OK);
3514 NamesAddButton(TgLoadCachedString(CSTID_CANCEL), BUTTON_CANCEL);
3515 NamesSetDefaultBtnId(BUTTON_OK, BUTTON_OK);
3516 NamesSetEntries(NULL, NULL, 0, NULL, TRUE, INVALID, 0);
3517 NamesSetStyle(NAMES_SIMPLE_SELECT_NAME, NAMES_LOOP_MANY);
3518 NamesSetCallback((GetEntriesFunc*)GetPropSetNames,
3519 (AfterLoopFunc*)FreePropSetNames, NULL);
3520 sprintf(win_name, TgLoadString(STID_TOOL_RESTORE_PROP), TOOL_NAME);
3521
3522 Names(win_name, NULL, pszPropSet, nPropSetSize, pszPropSet);
3523 return (*pszPropSet != '\0');
3524 }
3525
RestoreProperties()3526 void RestoreProperties()
3527 {
3528 struct PropertiesRec properties;
3529 long lMask=0L, lSkip=0L;
3530 struct CheckArrayRec check_array;
3531 char szPropSet[MAXSTRING], szPropSetSec[MAXSTRING];
3532
3533 memset(&check_array, 0, sizeof(struct CheckArrayRec));
3534 memset(&properties, 0, sizeof(struct PropertiesRec));
3535 properties.userdata = (void*)RESTORE_PROP;
3536 *szPropSet = '\0';
3537 if (!SelectPropSetForRestore(TgLoadString(STID_SEL_A_PROP_SET_TO_RESTORE),
3538 szPropSet, sizeof(szPropSet))) {
3539 return;
3540 }
3541 sprintf(szPropSetSec, "%s: %s", gszPropProfilePrefix, szPropSet);
3542 if (!PrepareToPasteProperties(szPropSetSec, &lMask, &check_array,
3543 &properties)) {
3544 return;
3545 }
3546 lSkip = (~lMask);
3547
3548 SelectProperties(TgLoadString(STID_UNCHECK_PROP_FOR_RESTORE_DOTS),
3549 RESTORE_PROP, &check_array, &properties);
3550 CleanUpCheckArray(&check_array);
3551 }
3552
BackupCopiedProperties()3553 void BackupCopiedProperties()
3554 {
3555 char *pszKeys=tgGetProfileString(gszCopyPasteSec, NULL, gszPropIniFile);
3556
3557 tgWriteProfileString(gszCopyPasteBackupSec, NULL, NULL, gszPropIniFile);
3558 if (pszKeys != NULL) {
3559 char *pszKey=NULL;
3560
3561 for (pszKey=pszKeys; *pszKey != '\0'; pszKey++) {
3562 char *pszValue=tgGetProfileString(gszCopyPasteSec, pszKey,
3563 gszPropIniFile);
3564
3565 if (pszValue != NULL) {
3566 tgWriteProfileString(gszCopyPasteBackupSec, pszKey, pszValue,
3567 gszPropIniFile);
3568 tgFreeProfileString(pszValue);
3569 }
3570 pszKey += strlen(pszKey);
3571 }
3572 tgFreeProfileString(pszKeys);
3573 }
3574 tgWriteProfileString(NULL, NULL, NULL, gszPropIniFile);
3575 }
3576
RestoreCopiedProperties()3577 void RestoreCopiedProperties()
3578 {
3579 char *pszKeys=tgGetProfileString(gszCopyPasteBackupSec, NULL,
3580 gszPropIniFile);
3581
3582 tgWriteProfileString(gszCopyPasteSec, NULL, NULL, gszPropIniFile);
3583 if (pszKeys != NULL) {
3584 char *pszKey=NULL;
3585
3586 for (pszKey=pszKeys; *pszKey != '\0'; pszKey++) {
3587 char *pszValue=tgGetProfileString(gszCopyPasteBackupSec, pszKey,
3588 gszPropIniFile);
3589
3590 if (pszValue != NULL) {
3591 tgWriteProfileString(gszCopyPasteSec, pszKey, pszValue,
3592 gszPropIniFile);
3593 tgFreeProfileString(pszValue);
3594 }
3595 pszKey += strlen(pszKey);
3596 }
3597 tgFreeProfileString(pszKeys);
3598 }
3599 tgWriteProfileString(NULL, NULL, NULL, gszPropIniFile);
3600 }
3601
3602 static
IniSectionListing(pszSection,pszIniFile,pnEntries)3603 DspList *IniSectionListing(pszSection, pszIniFile, pnEntries)
3604 char *pszSection, *pszIniFile;
3605 int *pnEntries;
3606 {
3607 DspList *dsp_ptr=NULL;
3608 char *pszKeys=NULL;
3609 int num_entries=0;
3610
3611 *pnEntries = 0;
3612 if ((pszKeys=tgGetProfileString(pszSection, NULL, pszIniFile)) != NULL) {
3613 DspList *pdl=NULL;
3614 char *pszKey=NULL;
3615
3616 for (pszKey=pszKeys; *pszKey != '\0'; pszKey++) {
3617 num_entries++;
3618 pszKey += strlen(pszKey);
3619 }
3620 dsp_ptr = (DspList*)malloc(num_entries*sizeof(DspList));
3621 if (dsp_ptr == NULL) FailAllocMessage();
3622 memset(dsp_ptr, 0, num_entries*sizeof(DspList));
3623 for (pszKey=pszKeys, pdl=dsp_ptr; *pszKey != '\0'; pszKey++, pdl++) {
3624 char *pszValue=tgGetProfileString(pszSection, pszKey, pszIniFile);
3625
3626 sprintf(gszMsgBox, "%s=%s", pszKey, (pszValue==NULL ? "" : pszValue));
3627 UtilStrCpyN(pdl->itemstr, sizeof(pdl->itemstr), gszMsgBox);
3628 /* use the directory field for inherited */
3629 pdl->directory = TRUE;
3630 pdl->next = (&pdl[1]);
3631
3632 if (pszValue != NULL) tgFreeProfileString(pszValue);
3633 pszKey += strlen(pszKey);
3634 }
3635 tgFreeProfileString(pszKeys);
3636 }
3637 if (num_entries == 0) return NULL;
3638
3639 dsp_ptr[num_entries-1].next = NULL;
3640 *pnEntries = num_entries;
3641
3642 return dsp_ptr;
3643 }
3644
3645 static
EditIniSectionStrings(psz_title,dsp_ptr,entries,num_entries,pf_after_loop)3646 int EditIniSectionStrings(psz_title, dsp_ptr, entries, num_entries,
3647 pf_after_loop)
3648 char *psz_title, **entries;
3649 DspList *dsp_ptr;
3650 int num_entries;
3651 AfterLoopFunc *pf_after_loop;
3652 {
3653 char win_name[128];
3654
3655 sprintf(win_name, TgLoadString(STID_TOOL_EDIT_INI_SECTION), TOOL_NAME);
3656 ResetNamesInfo();
3657 NamesSetTitle(psz_title);
3658 NamesAddButton(TgLoadCachedString(CSTID_OK), BUTTON_OK);
3659 NamesAddButton(TgLoadCachedString(CSTID_CANCEL), BUTTON_CANCEL);
3660 /* ignore double-click and <CR> */
3661 NamesSetDefaultBtnId(BUTTON_OK, INVALID);
3662 NamesSetStyle(NAMES_EDIT_ATTR, NAMES_LOOP_MANY);
3663 NamesSetCallback(NULL, pf_after_loop, NULL);
3664 NamesSetEntries(dsp_ptr, entries, num_entries, NULL, TRUE, INVALID, 0);
3665 return (Names(win_name, NULL, NULL, 0, NULL)==BUTTON_OK);
3666 }
3667
3668 static
DefEditIniSectionCheck(psz_key,psz_value)3669 int DefEditIniSectionCheck(psz_key, psz_value)
3670 char *psz_key, *psz_value;
3671 {
3672 return TRUE;
3673 }
3674
3675 static
EditIniSectionDefAfterLoop(pp_dsp_ptr,ppsz_entries,pn_num_entries,pn_marked_index,pp_check_array,cur_buf,btn_id,selected_index,p_void)3676 int EditIniSectionDefAfterLoop(pp_dsp_ptr, ppsz_entries, pn_num_entries,
3677 pn_marked_index, pp_check_array, cur_buf, btn_id, selected_index, p_void)
3678 DspList **pp_dsp_ptr;
3679 char ***ppsz_entries, *cur_buf;
3680 int *pn_num_entries, *pn_marked_index, btn_id, selected_index;
3681 struct CheckArrayRec **pp_check_array;
3682 void *p_void;
3683 /*
3684 * Returns FALSE if the content of the dialogbox is acceptable and
3685 * the dialogbox will be closed.
3686 * Returns TRUE to tell the dialogbox to continue to loop. In this case,
3687 * this function should call MsgBox() to let the user know why
3688 * the dialogbox is not closed.
3689 */
3690 {
3691 int i=0, num_entries=(*pn_num_entries);
3692
3693 if (btn_id == BUTTON_CANCEL) {
3694 return FALSE;
3695 }
3696 for (i=0; i < num_entries; i++) {
3697 char *psz_key=(*ppsz_entries)[i], *psz_value=NULL;
3698 char *psz=strchr(psz_key, '=');
3699
3700 *psz = '\0';
3701 psz_value = (&psz[1]);
3702 if (!DefEditIniSectionCheck(psz_key, psz_value)) {
3703 /* psz_value is not an acceptable value for psz_key */
3704 sprintf(gszMsgBox, TgLoadString(STID_BAD_VALUE_FOR_KEY), psz_key,
3705 psz_value);
3706 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3707 *psz = '=';
3708 return TRUE;
3709 }
3710 *psz = '=';
3711 }
3712 /* everything is fine */
3713 return FALSE;
3714 }
3715
EditIniSection(pszTitle,pszSection,pszIniFile,pf_after_loop)3716 int EditIniSection(pszTitle, pszSection, pszIniFile, pf_after_loop)
3717 char *pszTitle, *pszSection, *pszIniFile;
3718 AfterLoopFunc *pf_after_loop;
3719 {
3720 int num_entries=0, ok_pressed=FALSE;
3721 DspList *dsp_ptr=NULL;
3722 char sz_title[MAXSTRING], **entries=NULL;
3723
3724 dsp_ptr = IniSectionListing(pszSection, pszIniFile, &num_entries);
3725 if (dsp_ptr == NULL) {
3726 sprintf(gszMsgBox, TgLoadString(STID_NOTHING_TO_EDIT_SEC_EMPTY),
3727 pszSection, pszIniFile);
3728 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3729 return FALSE;
3730 }
3731 MakeQuiescent();
3732
3733 ignoreDirectoryFlag = TRUE;
3734 entries = MakeNameDspItemArray(num_entries, dsp_ptr);
3735 ignoreDirectoryFlag = FALSE;
3736 if (pszTitle == NULL) {
3737 sprintf(sz_title, TgLoadString(STID_EDIT_VALUES_FOR_DOTS), pszSection);
3738 } else {
3739 UtilStrCpyN(sz_title, sizeof(sz_title), pszTitle);
3740 }
3741 if (pf_after_loop == NULL) {
3742 pf_after_loop = (AfterLoopFunc*)EditIniSectionDefAfterLoop;
3743 }
3744 if (EditIniSectionStrings(sz_title, dsp_ptr, entries, num_entries,
3745 pf_after_loop)) {
3746 int i=0;
3747
3748 tgWriteProfileString(pszSection, NULL, NULL, pszIniFile);
3749 for (i=0; i < num_entries; i++) {
3750 char *psz=strchr(entries[i], '=');
3751
3752 *psz++ = '\0';
3753 tgWriteProfileString(pszSection, entries[i], psz, pszIniFile);
3754 }
3755 tgWriteProfileString(NULL, NULL, NULL, pszIniFile);
3756 ok_pressed = TRUE;
3757 }
3758 free(dsp_ptr);
3759 free(*entries);
3760 free(entries);
3761
3762 SetCurChoice(curChoiceBeforeMakeQuiescent);
3763
3764 return ok_pressed;
3765 }
3766
3767 static
IniSectionKeysListing(pszSection,pszIniFile,pnEntries)3768 DspList *IniSectionKeysListing(pszSection, pszIniFile, pnEntries)
3769 char *pszSection, *pszIniFile;
3770 int *pnEntries;
3771 {
3772 DspList *dsp_ptr=NULL;
3773 char *pszKeys=NULL;
3774 int num_entries=0;
3775
3776 *pnEntries = 0;
3777 if ((pszKeys=tgGetProfileString(pszSection, NULL, pszIniFile)) != NULL) {
3778 DspList *pdl=NULL;
3779 char *pszKey=NULL;
3780
3781 for (pszKey=pszKeys; *pszKey != '\0'; pszKey++) {
3782 num_entries++;
3783 pszKey += strlen(pszKey);
3784 }
3785 dsp_ptr = (DspList*)malloc(num_entries*sizeof(DspList));
3786 if (dsp_ptr == NULL) FailAllocMessage();
3787 memset(dsp_ptr, 0, num_entries*sizeof(DspList));
3788 for (pszKey=pszKeys, pdl=dsp_ptr; *pszKey != '\0'; pszKey++, pdl++) {
3789 UtilStrCpyN(pdl->itemstr, sizeof(pdl->itemstr), pszKey);
3790 /* use the directory field for inherited */
3791 pdl->next = (&pdl[1]);
3792
3793 pszKey += strlen(pszKey);
3794 }
3795 tgFreeProfileString(pszKeys);
3796 }
3797 if (num_entries == 0) return NULL;
3798
3799 dsp_ptr[num_entries-1].next = NULL;
3800 *pnEntries = num_entries;
3801
3802 return dsp_ptr;
3803 }
3804
3805 static
SelectFromIniSectionStrings(psz_title,dsp_ptr,entries,num_entries,selected_str,selected_str_sz)3806 int SelectFromIniSectionStrings(psz_title, dsp_ptr, entries, num_entries,
3807 selected_str, selected_str_sz)
3808 char *psz_title, **entries, *selected_str;
3809 DspList *dsp_ptr;
3810 int num_entries, selected_str_sz;
3811 {
3812 char win_name[128];
3813
3814 sprintf(win_name, TgLoadString(STID_TOOL_SEL_FROM_INI_SECTION), TOOL_NAME);
3815 ResetNamesInfo();
3816 NamesSetTitle(psz_title);
3817 NamesAddButton(TgLoadCachedString(CSTID_OK), BUTTON_OK);
3818 NamesAddButton(TgLoadCachedString(CSTID_CANCEL), BUTTON_CANCEL);
3819 /* ignore double-click and <CR> */
3820 NamesSetDefaultBtnId(BUTTON_OK, BUTTON_OK);
3821 NamesSetStyle(NAMES_SIMPLE_SELECT_NAME, NAMES_LOOP_ONCE);
3822 NamesSetEntries(dsp_ptr, entries, num_entries, NULL, TRUE, INVALID, 0);
3823 return (Names(win_name, NULL, selected_str, selected_str_sz,
3824 NULL)==BUTTON_OK);
3825 }
3826
SelectFromIniSection(pszTitle,pszSection,pszIniFile)3827 char *SelectFromIniSection(pszTitle, pszSection, pszIniFile)
3828 char *pszTitle, *pszSection, *pszIniFile;
3829 {
3830 int num_entries=0;
3831 DspList *dsp_ptr=NULL;
3832 char sz_title[MAXSTRING], **entries=NULL, selected_str[MAXSTRING];
3833
3834 MakeQuiescent();
3835
3836 dsp_ptr = IniSectionKeysListing(pszSection, pszIniFile, &num_entries);
3837 if (dsp_ptr == NULL) {
3838 sprintf(gszMsgBox, TgLoadString(STID_NOTHING_TO_SEL_SEC_EMPTY),
3839 pszSection, pszIniFile);
3840 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
3841 return FALSE;
3842 }
3843 ignoreDirectoryFlag = TRUE;
3844 entries = MakeNameDspItemArray(num_entries, dsp_ptr);
3845 ignoreDirectoryFlag = FALSE;
3846 if (pszTitle == NULL) {
3847 sprintf(sz_title, TgLoadString(STID_SELECT_A_VALUE_FROM_SEC_DOTS),
3848 pszSection);
3849 } else {
3850 UtilStrCpyN(sz_title, sizeof(sz_title), pszTitle);
3851 }
3852 *selected_str = '\0';
3853 if (!SelectFromIniSectionStrings(sz_title, dsp_ptr, entries, num_entries,
3854 selected_str, sizeof(selected_str))) {
3855 *selected_str = '\0';
3856 }
3857 free(dsp_ptr);
3858 free(*entries);
3859 free(entries);
3860
3861 return (*selected_str=='\0' ? NULL : UtilStrDup(selected_str));
3862 }
3863
3864 /* ----------------------- Recently Used Files ----------------------- */
3865
3866 static int maxRecentFiles=10;
3867
FreeRecentFilesListing(pkvi,max_count)3868 void FreeRecentFilesListing(pkvi, max_count)
3869 KeyValInfo *pkvi;
3870 int max_count;
3871 {
3872 if (pkvi != NULL) {
3873 int i=0;
3874
3875 for (i=0; i < max_count; i++) {
3876 UtilFree(pkvi[i].key);
3877 UtilFree(pkvi[i].value);
3878 }
3879 free(pkvi);
3880 }
3881 }
3882
RecentFilesListing(pnEntries)3883 KeyValInfo *RecentFilesListing(pnEntries)
3884 int *pnEntries;
3885 /*
3886 * key will store the file name
3887 * value will store the full path
3888 */
3889 {
3890 int i=0, count=0, real_count=0, fix_up=FALSE;
3891 char *buf=NULL;
3892 KeyValInfo *pkvi=NULL;
3893
3894 *pnEntries = 0;
3895 if ((buf=tgGetProfileString(gpszRecentFilesSec, gpszRecentFilesCountKey,
3896 gszFilesIniFile)) == NULL) {
3897 return NULL;
3898 }
3899 count = atoi(buf);
3900 tgFreeProfileString(buf);
3901 pkvi = (KeyValInfo*)malloc(count*sizeof(KeyValInfo));
3902 if (pkvi == NULL) FailAllocMessage();
3903 memset(pkvi, 0, count*sizeof(KeyValInfo));
3904 for (i=0; i < count; i++) {
3905 char sz_key[40], *psz=NULL;
3906
3907 sprintf(sz_key, "%1d", i);
3908 buf = tgGetProfileString(gpszRecentFilesSec, sz_key, gszFilesIniFile);
3909 /* just in case the ini file is corrupted */
3910 if (buf == NULL) {
3911 fix_up = TRUE;
3912 continue;
3913 }
3914 psz = UtilStrRChr(buf, DIR_SEP);
3915 if (psz != NULL) {
3916 *psz = '\0';
3917 pkvi[real_count].key = UtilStrDup(&psz[1]);
3918 if (pkvi[real_count].key == NULL) FailAllocMessage();
3919 *psz = DIR_SEP;
3920 } else {
3921 pkvi[real_count].key = UtilStrDup(buf);
3922 if (pkvi[real_count].key == NULL) FailAllocMessage();
3923 }
3924 pkvi[real_count].value = UtilStrDup(buf);
3925 if (pkvi[real_count].value == NULL) FailAllocMessage();
3926 if (fix_up) {
3927 tgWriteProfileString(gpszRecentFilesSec, sz_key, buf, gszFilesIniFile);
3928 }
3929 tgFreeProfileString(buf);
3930 real_count++;
3931 }
3932 if (fix_up) {
3933 sprintf(gszMsgBox, "%1d", real_count);
3934 tgWriteProfileString(gpszRecentFilesSec, gpszRecentFilesCountKey,
3935 gszMsgBox, gszFilesIniFile);
3936 tgWriteProfileString(NULL, NULL, NULL, gszFilesIniFile);
3937 }
3938 if (real_count == 0) {
3939 FreeRecentFilesListing(pkvi, count);
3940 pkvi = NULL;
3941 }
3942 *pnEntries = real_count;
3943
3944 return pkvi;
3945 }
3946
OpenARecentlyUsedFile(file_index)3947 void OpenARecentlyUsedFile(file_index)
3948 int file_index;
3949 {
3950 int count=0, do_not_save=FALSE, need_to_check_auto_exec=FALSE;
3951 KeyValInfo *pkvi=RecentFilesListing(&count);
3952 char *psz_url=NULL;
3953
3954 if (pkvi == NULL || count == 0 || file_index >= count) return;
3955
3956 psz_url = pkvi[file_index].value;
3957
3958 if (!BeforeOpenURL(&do_not_save)) {
3959 return;
3960 }
3961 OpenURL(psz_url, do_not_save, &need_to_check_auto_exec);
3962 FreeRecentFilesListing(pkvi, count);
3963 AfterOpenURL(need_to_check_auto_exec);
3964 }
3965
AddARecentlyUsedFile(path)3966 void AddARecentlyUsedFile(path)
3967 char *path;
3968 {
3969 int i=0, count=0, move_index=INVALID;
3970 KeyValInfo *pkvi=RecentFilesListing(&count);
3971
3972 if (count == 0) {
3973 /* do not translate -- program constants */
3974 tgWriteProfileString(gpszRecentFilesSec, NULL, NULL, gszFilesIniFile);
3975 tgWriteProfileString(gpszRecentFilesSec, "0", path, gszFilesIniFile);
3976 } else {
3977 char sz_key[40];
3978
3979 for (i=0; i < count; i++) {
3980 if (strcmp(path, pkvi[i].value) == 0) {
3981 if (i == 0) {
3982 FreeRecentFilesListing(pkvi, count);
3983 return;
3984 }
3985 move_index = i;
3986 break;
3987 }
3988 }
3989 tgWriteProfileString(gpszRecentFilesSec, NULL, NULL, gszFilesIniFile);
3990 if (move_index == INVALID) {
3991 if (count+1 > maxRecentFiles) {
3992 count = maxRecentFiles-1;
3993 }
3994 for (i=0; i < count+1; i++) {
3995 sprintf(sz_key, "%1d", i);
3996 if (i == 0) {
3997 tgWriteProfileString(gpszRecentFilesSec, sz_key, path,
3998 gszFilesIniFile);
3999 } else {
4000 tgWriteProfileString(gpszRecentFilesSec, sz_key, pkvi[i-1].value,
4001 gszFilesIniFile);
4002 }
4003 }
4004 } else {
4005 if (count > maxRecentFiles) {
4006 count = maxRecentFiles;
4007 }
4008 for (i=0; i < count; i++) {
4009 sprintf(sz_key, "%1d", i);
4010 if (i == 0) {
4011 tgWriteProfileString(gpszRecentFilesSec, sz_key,
4012 pkvi[move_index].value, gszFilesIniFile);
4013 } else if (i <= move_index) {
4014 tgWriteProfileString(gpszRecentFilesSec, sz_key, pkvi[i-1].value,
4015 gszFilesIniFile);
4016 } else {
4017 tgWriteProfileString(gpszRecentFilesSec, sz_key, pkvi[i].value,
4018 gszFilesIniFile);
4019 }
4020 }
4021 }
4022 }
4023 sprintf(gszMsgBox, "%1d", (move_index==INVALID ? count+1 : count));
4024 tgWriteProfileString(gpszRecentFilesSec, gpszRecentFilesCountKey,
4025 gszMsgBox, gszFilesIniFile);
4026 tgWriteProfileString(NULL, NULL, NULL, gszFilesIniFile);
4027 FreeRecentFilesListing(pkvi, count);
4028 }
4029
InitRecentFiles()4030 int InitRecentFiles()
4031 {
4032 char *c_ptr=NULL;
4033
4034 if (PRTGIF) return TRUE;
4035
4036 /* do not translate -- program constants */
4037 sprintf(gszFilesIniFile, "%s%cfiles.ini", tgifDir, DIR_SEP);
4038
4039 maxRecentFiles = 10;
4040 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"MaxRecentFiles")) != NULL) {
4041 maxRecentFiles = atoi(c_ptr);
4042 if (maxRecentFiles <= 0 || maxRecentFiles > 99) {
4043 sprintf(gszMsgBox, TgLoadString(STID_INVALID_XDEF_RNG_USE_ALT_VAL),
4044 TOOL_NAME, "MaxRecentFiles", c_ptr, 1, 99, 10);
4045 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4046 maxRecentFiles = 10;
4047 }
4048 }
4049 if ((c_ptr=tgGetProfileString(gpszRecentFilesSec, gpszRecentFilesCountKey,
4050 gszFilesIniFile)) != NULL) {
4051 int count = atoi(c_ptr);
4052
4053 if (count > maxRecentFiles) {
4054 sprintf(gszMsgBox, "%1d", maxRecentFiles);
4055 tgWriteProfileString(gpszRecentFilesSec, gpszRecentFilesCountKey,
4056 gszMsgBox, gszFilesIniFile);
4057 tgWriteProfileString(NULL, NULL, NULL, gszFilesIniFile);
4058 }
4059 tgFreeProfileString(c_ptr);
4060 }
4061 return TRUE;
4062 }
4063
CleanUpRecentFiles()4064 void CleanUpRecentFiles()
4065 {
4066 }
4067
4068 /* ----------------------- SimpleString Object ----------------------- */
4069
CreateSimpleStringObj(buf)4070 int CreateSimpleStringObj(buf)
4071 char *buf;
4072 {
4073 SimpleString *ss_ptr=NULL;
4074 struct ObjRec *obj_ptr=NULL;
4075
4076 ss_ptr = (SimpleString *)malloc(sizeof(SimpleString));
4077 if (ss_ptr == NULL) FailAllocMessage();
4078 memset(ss_ptr, 0, sizeof(SimpleString));
4079
4080 DynStrSet(&ss_ptr->dyn_str, buf);
4081
4082 obj_ptr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
4083 if (obj_ptr == NULL) FailAllocMessage();
4084 memset(obj_ptr, 0, sizeof(struct ObjRec));
4085
4086 obj_ptr->type = OBJ_SS;
4087 obj_ptr->color = colorIndex;
4088 if (mainDisplay != NULL) {
4089 UtilStrCpyN(obj_ptr->color_str, sizeof(obj_ptr->color_str),
4090 colorMenuItems[colorIndex]);
4091 }
4092 obj_ptr->id = objId++;
4093 obj_ptr->detail.ss = ss_ptr;
4094 /*
4095 * the double-byte stuff is left alone, always single byte for now
4096 */
4097
4098 AddObj(NULL, topObj, obj_ptr);
4099
4100 return TRUE;
4101 }
4102
SaveSimpleStringObj(FP,ObjPtr)4103 void SaveSimpleStringObj(FP, ObjPtr)
4104 FILE *FP;
4105 struct ObjRec *ObjPtr;
4106 {
4107 SimpleString *ss_ptr=ObjPtr->detail.ss;
4108
4109 if (fprintf(FP, "simple_string('%s',%1d,%1d,%1d,%1d,\n\t\"",
4110 colorMenuItems[ObjPtr->color], ObjPtr->id, ss_ptr->double_byte,
4111 ss_ptr->double_byte_mod_bytes, ss_ptr->double_byte_vertical) == EOF) {
4112 writeFileFailed = TRUE;
4113 }
4114 if (ss_ptr->double_byte) {
4115 SaveDoubleByteString(FP, ss_ptr->dyn_str.s);
4116 } else {
4117 SaveString(FP, ss_ptr->dyn_str.s);
4118 }
4119 if (fprintf(FP, "\")") == EOF) writeFileFailed = TRUE;
4120 }
4121
ReadSimpleStringObj(FP,Inbuf,ObjPtr)4122 void ReadSimpleStringObj(FP, Inbuf, ObjPtr)
4123 FILE *FP;
4124 char *Inbuf;
4125 struct ObjRec **ObjPtr;
4126 {
4127 SimpleString *ss_ptr=NULL;
4128 char *psz=NULL, *s=NULL, color_str[40], *line=NULL;
4129 int id=0, double_byte=FALSE, db_mod_bytes=FALSE, db_vertical=FALSE;
4130 int new_alloc=FALSE;
4131
4132 *ObjPtr = NULL;
4133
4134 s = FindChar((int)'(', Inbuf);
4135 s = ParseStr(s, (int)',', color_str, sizeof(color_str));
4136 InitScan(s, "\t\n, ");
4137
4138 if (GETINT("simple_string", id, "id") == INVALID ||
4139 GETINT("simple_string", double_byte, "double_byte") == INVALID ||
4140 GETINT("simple_string", db_mod_bytes, "db_mod_bytes") == INVALID ||
4141 GETINT("simple_string", db_vertical, "db_vertical") == INVALID) {
4142 return;
4143 }
4144 if (id >= objId) objId = id+1;
4145
4146 if ((line=UtilGetALine(FP)) == NULL) {
4147 sprintf(gszMsgBox, TgLoadString(STID_UNEXPECTED_EOF_IN_ABORT_READ),
4148 scanFileName, scanLineNum, "ReadSimpleStringObj()");
4149 if (PRTGIF) {
4150 fprintf(stderr, "%s\n", gszMsgBox);
4151 } else {
4152 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4153 }
4154 return;
4155 }
4156 scanLineNum++;
4157
4158 psz = FindChar((int)'"', line);
4159 s = ReadString(psz);
4160 *(--s) = '\0';
4161
4162 *ObjPtr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
4163 if (*ObjPtr == NULL) FailAllocMessage();
4164 memset(*ObjPtr, 0, sizeof(struct ObjRec));
4165 ss_ptr = (SimpleString *)malloc(sizeof(SimpleString));
4166 if (ss_ptr == NULL) FailAllocMessage();
4167 memset(ss_ptr, 0, sizeof(SimpleString));
4168
4169 DynStrSet(&ss_ptr->dyn_str, psz);
4170 free(line);
4171
4172 ss_ptr->double_byte = double_byte;
4173 ss_ptr->double_byte_mod_bytes = db_mod_bytes;
4174 ss_ptr->double_byte_vertical = db_vertical;
4175
4176 (*ObjPtr)->color = QuickFindColorIndex(*ObjPtr, color_str, &new_alloc, TRUE);
4177 UtilStrCpyN((*ObjPtr)->color_str, sizeof((*ObjPtr)->color_str), color_str);
4178 (*ObjPtr)->id = id;
4179 }
4180
FreeSimpleStringObj(ObjPtr)4181 void FreeSimpleStringObj(ObjPtr)
4182 struct ObjRec *ObjPtr;
4183 {
4184 UtilFree(ObjPtr->detail.ss->dyn_str.s);
4185 free(ObjPtr->detail.ss);
4186 free(ObjPtr);
4187 }
4188
4189 /* ----------------------- ReplaceGraphic() ----------------------- */
4190
4191 static
UnInheritAllAttrs(obj_ptr)4192 void UnInheritAllAttrs(obj_ptr)
4193 struct ObjRec *obj_ptr;
4194 {
4195 struct AttrRec *attr_ptr;
4196
4197 for (attr_ptr=obj_ptr->fattr; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
4198 if (attr_ptr->inherited) {
4199 attr_ptr->inherited = FALSE;
4200 }
4201 }
4202 }
4203
ReplaceGraphic()4204 void ReplaceGraphic()
4205 {
4206 struct SelRec *saved_top_sel=NULL, *saved_bot_sel=NULL, *sel_ptr=NULL;
4207 struct SelRec *prev_sel=NULL;
4208 struct ObjRec *pasted_top_obj=NULL, *pasted_bot_obj=NULL;
4209 struct ObjRec *icon_obj_to_replace=NULL;
4210 char *orig_cut_buffer=NULL;
4211 int sel_ltx=selLtX, sel_lty=selLtY, sel_rbx=selRbX, sel_rby=selRbY;
4212 int len=0, changed=FALSE, icons_converted_to_groups=FALSE, icon_count=0;
4213 int from_selection=FALSE;
4214
4215 if (topSel == NULL) {
4216 MsgBox(TgLoadCachedString(CSTID_NO_OBJ_SELECTED), TOOL_NAME, INFO_MB);
4217 return;
4218 }
4219 for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=sel_ptr->prev) {
4220 if (sel_ptr->obj->type == OBJ_ICON) {
4221 icon_obj_to_replace = sel_ptr->obj;
4222 icon_count++;
4223 }
4224 }
4225 if (icon_count > 1) {
4226 MsgBox(TgLoadString(STID_TOO_MANY_ICON_REPLACE_GRAPHIC), TOOL_NAME,
4227 INFO_MB);
4228 return;
4229 }
4230 orig_cut_buffer = FetchSelectionOrCutBuffer(&len, &from_selection);
4231 if (orig_cut_buffer == NULL) {
4232 MsgBox(TgLoadString(STID_CUT_BUFFER_EMPTY), TOOL_NAME, INFO_MB);
4233 return;
4234 }
4235 if (CutBufferType(orig_cut_buffer) != CBF_TGIF_OBJ) {
4236 sprintf(gszMsgBox, TgLoadString(STID_CANT_REPLACE_GRAPHIC_NOT_TGIF),
4237 TOOL_NAME);
4238 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4239 return;
4240 }
4241 HighLightReverse();
4242 saved_top_sel = topSel;
4243 saved_bot_sel = botSel;
4244 topSel = botSel = NULL;
4245 UpdSelBBox();
4246
4247 if (!GetObjsFromCutBuffer(&orig_cut_buffer[1], len-1, &pasted_top_obj,
4248 &pasted_bot_obj)) {
4249 FreeSelectionOrCutBuffer(orig_cut_buffer, from_selection);
4250 topSel = saved_top_sel;
4251 botSel = saved_bot_sel;
4252 UpdSelBBox();
4253 HighLightForward();
4254 return;
4255 }
4256 FreeSelectionOrCutBuffer(orig_cut_buffer, from_selection);
4257
4258 if (pasted_top_obj == NULL || pasted_top_obj != pasted_bot_obj) {
4259 MsgBox(TgLoadString(STID_CANT_REPLACE_GRAPHIC_TOO_MANY), TOOL_NAME,
4260 INFO_MB);
4261 topSel = saved_top_sel;
4262 botSel = saved_bot_sel;
4263 UpdSelBBox();
4264 HighLightForward();
4265 return;
4266 }
4267 if (pasted_top_obj->type == OBJ_SYM || pasted_top_obj->type == OBJ_ICON ||
4268 pasted_top_obj->type == OBJ_PIN) {
4269 pasted_top_obj->type = OBJ_GROUP;
4270 }
4271 DelAllAttrs(pasted_top_obj->fattr);
4272
4273 topSel = saved_top_sel;
4274 botSel = saved_bot_sel;
4275 UpdSelBBox();
4276
4277 StartCompositeCmd();
4278 for (sel_ptr=botSel; sel_ptr != NULL; sel_ptr=prev_sel) {
4279 struct ObjRec *obj_ptr=sel_ptr->obj, *new_obj_ptr=NULL;
4280 int convert_to_group=TRUE;
4281
4282 prev_sel = sel_ptr->prev;
4283 if (obj_ptr->type == OBJ_TEXT) continue;
4284
4285 if (obj_ptr->type == OBJ_ICON && obj_ptr == icon_obj_to_replace) {
4286 switch (MsgBox(TgLoadString(STID_Q_CVT_ICON_TO_GRP_IN_REPLACE),
4287 TOOL_NAME, YNC_MB)) {
4288 case MB_ID_YES: break;
4289 case MB_ID_NO: convert_to_group = FALSE; break;
4290 case MB_ID_CANCEL: continue;
4291 }
4292 }
4293 changed = TRUE;
4294
4295 PrepareToReplaceAnObj(obj_ptr);
4296
4297 new_obj_ptr = DupObj(pasted_top_obj);
4298 MoveObj(new_obj_ptr, obj_ptr->obbox.ltx-new_obj_ptr->obbox.ltx,
4299 obj_ptr->obbox.lty-new_obj_ptr->obbox.lty);
4300
4301 new_obj_ptr->prev = obj_ptr->prev;
4302 new_obj_ptr->next = obj_ptr->next;
4303 new_obj_ptr->fattr = obj_ptr->fattr;
4304 new_obj_ptr->lattr = obj_ptr->lattr;
4305
4306 obj_ptr->fattr = obj_ptr->lattr = NULL;
4307 UnlinkObj(obj_ptr);
4308
4309 if (obj_ptr->type == OBJ_SYM) new_obj_ptr->type = OBJ_SYM;
4310
4311 UpdAttrOwner(new_obj_ptr->fattr, new_obj_ptr);
4312 if (new_obj_ptr->prev == NULL) {
4313 curPage->top = topObj = new_obj_ptr;
4314 } else {
4315 new_obj_ptr->prev->next = new_obj_ptr;
4316 }
4317 if (new_obj_ptr->next == NULL) {
4318 curPage->bot = botObj = new_obj_ptr;
4319 } else {
4320 new_obj_ptr->next->prev = new_obj_ptr;
4321 }
4322 AdjObjBBox(new_obj_ptr);
4323 ExpandCurSelBBoxes(new_obj_ptr);
4324
4325 sel_ptr->obj = new_obj_ptr;
4326 if (convert_to_group) {
4327 icons_converted_to_groups = TRUE;
4328 UnInheritAllAttrs(new_obj_ptr);
4329 } else {
4330 struct SelRec *tmp_sel=NULL;
4331
4332 saved_top_sel = topSel;
4333 saved_bot_sel = botSel;
4334 topSel = botSel = tmp_sel = SelectThisObject(new_obj_ptr);
4335 UpdSelBBox();
4336 MakeIconic(NULL, FALSE);
4337 topSel = saved_top_sel;
4338 botSel = saved_bot_sel;
4339 UpdSelBBox();
4340 free(tmp_sel);
4341 }
4342 RecordReplaceAnObj(new_obj_ptr);
4343 FreeObj(obj_ptr);
4344 }
4345 EndCompositeCmd();
4346
4347 if (changed) {
4348 UpdSelBBox();
4349 RedrawAreas(botObj, sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1),
4350 sel_rbx+GRID_ABS_SIZE(1), sel_rby+GRID_ABS_SIZE(1),
4351 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
4352 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
4353 SetFileModified(TRUE);
4354 justDupped = FALSE;
4355 if (icons_converted_to_groups) {
4356 MsgBox(TgLoadString(STID_REPLACE_GRAPHIC_ICON_TO_GROUP), TOOL_NAME,
4357 INFO_MB);
4358 } else {
4359 Msg(TgLoadString(STID_REPLACE_GRAPHIC_DONE));
4360 }
4361 }
4362 HighLightForward();
4363 }
4364
4365 /* ----------------------- ReplaceGraphic() ----------------------- */
4366
4367 static int wordWrapDuringImportTextFile=FALSE;
4368
4369 #ifndef A4PAPER
4370 static int topMarginForImportTextFile=HALF_INCH;
4371 static int leftMarginForImportTextFile=HALF_INCH;
4372 static int rightMarginForImportTextFile=HALF_INCH;
4373 static int bottomMarginForImportTextFile=HALF_INCH;
4374 #else /* A4PAPER */
4375 static int topMarginForImportTextFile=ONE_CM;
4376 static int leftMarginForImportTextFile=ONE_CM;
4377 static int rightMarginForImportTextFile=ONE_CM;
4378 static int bottomMarginForImportTextFile=ONE_CM;
4379 #endif /* A4PAPER */
4380
4381 static
DoSetMarginsForImportMultipageTextFile(spec)4382 int DoSetMarginsForImportMultipageTextFile(spec)
4383 char *spec;
4384 {
4385 int top=0, bottom=0, left=0, right=0;
4386 char *top_str=NULL, *bottom_str=NULL, *left_str=NULL, *right_str=NULL;
4387
4388 UtilTrimBlanks(spec);
4389 top_str = strtok(spec, ",\t\n\r");
4390 if (top_str == NULL) return FALSE;
4391 bottom_str = strtok(NULL, ",\t\n\r");
4392 if (bottom_str == NULL) return FALSE;
4393 left_str = strtok(NULL, ",\t\n\r");
4394 if (left_str == NULL) return FALSE;
4395 right_str = strtok(NULL, ",\t\n\r");
4396 if (right_str == NULL) return FALSE;
4397
4398 if (GetDimension(top_str, FALSE, &top) &&
4399 GetDimension(bottom_str, FALSE, &bottom) &&
4400 GetDimension(left_str, FALSE, &left) &&
4401 GetDimension(right_str, FALSE, &right)) {
4402 topMarginForImportTextFile = top;
4403 bottomMarginForImportTextFile = bottom;
4404 leftMarginForImportTextFile = left;
4405 rightMarginForImportTextFile = right;
4406
4407 return TRUE;
4408 }
4409 return FALSE;
4410 }
4411
4412 static
GetCurMarginsForImportTextFile(buf)4413 void GetCurMarginsForImportTextFile(buf)
4414 char *buf;
4415 {
4416 char n_str[MAXSTRING], s_str[MAXSTRING], w_str[MAXSTRING], e_str[MAXSTRING];
4417 float n=((float)topMarginForImportTextFile)*printMag/((float)100.0);
4418 float s=((float)bottomMarginForImportTextFile)*printMag/((float)100.0);
4419 float w=((float)leftMarginForImportTextFile)*printMag/((float)100.0);
4420 float e=((float)rightMarginForImportTextFile)*printMag/((float)100.0);
4421 float n_val=(float)0.0, s_val=(float)0.0, w_val=(float)0.0, e_val=(float)0.0;
4422 float unit=(float)0.0;
4423
4424 switch (gridSystem) {
4425 case ENGLISH_GRID:
4426 unit = (float)PIX_PER_INCH;
4427
4428 n_val = n / unit;
4429 s_val = s / unit;
4430 w_val = w / unit;
4431 e_val = e / unit;
4432 FormatFloat(&n_val, n_str);
4433 FormatFloat(&s_val, s_str);
4434 FormatFloat(&w_val, w_str);
4435 FormatFloat(&e_val, e_str);
4436 /* do not translate -- program constants */
4437 sprintf(buf, "[ %s in, %s in, %s in, %s in ]",
4438 n_str, s_str, w_str, e_str);
4439 break;
4440 case METRIC_GRID:
4441 unit = (float)ONE_CM;
4442
4443 n_val = n / unit;
4444 s_val = s / unit;
4445 w_val = w / unit;
4446 e_val = e / unit;
4447 FormatFloat(&n_val, n_str);
4448 FormatFloat(&s_val, s_str);
4449 FormatFloat(&w_val, w_str);
4450 FormatFloat(&e_val, e_str);
4451 /* do not translate -- program constants */
4452 sprintf(buf, "[ %s cm, %s cm, %s cm, %s cm ]",
4453 n_str, s_str, w_str, e_str);
4454 break;
4455 }
4456 }
4457
ImportMultipageTextFile()4458 void ImportMultipageTextFile()
4459 {
4460 }
4461
SetMarginsForImportMultipageTextFile()4462 void SetMarginsForImportMultipageTextFile()
4463 {
4464 char buf[MAXSTRING<<1], spec[MAXSTRING+1], spec_copy[MAXSTRING+1];
4465
4466 GetCurMarginsForImportTextFile(gszMsgBox);
4467 sprintf(buf, TgLoadString(STID_CUR_MARGINS_ARE_GIVEN), gszMsgBox);
4468 *spec = '\0';
4469 switch (gridSystem) {
4470 case ENGLISH_GRID:
4471 sprintf(gszMsgBox, TgLoadString(STID_ENTER_MARGINS),
4472 "0.5in,0.5in,0.5in,0.5in");
4473 break;
4474 case METRIC_GRID:
4475 sprintf(gszMsgBox, TgLoadString(STID_ENTER_MARGINS),
4476 "1cm,1cm,1cm,1cm");
4477 break;
4478 }
4479 if (Dialog(gszMsgBox, buf, spec) == INVALID) {
4480 return;
4481 }
4482 UtilStrCpyN(spec_copy, sizeof(spec_copy), spec);
4483
4484 if (!DoSetMarginsForImportMultipageTextFile(spec_copy)) {
4485 sprintf(gszMsgBox, TgLoadString(STID_FAIL_TO_PARSE_FOR_4_VAL), spec);
4486 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
4487 } else {
4488 char buf[MAXSTRING<<1];
4489
4490 strcpy(buf, " ");
4491 GetCurMarginsForImportTextFile(&buf[4]);
4492 TwoLineMsg(TgLoadString(STID_NEW_MARGINS_ARE_GIVEN), buf);
4493 }
4494 }
4495
ToggleWordWrapDuringImportMultipageTextFile()4496 void ToggleWordWrapDuringImportMultipageTextFile()
4497 {
4498 wordWrapDuringImportTextFile = !wordWrapDuringImportTextFile;
4499 sprintf(gszMsgBox, TgLoadString(wordWrapDuringImportTextFile ?
4500 STID_WILL_USE_WORDWRAP_IMPORT_TEXT : STID_NO_WORDWRAP_IMPORT_TEXT),
4501 TOOL_NAME);
4502 Msg(gszMsgBox);
4503 }
4504
RefreshImportMutipageTextFileMenu(menu)4505 int RefreshImportMutipageTextFileMenu(menu)
4506 TgMenu *menu;
4507 {
4508 int ok=TRUE;
4509
4510 /* Word Wrap */
4511 ok &= TgSetMenuItemCheckById(menu, CMDID_TOGGLEWORDWRAPONIMPORTTEXT,
4512 wordWrapDuringImportTextFile);
4513
4514 /*
4515 * Well, don't know how to do all these yet. Just disable them for now.
4516 */
4517 ok &= TgEnableMenuItemById(menu, CMDID_IMPORTMULTIPAGETEXTFILE, FALSE);
4518 ok &= TgEnableMenuItemById(menu, CMDID_SETMARGINSONIMPORTTEXT, FALSE);
4519 ok &= TgEnableMenuItemById(menu, CMDID_TOGGLEWORDWRAPONIMPORTTEXT, FALSE);
4520
4521 return ok;
4522 }
4523
CreateImportMutipageTextFileMenu(parent_menu,x,y,menu_info,status_str_xlated)4524 TgMenu *CreateImportMutipageTextFileMenu(parent_menu, x, y, menu_info,
4525 status_str_xlated)
4526 TgMenu *parent_menu;
4527 int x, y;
4528 TgMenuInfo *menu_info;
4529 int status_str_xlated; /* ignored, always 0 */
4530 {
4531 TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE);
4532
4533 if (menu != NULL) {
4534 if (!RefreshImportMutipageTextFileMenu(menu)) {
4535 return TgDestroyMenu(menu, TRUE);
4536 }
4537 menu->refresh_proc =
4538 ((RefreshMenuFunc*)RefreshImportMutipageTextFileMenu);
4539 }
4540 return menu;
4541 }
4542
4543 /* ----------------------- Init and CleanUp ----------------------- */
4544
4545 static
CleanUpCutBufferInfo()4546 void CleanUpCutBufferInfo()
4547 {
4548 ResetCutBufferInfo();
4549 }
4550
CleanUpCutPaste()4551 void CleanUpCutPaste()
4552 {
4553 cutBufferIsTgifObj = FALSE;
4554 cutBufferIsUTF8 = FALSE;
4555 FreeDynStrBuf(&dsCutBuffer);
4556 CleanUpCutBufferInfo();
4557 }
4558
4559 static
ResetXCutBuffers()4560 void ResetXCutBuffers()
4561 {
4562 int i=0;
4563
4564 for (i=0; gaCutBufferAtom[i] != (Atom)0; i++) {
4565 XChangeProperty(mainDisplay, rootWindow, gaCutBufferAtom[i], XA_STRING,
4566 8, PropModeAppend, (unsigned char *)"", 0);
4567 }
4568 }
4569
4570 static
InitCutBufferInfo()4571 void InitCutBufferInfo()
4572 {
4573 memset(&gSetCutBufferInfo, 0, sizeof(SetCutBufferInfo));
4574 }
4575
InitCutPaste()4576 int InitCutPaste()
4577 {
4578 char *c_ptr=NULL;
4579 int ival=0;
4580
4581 InitCutBufferInfo();
4582
4583 pasteFromXSelectionOnly = TRUE;
4584 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"PasteFromXSelectionOnly")) !=
4585 NULL && UtilStrICmp(c_ptr, "false") == 0) {
4586 pasteFromXSelectionOnly = FALSE;
4587 }
4588 pasteFromSelectionTimeout = 10;
4589 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"PasteFromSelectionTimeout")) !=
4590 NULL) {
4591 if (sscanf(c_ptr, "%d", &ival) != 1 || ival < 0) {
4592 fprintf(stderr, TgLoadString(STID_INVALID_XDEF), TOOL_NAME,
4593 "PasteFromSelectionTimeout", c_ptr);
4594 fprintf(stderr, "\n");
4595 } else {
4596 pasteFromSelectionTimeout = ival;
4597 }
4598 }
4599 debugCopyPaste = FALSE;
4600 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"DebugCopyPaste")) != NULL &&
4601 UtilStrICmp(c_ptr, "true") == 0) {
4602 debugCopyPaste = TRUE;
4603 }
4604 memset(&dsCutBuffer, 0, sizeof(dsCutBuffer));
4605 ResetXCutBuffers();
4606
4607 return TRUE;
4608 }
4609