1 /**
2  *  Yudit Unicode Editor Source File
3  *
4  *  GNU Copyright (C) 1997-2006  Gaspar Sinai <gaspar@yudit.org>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License, version 2,
8  *  dated June 1991. See file COPYYING for details.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 
20 #include "gui/SYudit.h"
21 #include "gui/Main.h"
22 #include "stoolkit/SUtil.h"
23 #include "stoolkit/SEncoder.h"
24 #include "stoolkit/SIO.h"
25 #include "stoolkit/STypes.h"
26 #include "stoolkit/SIOStream.h"
27 #include "swidget/SUniPrint.h"
28 #include "swidget/SIconFactory.h"
29 #include <swindow/SPrinter.h>
30 #include <swindow/SScriptProcessor.h>
31 #include <stdlib.h>
32 
33 static SString translateHighlightMode (const SString& hl);
34 static SString getPrintHelp ();
35 static int getLineNumber (const SString& s);
36 
37 #define SGC_DOUBLE_BUFFER  true
38 
39 #define CRYPT_FILE_MATCHER "*.sedy"
40 #define CRYPT_MIN_PASSWORD_SIZE 4
41 
42 #define SYUDIT_AUTO_KEYBOARD true
43 
44 /**
45  * A caret that redraws itself differently for lr and rl text
46  */
SYudit(const SStringVector & args,const SProperties & props,const SString & sedyLib)47 SYudit::SYudit (const SStringVector& args, const SProperties& props, const SString& sedyLib)
48 {
49   passwordDialog = 0;
50   deferredLoader = 0;
51   sedyLibrary = sedyLib;
52   if (sedyLibrary.size()) {
53     cryptFileMatcher = SString(CRYPT_FILE_MATCHER);
54   }
55   // No use to make this main window double buffered
56   // because it almost only redraws its borders and that's it
57 // This is done in SFrame.
58 //  setThisDoubleBuffered (false);
59   SPanel::setAllDoubleBuffered (SGC_DOUBLE_BUFFER);
60   // preparse args
61   unsigned int i;
62   for (i=1; i<args.size(); i++)
63   {
64 //    fprintf (stderr, "SGCARG[%i] %*.*s\n", i, SSARGS(args[i]));
65     if (args[i] == SString("--"))
66     {
67       break;
68     }
69     else if (args[i] == SString("-ndb"))
70     {
71       SPanel::setAllDoubleBuffered (false);
72     }
73     else if (args[i] == SString("-db"))
74     {
75       SPanel::setAllDoubleBuffered (true);
76     }
77   }
78 
79   freeHandShown = false;
80   encrypted = false;
81   freehand = 0;
82   freeHandHeight = 0;
83   setLayout (SLayout (SLocation (0,0), SLocation (3000,2000)));
84   originalProperties = props;
85 
86   /* TODO: move this to config file */
87   helpStrings.put ("hilfe", "de");
88   SEncoder kana("Kana");
89   SEncoder utf8("utf-8-s");
90   helpStrings.put (utf8.encode (kana.decode ("HERUPU", false)), "ja");
91   SEncoder hung("Hungarian");
92   helpStrings.put ("segit", "hu");
93   helpStrings.put (utf8.encode (hung.decode ("segi't", false)), "hu");
94   helpStrings.put (utf8.encode (hung.decode ("segi'tse'g", false)), "hu");
95   SEncoder yidd("Yiddish");
96   SV_UCS4 yi0;
97   yi0.append (SD_CD_RLO);
98   yi0.append (yidd.decode ("gehilF", false));
99   yi0.append (SD_CD_PDF);
100   SV_UCS4 yi1;
101   yi1.append (SD_CD_RLO);
102   yi1.append (yidd.decode ("helF", false));
103   yi1.append (SD_CD_PDF);
104   helpStrings.put (utf8.encode (yi0), "yi");
105   helpStrings.put (utf8.encode (yi1), "yi");
106   helpStrings.put (utf8.encode (yidd.decode ("gehilF", false)), "yi");
107   helpStrings.put (utf8.encode (yidd.decode ("helF", false)), "yi");
108   helpStrings.put ("ayuda", "es");
109 
110   configFile = props["yudit.config"];
111 
112   char fnc[64];
113   /* get an unused filename */
114   for (unsigned int fn=0; fn<100000; fn++)
115   {
116    if (fn==0)
117    {
118      sprintf (fnc, "untitled.txt");
119    }
120    else
121    {
122      sprintf (fnc, "untitled%d.txt", fn);
123    }
124    currentFileName = SString (fnc);
125 
126    SFile cfile (currentFileName);
127    if (cfile.size() < 0) break;
128   }
129   lastprinterOption = props["yudit.default.printer.options"];
130   lastpreviewOption ="-e ";
131   lastpreviewOption.append (props["yudit.default.preview.command"]);
132   lastpreviewOption.replaceAll("\\", "/");
133   lastpreviewOption.replaceAll("//", "/");
134   lastencoding=props["yudit.default.filetype"];
135 
136   setFrameListener (this);
137   command = new STextEdit ();
138   SString commandFont ("default");
139   if (props.get("yudit.command.font"))
140   {
141     commandFont = props["yudit.command.font"];
142   }
143   SString commandFontSizeString ("16");
144   if (props.get("yudit.command.fontsize"))
145   {
146     commandFontSizeString = props["yudit.command.fontsize"];
147   }
148   commandFontSizeString.append ((char)0);
149   double commandFontSize=0;
150   sscanf (commandFontSizeString.array(), "%lf", &commandFontSize);
151 
152   if (commandFontSize < 2.0) commandFontSize = 2.0;
153   command->setFont (commandFont, commandFontSize);
154   unsigned int commandHeight = command->getPreferredSize().height;
155   command->setMultiline (false);
156   command->setLineEndMark (false);
157 
158   messagebar = new SMessageBar (props);
159   unsigned int msgbarHeight = messagebar->getPreferredSize().height;
160 
161 
162   toolbar = new SToolBar (props);
163   unsigned int toobarHeight = toolbar->getPreferredSize().height;
164 
165   toolbar->setLayout (
166     SLayout (
167      SLocation (2,0),
168      SLocation (2998, toobarHeight+0),
169      SLocation (0, 0),
170      SLocation (100, 0)
171     )
172   );
173   toolbar->setListener (this);
174 
175 
176   messagelabel = new SMessageLabel (props);
177   unsigned int messagelabeHeight = messagelabel->getPreferredSize().height;
178 
179   messagelabel->setLayout (
180     SLayout (
181       SLocation (2, 1998-messagelabeHeight),
182       SLocation (2998, 1998),
183       SLocation (0, 100),
184       SLocation (100, 100)
185     )
186   );
187   command->setLayout (
188     SLayout (
189       SLocation (2, 1998-commandHeight-messagelabeHeight),
190       SLocation (2998, 1998-messagelabeHeight),
191       SLocation (0, 100),
192       SLocation (100, 100)
193     )
194   );
195 
196   messagebar->setLayout (
197     SLayout (
198      SLocation (2,1998-msgbarHeight-commandHeight-messagelabeHeight),
199      SLocation (2998, 1998-commandHeight-messagelabeHeight),
200      SLocation (0, 100),
201      SLocation (100, 100)
202     )
203   );
204 
205   sliderLayout =  SLayout (
206       SLocation (2978, toobarHeight+2),
207       SLocation (2998, 1998 - commandHeight - msgbarHeight - messagelabeHeight),
208       SLocation (100, 0),
209       SLocation (100, 100)
210   );
211 
212   slider = new SSlider ();
213   slider->setLayout (sliderLayout);
214   /* on mac somehow it did not want to resize - force it */
215   slider->resize (SDimension (10, 200));
216 
217   SString currentFont = toolbar->fonts[toolbar->currentFont];
218   SString currentFontSize = toolbar->fontsizes[toolbar->currentFontSize];
219   SString currentInput = toolbar->inputs[toolbar->currentInput];
220   SString currentParagraphSeparator = toolbar->paragraphBreaks[toolbar->currentParagraphSeparator];
221 
222 
223   editor = new STextEdit ();
224   editor->addSyntaxListener (toolbar);
225 
226   currentFontSize.append ((char)0);
227   double df;
228   if (sscanf (currentFontSize.array(), "%lf", &df)==0 || df < 2.0) df = 2.0;
229   editor->setFont (currentFont, df);
230 
231   editor->setMultiline (true);
232   editor->setLineEndMark (true);
233   editor->setDocumentEmbedding (toolbar->currentEmbedding);
234 
235   editorLayout =
236     SLayout (
237       SLocation (2, toobarHeight+2),
238       SLocation (2978, 1998 - commandHeight - msgbarHeight - messagelabeHeight),
239       SLocation (0, 0),
240       SLocation (100, 100)
241     );
242   editor->setLayout (editorLayout);
243 
244   /*SGC */
245   SString inputStyle = originalProperties["yudit.editor.xinputs.style"];
246 
247   /* allowed styles */
248   if (inputStyle=="preedit-over-status-under"
249        || inputStyle == "preedit-under-status-under"
250        || inputStyle=="preedit-over-status-over"
251        || inputStyle == "preedit-root-status-root" )
252   {
253     SProperties p;
254     SColor cbg(originalProperties["yudit.background"]);
255     SColor cfg(originalProperties["yudit.label.foreground"]);
256 
257     sprintf (fnc, "%lu,%lu", (unsigned long)cbg.getValue(),
258       (unsigned long)cfg.getValue());
259     p.put ("InputClientColor", fnc);
260 
261     SColor sbg(originalProperties["yudit.background"]);
262     SColor sfg(originalProperties["yudit.title.foreground"]);
263 
264     sprintf (fnc, "%lu,%lu", (unsigned long)sbg.getValue(),
265       (unsigned long)sfg.getValue());
266     p.put ("InputStatusColor", fnc);
267     editor->setXIMProperties (p);
268 
269     p.put ("InputStyle", inputStyle);
270     editor->setXIMProperties (p);
271   }
272   else
273   {
274     fprintf (stderr, "Yudit: unknown yudit.editor.xinputs.style=%*.*s\n",
275        SSARGS(inputStyle));
276   }
277 
278   /* showInputStatus has set up the xim properties for editor */
279   editor->setInputMethod (currentInput);
280 
281   if (currentInput.size() > 2)
282   {
283     if (currentInput != SS_KINPUT2_IM
284        && currentInput != SS_WINDOWS_IM
285        && currentInput[0] != 'x'
286        && currentInput[1] != 'X')
287     {
288       command->setInputMethod (currentInput);
289     }
290   }
291   if (props["yudit.editor.showbreak"]=="true")
292   {
293     editor->setLineEndMark (true);
294   }
295   else
296   {
297     editor->setLineEndMark (false);
298   }
299   if (props["yudit.editor.wordwrap"]=="true")
300   {
301     editor->setWordWrap (true);
302   }
303   else
304   {
305     editor->setWordWrap (false);
306   }
307   SSyntaxColors syn;
308   syn.colors[(unsigned int) SSyntax::SD_NONE] = SColor ("cyan");
309 /*
310   got rid of none. For errors and none we use the default fg.
311     = props.getProperty ("yudit.editor.syntax.none.foreground", "green");
312 */
313 
314   syn.colors[(unsigned int) SSyntax::SD_ERROR]
315     = props.getProperty ("yudit.editor.syntax.error.foreground", "OrangeRed3");
316   syn.colors[(unsigned int) SSyntax::SD_NUMBER]
317     = props.getProperty ("yudit.editor.syntax.number.foreground", "orange");
318   syn.colors[(unsigned int) SSyntax::SD_STRING]
319     = props.getProperty ("yudit.editor.syntax.string.foreground", "magenta");
320   syn.colors[(unsigned int) SSyntax::SD_COMMENT]
321     = props.getProperty ("yudit.editor.syntax.comment.foreground", "lightgray");
322   syn.colors[(unsigned int) SSyntax::SD_KEYWORD]
323     = props.getProperty ("yudit.editor.syntax.token.foreground", "yellow");
324   syn.colors[(unsigned int) SSyntax::SD_VARIABLE]
325     = props.getProperty ("yudit.editor.syntax.variable.foreground", "red");
326   syn.colors[(unsigned int) SSyntax::SD_DEFINE]
327     = props.getProperty ("yudit.editor.syntax.define.foreground", "cyan");
328   syn.colors[(unsigned int) SSyntax::SD_CONTROL]
329     = props.getProperty ("yudit.editor.syntax.control.foreground", "CornflowerBlue");
330   syn.colors[(unsigned int) SSyntax::SD_OTHER]
331     = props.getProperty ("yudit.editor.syntax.other.foreground", "gray90");
332 
333   editor->setSyntaxColors (syn);
334 
335   const SString& hl = props["yudit.editor.syntax"];
336   SString mode = translateHighlightMode (hl);
337   if (mode.size() >= 0)
338   {
339     editor->setSyntax (mode);
340   }
341 
342   SEditor e(currentParagraphSeparator);
343   editor->setEditor (e);
344   messagebar->setFontSize(df);
345   command->setEditor(SEditor());
346 
347   add (slider);
348   add (editor);
349   add (command);
350   add (toolbar);
351   add (messagebar);
352   add (messagelabel);
353 
354   setBackground (props["yudit.background"]);
355   editor->setTextBackground (props["yudit.editor.background"]);
356   editor->setForeground (props["yudit.editor.left.foreground"],
357             props["yudit.editor.right.foreground"]);
358   editor->setCaretForeground (props["yudit.editor.caret.left.foreground"],
359             props["yudit.editor.caret.right.foreground"]);
360   command->setTextBackground (props["yudit.command.background"]);
361   command->setForeground (props["yudit.command.left.foreground"],
362             props["yudit.command.right.foreground"]);
363   command->setCaretForeground (props["yudit.command.caret.left.foreground"],
364             props["yudit.command.caret.right.foreground"]);
365   slider->setSliderBackground (props["yudit.slider.background"]);
366 
367   SDimension pw = toolbar->getPreferredSize();
368   /* get the dimension */
369   SDimension ms(props["yudit.default.geometry"]);
370   //if (ms.width < pw.width + 10) ms.width = pw.width + 10;
371   //if (ms.height < pw.height + 10) ms.width = pw.height + 10;
372   if (ms.width <  150) ms.width = 150;
373   if (ms.height < 100) ms.height =  100;
374   resize (ms);
375   setMinimumSize (SDimension (150, 100));
376 
377   caretNow = STextIndex (0,0);
378   messagebar->setRow(1);
379   messagebar->setColumn (0);
380   editor->setCursorIndex(SCursorIndex(0,0));
381   editor->addTextEditLS (this);
382   command->addTextEditLS (this);
383   command->setHistorySize(30);
384 
385   kmapDialog = 0;
386   fileDialog = 0;
387   highlightDialog = 0;
388   textDialog = 0;
389 
390 #ifdef USE_WINAPI
391   SToolBar::SFormatIndex ft=SToolBar::SS_FORMAT_DOS;
392 #else
393   SToolBar::SFormatIndex ft=SToolBar::SS_FORMAT_UNIX;
394 #endif
395   toolbar->setParagraphSeparator (ft, true);
396   int lineNum = -1;
397   isFirstLoad = false;
398   SStringVector v;
399   if (args.size())
400   {
401     SString comm ("open -yes ");
402     SString enc ((lastencoding.size()==0)?SString("utf-8"):lastencoding);
403     SString filename;
404     bool help=false;
405     unsigned int i;
406     for (i=1; i<args.size(); i++)
407     {
408       if (args[i] == SString("--"))
409       {
410         if (i+1 < args.size())
411         {
412           filename = args[i+1];
413         }
414         break;
415       }
416       // +NUMBER
417       else if (getLineNumber (args[i]) > 0)
418       {
419         lineNum = getLineNumber (args[i]);
420       }
421       else if (args[i] == SString("-e") && i+1 < args.size())
422       {
423         i++;
424         enc = args[i];
425       }
426       else if (args[i] == SString("-help") || args[i] == SString("-h"))
427       {
428         help = true;
429       }
430       else if (args[i] == SString("-ndb") || args[i] == SString("-db"))
431       {
432         // already processed
433       }
434       else if (args[i] == SString("-us"))
435       {
436         SScriptProcessor::support(true);
437       }
438       else if (args[i] == SString("-nus"))
439       {
440         SScriptProcessor::support(false);
441       }
442       else if (args[i] == SString("-noinit"))
443       {
444         SScriptProcessor::doInit(false);
445       }
446       else if ((args[i] == SString("-d") || args[i] == SString("-geometry"))
447 	      && i+1 < args.size()) {
448         i++;
449 	ms = SDimension (args[i]);
450         //if (ms.width < pw.width + 10) ms.width = pw.width + 10;
451         //if (ms.height < pw.height + 10) ms.width = pw.height + 10;
452         if (ms.width < 150) ms.width =  150;
453         if (ms.height < 100) ms.width =  100;
454         resize (ms);
455       }
456       else
457       {
458         filename = args[i];
459         break;
460       }
461     }
462     //currentFileName = filename;
463     if (help)
464     {
465       filename = SString("help");
466       command->putHistory (filename);
467     }
468     else
469     {
470        filename = composeFileNameCommand (comm, enc,
471             completeFileName(filename));
472        /* now it comes handy - args starts with 1 */
473        unsigned int j;
474        for (j=args.size(); j>i; j--)
475        {
476           SString ss = composeFileNameCommand (comm, enc,
477                 completeFileName (args[j-1]));
478           command->putHistory (ss);
479        }
480     }
481     v.smartSplit (filename);
482     firstLoad = v;
483   }
484 
485   isFirstLoad = true;
486   deferredLoader = STimer::newTimer(100, this);
487   editor->setEditable (false);
488 
489   toolbar->setFileName(currentFileName, lastencoding);
490   toolbar->setHighlightName (editor->getHighlightName());
491 
492   setFileTitle ();
493   SIcon* icon = SIconFactory::getIcon("Yudit");
494   setApplicationImage (icon->getImage ());
495 
496 //fprintf (stderr, "SYudit.cpp EDITOR FOCUS REQUEST\n");
497   setDropListener (this, SStringVector ("text/uri-list,text/plain"));
498   showFreeHand (currentInput=="freehand");
499   if (lineNum > 0)
500   {
501     editor->setCursorIndex(SCursorIndex((unsigned int)(lineNum-1), 0, true));
502   }
503 
504 }
505 
~SYudit()506 SYudit::~SYudit ()
507 {
508 }
509 bool
close(SPanel * comp)510 SYudit::close (SPanel* comp)
511 {
512 
513   if (textDialog != 0 && textDialog->isShown())
514   {
515     textDialog->center();
516     return false;
517   }
518   bool ret = false;
519   if (toolbar->modified)
520   {
521     createTextDialog ();
522     ret = textDialog->getInput (
523         "Yudit: Exit", translate ("Unsaved changes.\nExit anyway?\n"),
524         STextDialog::SS_QUESTION);
525     if (ret)
526     {
527        saveProperties();
528        exit (0);
529     }
530     return false;
531   }
532   if (toolbar->printing)
533   {
534     createTextDialog ();
535     ret = textDialog->getInput (
536         "Yudit: Exit", translate ("Pending printing job.\nExit anyway?\n"),
537         SDialog::SS_QUESTION);
538     if (ret)
539     {
540        saveProperties();
541        exit (0);
542     }
543   }
544   saveProperties();
545   exit (0);
546 }
547 
548 /**
549  * Listening to toolbar.
550  */
551 void
toolBarButtonPressed(void * src,int which,bool accel)552 SYudit::toolBarButtonPressed (void* src, int which, bool accel)
553 {
554   if (!toolbar->printing) messagelabel->setMessage("");
555   if (textDialog != 0 && textDialog->isShown()) return;
556   SString currentFont = toolbar->fonts[toolbar->currentFont];
557   SString currentFontSize = toolbar->fontsizes[toolbar->currentFontSize];
558   SString currentInput = toolbar->inputs[toolbar->currentInput];
559   SString currentParagraphSeparator = toolbar->paragraphBreaks[toolbar->currentParagraphSeparator];
560   currentFontSize.append ((char)0);
561   double df;
562   SString pstr;
563   SStringVector pstrVector;
564   if (sscanf (currentFontSize.array(), "%lf", &df)==0 || df < 2.0) df = 2.0;
565   bool ok = false;
566   int dire = false;
567   bool wasmodified = toolbar->modified;
568 
569   switch (which)
570   {
571   /* FIXME */
572   case SToolBar::SS_OPEN:
573     if (!accel)
574     {
575        createFileDialog();
576        if (toolbar->modified)
577        {
578          createTextDialog();
579          ok = textDialog->getInput (
580           "Yudit: Open", translate ("Unsaved changes.\nOpen anyway?\n"),
581            STextDialog::SS_QUESTION);
582          if (!ok)
583          {
584            return;
585          }
586        }
587        fileDialog->setFileName (currentFileName);
588        fileDialog->setFileType (lastencoding);
589        ok = fileDialog->getInput ("Yudit: Open", false, false);
590        if (!ok)
591        {
592           return;
593        }
594        pstr.clear();
595        pstr.append ("open ");
596        pstr.append ("-yes ");
597        pstr.append ("-e ");
598        pstr.append (fileDialog->getFileType());
599        pstr.append (" ");
600        pstr.append (quoteFileName (fileDialog->getFileName()));
601        command->setText (pstr);
602        command->setCursorIndex (SCursorIndex(0,10000));
603        command->putHistory (pstr);
604        pstrVector.smartSplit(pstr);
605        load (pstrVector, pstr);
606        return;
607     }
608     if (toolbar->modified)
609     {
610       messagelabel->setMessage (translate ("Unsaved changes. Enter discards!"), SMessageLabel::SS_ERR);
611       SString str = composeFileNameCommand ("open -yes ",
612          lastencoding, currentFileName);
613       command->setText(str);
614       command->setCursorIndex (SCursorIndex(0,10000));
615     }
616     else
617     {
618       messagelabel->setMessage (translate ("open -yes -e encoding file"),
619          SMessageLabel::SS_INFO);
620       SString str = composeFileNameCommand (
621              "open ", lastencoding, currentFileName);
622       command->setText(str);
623       command->setCursorIndex (SCursorIndex(0,10000));
624     }
625     command->setFocus();
626     break;
627   case SToolBar::SS_SAVE:
628     if (!accel)
629     {
630        createFileDialog();
631        fileDialog->setFileName (currentFileName);
632        fileDialog->setFileType (lastencoding);
633        pstr = fileDialog->getFileName();
634        ok = fileDialog->getInput ("Yudit: Save", false, false);
635        if (!ok)
636        {
637           return;
638        }
639        if (pstr != fileDialog->getFileName() &&
640           newFileExists (fileDialog->getFileName()))
641        {
642          createTextDialog();
643          ok = textDialog->getInput (
644           "Yudit: Save", translate ("File exists.\nSave anyway?"),
645            STextDialog::SS_QUESTION);
646          if (!ok)
647          {
648            return;
649          }
650        }
651        pstr.clear();
652        pstr.append ("save ");
653        pstr.append ("-yes ");
654        pstr.append ("-e ");
655        pstr.append (fileDialog->getFileType());
656        pstr.append (" ");
657        pstr.append (quoteFileName (fileDialog->getFileName()));
658        command->setText (pstr);
659        command->setCursorIndex (SCursorIndex(0,10000));
660        command->putHistory (pstr);
661        pstrVector.smartSplit(pstr);
662        save (pstrVector, pstr);
663        return;
664     }
665     messagelabel->setMessage (translate ("save -e encoding file"),
666        SMessageLabel::SS_INFO);
667     {
668       SString str = composeFileNameCommand (
669              "save ", lastencoding, currentFileName);;
670       command->setText(str);
671       command->setCursorIndex (SCursorIndex(0,10000));
672     }
673     command->setFocus();
674     break;
675   case SToolBar::SS_FIND:
676     messagelabel->setMessage (translate ("find string"),
677        SMessageLabel::SS_INFO);
678     command->setText("find ");
679     command->setCursorIndex (SCursorIndex(0,10000));
680     command->setFocus();
681     break;
682   case SToolBar::SS_GOTO:
683     messagelabel->setMessage (translate ("go line [column]"),
684        SMessageLabel::SS_INFO);
685     command->setText("go ");
686     command->setCursorIndex (SCursorIndex(0,10000));
687     command->setFocus();
688     break;
689   case SToolBar::SS_PRINT:
690     messagelabel->setMessage (getPrintHelp (), SMessageLabel::SS_INFO);
691     pstr.append ("print ");
692     pstr.append (lastprinterOption);
693     command->setText(pstr);
694     command->setCursorIndex (SCursorIndex(0,10000));
695     command->setFocus();
696     break;
697   case SToolBar::SS_PRINT_PREVIEW:
698     messagelabel->setMessage (translate ("print -e program"),
699        SMessageLabel::SS_INFO);
700     pstr.append ("print ");
701     pstr.append (lastpreviewOption);
702     command->setText(pstr);
703     command->setCursorIndex (SCursorIndex(0,10000));
704     command->setFocus();
705     break;
706   case SToolBar::SS_UNDO:
707     if (!editor->undo())
708     {
709       messagelabel->setMessage (translate ("Nothing to undo."),
710          SMessageLabel::SS_WARN);
711       toolbar->setModified (false);
712     }
713     toolbar->setEmbedding(editor->getDocumentEmbedding(), false);
714     break;
715   case SToolBar::SS_REDO:
716     if (!editor->redo())
717     {
718       messagelabel->setMessage (translate ("Nothing to redo."),
719          SMessageLabel::SS_WARN);
720     }
721     toolbar->setEmbedding(editor->getDocumentEmbedding(), false);
722     break;
723   case SToolBar::SS_DOCUMENT_EMBEDDING:
724     editor->setDocumentEmbedding (toolbar->currentEmbedding);
725     break;
726   case SToolBar::SS_SET_OVERRIDE:
727     /* change it back */
728     dire = editor->changeDirection (toolbar->overrideLR ? SS_DR_LO : SS_DR_RO);
729     if (dire)
730     {
731       messagelabel->setMessage("");
732     }
733     else
734     {
735       /* leave it back */
736       if (!wasmodified) toolbar->setModified (true);
737       messagelabel->setMessage (
738         translate ("Direction of selected text has been set."),
739         SMessageLabel::SS_INFO);
740     }
741     break;
742   case SToolBar::SS_YIELD_EMBEDDING:
743     dire = editor->changeDirection  (toolbar->currentLR ? SS_DR_L : SS_DR_R);
744     if (dire)
745     {
746       messagelabel->setMessage("");
747     }
748     else
749     {
750       /* leave it back */
751       if (!wasmodified) toolbar->setModified (true);
752       messagelabel->setMessage (
753         translate ("Direction of selected text has been re-set."),
754         SMessageLabel::SS_INFO);
755     }
756     break;
757 
758   case SToolBar::SS_SET_EMBEDDING:
759     /* change it back */
760     dire = editor->changeDirection (toolbar->embedLR ? SS_DR_LE : SS_DR_RE);
761     if (dire)
762     {
763       messagelabel->setMessage("");
764     }
765     else
766     {
767       /* leave it back */
768       if (!wasmodified) toolbar->setModified (true);
769       messagelabel->setMessage (
770         translate ("Direction of selected text has been set."),
771         SMessageLabel::SS_INFO);
772     }
773     break;
774   case SToolBar::SS_MAGNIFY_PLUS:
775   case SToolBar::SS_MAGNIFY_MINUS:
776     messagebar->setFontSize(df);
777     editor->setFontSize (df);
778     if (freehand) freehand->setFontSize (df);
779     break;
780   case SToolBar::SS_FONT:
781     editor->setFont (currentFont, df);
782     if (freehand) freehand->setFont (currentFont, df);
783     break;
784   case SToolBar::SS_INPUT:
785     if (!accel)
786     {
787        createKMapDialog ();
788        ok = kmapDialog->getInput ("Yudit: KMap Setup",
789             toolbar->inputs, toolbar->currentInput);
790        if (!ok || kmapDialog->getSelectedKMap() < 0) break;
791        toolbar->inputChanged(kmapDialog->getKMapList (),
792           kmapDialog->getSelectedKMap());
793        currentInput =  toolbar->inputs[toolbar->currentInput];
794        userProps.put ("yudit.editor.inputs", toolbar->inputs.join (","));
795        userProps.put ("yudit.editor.input", currentInput);
796        saveProperties();
797     }
798     editor->setInputMethod (currentInput);
799     showFreeHand (currentInput=="freehand");
800 
801     if (currentInput != SS_KINPUT2_IM
802        && currentInput != SS_WINDOWS_IM
803        && currentInput[0] != 'x'
804        && currentInput[1] != 'X')
805     {
806       command->setInputMethod (currentInput);
807     }
808     else
809     {
810       command->setInputMethod ("straight");
811     }
812     /* update glyph info */
813     caretMoved();
814     break;
815   case SToolBar::SS_PARAGRAPH_BREAK:
816     editor->setParagraphSeparator (currentParagraphSeparator, true);
817     break;
818   case SToolBar::SS_HIGHLIGHTING:
819     if (!accel)
820     {
821        createHighlightDialog();
822        SString gotMode = editor->getHighlightName();
823        highlightDialog->setHighlightName (gotMode);
824        ok = highlightDialog->getInput ("Yudit: Highlighting");
825        if (!ok)
826        {
827           return;
828        }
829        SString hlmode = highlightDialog->getHighlightName();
830        pstr.clear();
831        pstr.append ("syntax ");
832        pstr.append (" ");
833        //pstr.append (quoteFileName (hlmode));
834        pstr.append (hlmode);
835        //command->setText (pstr);
836        //command->setCursorIndex (SCursorIndex(0,10000));
837        if (setHighlight (hlmode))
838        {
839          command->putHistory(pstr);
840        }
841        return;
842     }
843     else
844     {
845       SString gotMode = editor->getHighlightName();
846       SString cmd ("syntax");
847       cmd.append (" ");
848       cmd.append (gotMode);
849       command->setText (cmd);
850       command->setCursorIndex (SCursorIndex(0,10000));
851       command->setFocus();
852     }
853     break;
854   default:
855     break;
856   }
857 }
858 
859 bool
setHighlight(const SString & syntaxMode)860 SYudit::setHighlight (const SString& syntaxMode)
861 {
862   SString smode;
863   if ((smode = translateHighlightMode (syntaxMode)) == "")
864   {
865     SString err = translate ("usage: ");
866     err.append ("syntax none|simple|simple-dark|hunspell:en_US|...");
867     messagelabel->setMessage (err, SMessageLabel::SS_ERR);
868     return false;
869   }
870   SString oldM = editor->getHighlightName ();
871   editor->setSyntax (smode);
872   SString gotMode = editor->getSyntaxName();
873   if (gotMode != smode && smode != "simple"
874       && smode != "simple-dark" && smode != "none")
875   {
876     SString err = translate ("Can not set syntax: ");
877     err.append (smode);
878     messagelabel->setMessage (err, SMessageLabel::SS_ERR);
879     editor->setSyntax (oldM);
880     return false;
881   }
882   // dont display these
883   toolbar->setHighlightName (editor->getHighlightName());
884 
885   userProps.put ("yudit.editor.syntax", smode);
886   return true;
887 }
888 
889 void
toolBarButtonLeave(void * src,int which)890 SYudit::toolBarButtonLeave (void* src, int which)
891 {
892 }
893 
894 void
toolBarButtonEnter(void * src,int which)895 SYudit::toolBarButtonEnter (void* src, int which)
896 {
897 }
898 
899 
900 /**
901  * This is the STextEditLS
902  */
903 void
textChanged(void * source)904 SYudit::textChanged (void *source)
905 {
906   if (source == editor)
907   {
908     if (!toolbar->printing) messagelabel->setMessage("");
909     toolbar->setModified (true);
910     return;
911   }
912 }
913 
914 void
textEntered(void * source)915 SYudit::textEntered (void *source)
916 {
917   if (!toolbar->printing) messagelabel->setMessage("");
918   if (source != command) return;
919   SString text =  command->getText();
920   if (text.size()==0)
921   {
922     editor->setFocus();
923     return;
924   }
925   SStringVector cv;
926   cv.smartSplit (text);
927   if (cv.size()==2 && cv[0]=="quit" && cv[1] == "-yes")
928   {
929     exit (0);
930   }
931   if (cv.size()==1 && cv[0] == "quit")
932   {
933     if (toolbar->modified)
934     {
935       messagelabel->setMessage (translate ("Unsaved changes. Enter quits!"),
936          SMessageLabel::SS_ERR);
937       command->setText("quit -yes");
938       command->setCursorIndex (SCursorIndex(0,10000));
939       command->setFocus();
940       return;
941     }
942     if (toolbar->printing)
943     {
944       messagelabel->setMessage (translate ("Pending printing job. Enter quits!"),
945          SMessageLabel::SS_ERR);
946       command->setText("quit -yes");
947       command->setCursorIndex (SCursorIndex(0,10000));
948       command->setFocus();
949       return;
950     }
951     exit (0);
952   }
953   command->putHistory(text);
954   if (cv.size()>0 && cv[0] == "print")
955   {
956     print (cv, text);
957     return;
958   }
959   if ((cv.size()>0 && (cv[0] == "help" || cv[0] == "test" ||
960        helpStrings.get(cv[0]) != 0))
961      || (cv.size() > 1 && cv[0] == "howto"))
962   {
963     load (cv, text);
964     return;
965   }
966   if (cv.size()>0 && (cv[0] == "open" || cv[0] == "load"))
967   {
968     load (cv, text);
969     return;
970   }
971   if (cv.size()>0 && (cv[0] == "configure" || cv[0] == "config"))
972   {
973     load (cv, text);
974     return;
975   }
976   if (cv.size()>0 && (cv[0] == "save" || cv[0] == "save"))
977   {
978     save (cv, text);
979     return;
980   }
981   if (cv.size()>0 && cv[0] == "go")
982   {
983     goLineRow (cv, text);
984     return;
985   }
986   if (cv.size()>0 && cv[0] == "find")
987   {
988     find (cv, text);
989     return;
990   }
991   if (cv.size()>0 && cv[0] == "replace")
992   {
993     replace (cv, text);
994     return;
995   }
996   if (cv.size()>0 && cv[0] == "sedy")
997   {
998     SString lib = SSedy::getLocation ();
999     if (lib.size()==0) lib = SString ("not-found");
1000     SString message ("Sedy: ");
1001     message.append (lib);
1002     messagelabel->setMessage (message, SMessageLabel::SS_INFO);
1003     return;
1004   }
1005   if (cv.size() > 0 && cv[0] == "syntax")
1006   {
1007     SString smode;
1008     if (cv.size() != 2)
1009     {
1010       SString err = translate ("usage: ");
1011       err.append ("syntax none|simple|simple-dark|hunspell:en_US... ");
1012       messagelabel->setMessage (err, SMessageLabel::SS_ERR);
1013       return;
1014     }
1015     if (setHighlight (cv[1]))
1016     {
1017       editor->setFocus();
1018       command->putHistory(text);
1019     }
1020     return;
1021   }
1022   if (cv.size() > 0 && cv[0] == "wordwrap")
1023   {
1024     if (cv.size() != 2 || (cv[1] != "true" && cv[1] != "false"))
1025     {
1026       SString err = translate ("usage: ");
1027       err.append ("wordwrap true|false");
1028       messagelabel->setMessage (err, SMessageLabel::SS_ERR);
1029       return;
1030     }
1031     if (cv[1]=="true")
1032     {
1033       editor->setWordWrap (true);
1034     }
1035     else
1036     {
1037       editor->setWordWrap (false);
1038     }
1039     userProps.put ("yudit.editor.wordwrap", cv[1]);
1040     editor->setFocus();
1041     command->putHistory(text);
1042     return;
1043   }
1044   SString mess ("syntax error: ");
1045   mess.append (SS_LB_LRE);
1046   mess.append ("'");
1047   mess.append (text);
1048   mess.append ("'");
1049   mess.append (SS_LB_PDF);
1050   messagelabel->setMessage (mess, SMessageLabel::SS_ERR);
1051   command->clear();
1052   command->historyEnd();
1053   //editor->setFocus();
1054 }
1055 
1056 void
print(const SStringVector & args,const SString & str)1057 SYudit::print (const SStringVector& args, const SString& str)
1058 {
1059   if (toolbar->printing) return;
1060   SString executable;
1061   SString printer;
1062   SString filename;
1063   SString hsize("10");
1064   unsigned int i;
1065   bool shownl = false;
1066   bool islpr = false;
1067   double fontSize = messagebar->fontSize;
1068 
1069   SPrinter::SMedia media = SPrinter::A4;
1070   SPrinter::SOrientation orientation = SPrinter::PORTRAIT;
1071 
1072   for (i=1; i<args.size(); i++)
1073   {
1074     if ((args[i] == "-printer" || args[i] =="-p") && i+1 < args.size())
1075     {
1076       i++;
1077       printer = args[i];
1078     }
1079     else if ((args[i] == "-hsize") && i+1 < args.size())
1080     {
1081       i++;
1082       hsize = args[i];
1083     }
1084     else if ((args[i] == "-size") && i+1 < args.size())
1085     {
1086       i++;
1087       SString sarg = args[i];
1088       sarg.append ((char)0);
1089       sscanf (sarg.array(), "%lf", &fontSize);
1090       if (fontSize > 1000.0)
1091       {
1092         fontSize = 1000.0;
1093       }
1094       if (fontSize < 1.0)
1095       {
1096         fontSize = 1.0;
1097       }
1098     }
1099     else if ((args[i] == "-out" || args[i] =="-o") && i+1 < args.size())
1100     {
1101       i++;
1102       filename = completeFileName (args[i]);
1103     }
1104     else if ((args[i] == "-m" || args[i] =="-media") && i+1 < args.size())
1105     {
1106       i++;
1107       if (args[i] == "A3")
1108       {
1109         media = SPrinter::A3;
1110       }
1111       else if (args[i] == "A4")
1112       {
1113         media = SPrinter::A4;
1114       }
1115       else if (args[i] == "A5")
1116       {
1117         media = SPrinter::A5;
1118       }
1119       else if (args[i] == "B4")
1120       {
1121         media = SPrinter::B4;
1122       }
1123       else if (args[i] == "B5")
1124       {
1125         media = SPrinter::B5;
1126       }
1127       else if (args[i] == "Executive")
1128       {
1129         media = SPrinter::Executive;
1130       }
1131       else if (args[i] == "Folio")
1132       {
1133         media = SPrinter::Folio;
1134       }
1135       else if (args[i] == "Ledger")
1136       {
1137         media = SPrinter::Ledger;
1138       }
1139       else if (args[i] == "Legal")
1140       {
1141         media = SPrinter::Legal;
1142       }
1143       else if (args[i] == "Letter")
1144       {
1145         media = SPrinter::Letter;
1146       }
1147       else if (args[i] == "Quarto")
1148       {
1149         media = SPrinter::Quarto;
1150       }
1151       else if (args[i] == "Statement")
1152       {
1153         media = SPrinter::Statement;
1154       }
1155       else if (args[i] == "Tabloid")
1156       {
1157         media = SPrinter::Tabloid;
1158       }
1159       else
1160       {
1161         media = SPrinter::A4;
1162       }
1163     }
1164     else if (args[i] == "-exec" && i+1 < args.size())
1165     {
1166       i++;
1167       executable = args[i];
1168       int ind = str.find("-exec");
1169       if (ind > 0)
1170       {
1171         /* strlen ("-exec")*/
1172         ind += 5;
1173         while (ind < (int) str.size()
1174               && (str[(unsigned int)ind] == ' '
1175                   || str[(unsigned int)ind] == '\t')) ind++;
1176         if (ind < (int) str.size())
1177         {
1178           executable = SString (&str.array()[(unsigned int)ind],
1179              str.size()-(unsigned int)ind);
1180           i = args.size();
1181           break;
1182         }
1183       }
1184     }
1185     else if (args[i] =="-e" && i+1 < args.size())
1186     {
1187       /* strlen ("-e")*/
1188       i++;
1189       executable = args[i];
1190       int ind = str.find("-e");
1191       if (ind > 0)
1192       {
1193         ind += 2;
1194         while (ind < (int) str.size()
1195               && (str[(unsigned int)ind] == ' '
1196                   || str[(unsigned int)ind] == '\t')) ind++;
1197         if (ind < (int) str.size())
1198         {
1199           executable = SString (&str.array()[(unsigned int)ind],
1200              str.size()-(unsigned int)ind);
1201           i = args.size();
1202           break;
1203         }
1204       }
1205     }
1206     else if (args[i] == "-break" || args[i] =="-b")
1207     {
1208       shownl = true;
1209     }
1210     else if (args[i] == "-L" || args[i] =="-landscape")
1211     {
1212       orientation = SPrinter::LANDSCAPE;
1213     }
1214     else
1215     {
1216       break;
1217     }
1218   }
1219   hsize.append ((char)0);
1220   double hsized=10.0;
1221   sscanf (hsize.array(), "%lf", &hsized);
1222   if (hsized < 2.0) hsized = 1.0;
1223   if (hsized > 100.0) hsized = 100.0;
1224 
1225   if (filename.size()==0 && executable.size()==0)
1226   {
1227      islpr = true;
1228 
1229 #ifdef USE_WINAPI
1230      executable  = originalProperties["yudit.default.preview.command"];
1231      executable.replaceAll("\\", "/");
1232      executable.replaceAll("//", "/");
1233      if (!addMytoolPrefix (&executable)) return;
1234 #else
1235      executable = "lpr";
1236 #endif
1237   }
1238   if (i<args.size() || (filename.size()!=0 && executable.size()!=0)
1239      || (filename.size()!=0 && printer.size() > 0))
1240   {
1241     messagelabel->setMessage (getPrintHelp(), SMessageLabel::SS_ERR);
1242     return;
1243   }
1244   SOutputStream os;
1245   if (executable.size())
1246   {
1247     if (!islpr && !addMytoolPrefix (&executable)) return;
1248     if (printer.size())
1249     {
1250       executable.append (" -P ");
1251       executable.append (printer);
1252     }
1253     //fprintf (stderr, "executable [%*.*s]\n", SSARGS (executable));
1254     SPipe p(executable);
1255     os = p.getOutputStream();
1256     if (!os.isOK())
1257     {
1258       SString ems ("Can not execute: ");
1259       ems.append (SS_LB_LRE);
1260       ems.append ("'");
1261       ems.append (executable);
1262       ems.append ("'");
1263       ems.append (SS_LB_PDF);
1264       messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1265       return;
1266     }
1267   }
1268   else
1269   {
1270     SFile f(filename);
1271     os = f.getOutputStream();
1272     if (!os.isOK())
1273     {
1274       SString ems ("Can not open: ");
1275       ems.append (SS_LB_LRE);
1276       ems.append ("'");
1277       ems.append (filename);
1278       ems.append ("'");
1279       ems.append (SS_LB_PDF);
1280       messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1281     }
1282   }
1283   SWriter writer(os);
1284   SString fontName = toolbar->fonts[toolbar->currentFont];
1285 
1286   SPrinter p (writer, SPrinter::POSTSCRIPT, media, orientation);
1287   SUniPrint uniPrint(p, fontName, hsized, fontName, fontSize);
1288 
1289   SString text = editor->getSelectedText();
1290   SString sel = currentFileName;
1291   if (text.size() == 0)
1292   {
1293     text = editor->getText();
1294   }
1295   else
1296   {
1297     sel.append (" (excerpt)");
1298   }
1299 
1300   uniPrint.setDocumentEmbedding (toolbar->currentEmbedding);
1301   uniPrint.setLineEndMark(shownl);
1302   uniPrint.setWordWrap (editor->getWordWrap());
1303   toolbar->setPrinting(true);
1304 
1305   command->clear();
1306   command->historyEnd();
1307   editor->setFocus();
1308   messagelabel->setMessage (
1309      translate ("Printing..."),
1310       SMessageLabel::SS_NONE);
1311   if (!uniPrint.print (sel, text, true))
1312   {
1313       toolbar->setPrinting (false);
1314       SString ems ("Printing failed on '");
1315       ems.append (executable);
1316       ems.append (filename);
1317       ems.append ("'");
1318       messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1319       return;
1320   }
1321   int pagecount = uniPrint.getPageCount();
1322   char a[64];
1323   if (pagecount >= 1)
1324   {
1325     SString tr(translate("Printed %d page(s)."));
1326     tr.append ((char)0);
1327     sprintf (a, tr.array(), pagecount);
1328     if (uniPrint.hasNative())
1329     {
1330       SString ms ("Bitmap font printed (bad printing quality).");
1331       ms.append (a);
1332       messagelabel->setMessage (ms, SMessageLabel::SS_WARN);
1333     }
1334     else
1335     {
1336       SString ms (a);
1337       messagelabel->setMessage (ms, SMessageLabel::SS_INFO);
1338     }
1339   }
1340   command->clear();
1341   command->historyEnd();
1342 
1343   SString  op;
1344   for (i=strlen ("print "); i<str.size(); i++)
1345   {
1346     op.append ((char)str[i]);
1347   }
1348   if (executable.size() && !islpr && args.size() != 1)
1349   {
1350     lastpreviewOption = op;
1351   }
1352   else
1353   {
1354     lastprinterOption = op;
1355     //fprintf (stderr, "lastprinterOption=[%*.*s] str=[%*.*s]\n",
1356      //   SSARGS(lastprinterOption), SSARGS (str));
1357   }
1358   toolbar->setPrinting (false);
1359 }
1360 
1361 void
load(const SStringVector & args,const SString & notused)1362 SYudit::load (const SStringVector& args, const SString& notused)
1363 {
1364   caretIndex.put (currentFileName, caretNow);
1365   SString encode="utf-8";
1366   bool hasyes = false;
1367   SString filename;
1368   unsigned int i;
1369   SString internal;
1370   for (i=1; i<args.size(); i++)
1371   {
1372     if (args[i] == "-e" && i+1 < args.size())
1373     {
1374       i++;
1375       encode = args[i];
1376     }
1377     else if (args[i] =="-yes")
1378     {
1379       hasyes = true;
1380     }
1381     else if (i+1 == args.size())
1382     {
1383       filename = completeFileName(args[i]);
1384     }
1385     else
1386     {
1387       break;
1388     }
1389   }
1390   if (args[0] =="help" || helpStrings.get (args[0]) != 0)
1391   {
1392     internal =  getPrefix();
1393     internal.append ("/doc/");
1394     SString lang = getLanguage();
1395     if (helpStrings.get (args[0]) != 0)
1396     {
1397       lang = helpStrings[args[0]];
1398     }
1399     if (lang.size())
1400     {
1401       SString nd = internal;
1402       nd.append (lang);
1403       nd.append ("/");
1404       nd.append ("FAQ.TXT");
1405       SFile file (nd);
1406       if (file.size() > 0)
1407       {
1408         internal.append (lang);
1409         internal.append ("/");
1410       }
1411     }
1412 
1413     internal.append ("FAQ.TXT");
1414     i = args.size();
1415     encode = "utf-8";
1416     filename = internal;
1417   }
1418 
1419   if (args[0] =="howto" && args.size() >1)
1420   {
1421     internal =  getPrefix();
1422     internal.append ("/doc/");
1423     SString lang = getLanguage();
1424     if (helpStrings.get (args[0]) != 0)
1425     {
1426       lang = helpStrings[args[0]];
1427     }
1428     if (lang.size())
1429     {
1430       SString nd = internal;
1431       nd.append (lang);
1432       nd.append ("/");
1433       nd.append ("HOWTO-");
1434       nd.append (args[1]);
1435       nd.append (".txt");
1436       SFile file (nd);
1437       if (file.size() > 0)
1438       {
1439         internal.append (lang);
1440         internal.append ("/");
1441       }
1442     }
1443     internal.append ("HOWTO-");
1444     internal.append (args[1]);
1445     internal.append (".txt");
1446     i = args.size();
1447     encode = "utf-8";
1448     filename = internal;
1449   }
1450 
1451   if (args[0] =="test")
1452   {
1453     internal =  getPrefix();
1454     internal.append ("/doc/");
1455     internal.append ("TestPage.txt");
1456     i = args.size();
1457     encode = "utf-8";
1458     filename = internal;
1459   }
1460   if (args[0] =="configure" || args[0] =="config")
1461   {
1462     SString afile = currentFileName;
1463     currentFileName = "/dev/null";
1464     /* trick to save properties */
1465     saveProperties();
1466     currentFileName = afile;
1467     SString internal = getHome();;
1468     internal.append ("/.yudit/yudit.properties");
1469     i = args.size();
1470     encode = "utf-8";
1471     filename = internal;
1472   }
1473 
1474   if (filename.size()==0)
1475   {
1476     if (i<args.size())
1477     {
1478       messagelabel->setMessage (translate ("usage: open -e utf-8 -yes filename"),
1479           SMessageLabel::SS_ERR);
1480       return;
1481     }
1482     filename = currentFileName;
1483   }
1484   if (!hasyes && toolbar->modified)
1485   {
1486     messagelabel->setMessage (translate ("Unsaved changes. Try -yes option"),
1487        SMessageLabel::SS_ERR);
1488     return;
1489   }
1490   if (!hasyes && toolbar->printing)
1491   {
1492     messagelabel->setMessage (translate ("Pending printing job. Try -yes option"),
1493        SMessageLabel::SS_ERR);
1494     return;
1495   }
1496 
1497   SEncoder utf8("utf-8-s");
1498   SEncoder enc(encode);
1499   if (!enc.isOK())
1500   {
1501     SString ems = translate ("Unknown encoding: ");
1502 
1503     ems.append (SS_LB_LRE);
1504     ems.append ("'");
1505     ems.append (encode);
1506     ems.append ("'");
1507     ems.append (SS_LB_PDF);
1508 
1509     messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1510     return;
1511   }
1512   SFile f(filename);
1513   SFileImage im = f.getFileImage();
1514 //fprintf(stderr, "size=%ld im=%ld array=%lx\n", f.size(), im.size(), (unsigned long) im.array());
1515   if (f.size()<0 || im.size()<0 || im.array()==0)
1516   {
1517     if (hasyes)
1518     {
1519       lastencoding = encode;
1520       command->clear();
1521       currentFileName = filename;
1522       toolbar->setFileName(currentFileName, lastencoding);
1523       setFileTitle ();
1524 
1525       editor->clear();
1526       editor->setFocus();
1527       toolbar->setModified(false);
1528     }
1529     SString ems = translate ("Can not read: ");
1530     ems.append (SS_LB_LRE);
1531     ems.append ("'");
1532     ems.append (filename);
1533     ems.append ("'");
1534     ems.append (SS_LB_PDF);
1535     messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1536     return;
1537   }
1538   SString text (im.array(), f.size());
1539   if (cryptFileMatcher.size()!=0 && filename.match (cryptFileMatcher)) {
1540 
1541 //fprintf (stderr, "Sedy currentFileName = %*.*s\n", SSARGS(currentFileName));
1542 
1543     SStatus status = decryptText (filename, text, &text);
1544     if (status == Failed) {
1545         SString ems = translate ("Can not read: ");
1546         ems.append (SS_LB_LRE);
1547         ems.append ("'");
1548         ems.append (filename);
1549         ems.append ("'");
1550         ems.append (SS_LB_PDF);
1551         messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1552         // NO workaround works here for editor focus.
1553         //window->getKeyboardFocus();
1554         editor->setFocus();
1555         return;
1556     }
1557     if (status == Canceled) {
1558         // NO workaround works here for editor focus.
1559         //window->getKeyboardFocus();
1560         editor->setFocus();
1561         return;
1562     }
1563     //workaround to get focus.
1564     window->getKeyboardFocus();
1565     encrypted = true;
1566   } else {
1567     encrypted = false;
1568   }
1569 
1570   SV_UCS4 ucs4 = enc.decode (text);
1571 //fprintf (stderr, "BOTTLE - END\n");
1572   bool sft = false;
1573 #ifdef USE_WINAPI
1574   SToolBar::SFormatIndex ft=SToolBar::SS_FORMAT_DOS;
1575 #else
1576   SToolBar::SFormatIndex ft=SToolBar::SS_FORMAT_UNIX;
1577 #endif
1578   bool hadlinebreak = false;
1579   if (ucs4.size() > 1 &&
1580       (ucs4[ucs4.size()-1] == (SS_UCS4) '\r'
1581     || ucs4[ucs4.size()-1] == (SS_UCS4) '\n'
1582     || ucs4[ucs4.size()-1] == (SS_UCS4) 0x2029))
1583   {
1584     switch (ucs4[ucs4.size()-1])
1585     {
1586     case '\n':
1587       ft =  (ucs4.size()>1 && ucs4[ucs4.size()-2]=='\r')
1588          ? SToolBar::SS_FORMAT_DOS : SToolBar::SS_FORMAT_UNIX;
1589       hadlinebreak = true;
1590       break;
1591     case '\r': ft = SToolBar::SS_FORMAT_MAC;
1592       hadlinebreak = true;
1593       break;
1594     case 0x2029: ft = SToolBar::SS_FORMAT_PS;
1595       hadlinebreak = true;
1596       break;
1597     }
1598   }
1599   else
1600   {
1601     ft = SToolBar::SS_FORMAT_UNIX;
1602   }
1603   sft = (toolbar->currentParagraphSeparator != (unsigned int) ft);
1604   text = utf8.encode (ucs4);
1605   editor->clear();
1606   editor->setText(text);
1607   editor->setCursorIndex(SCursorIndex(0,0));
1608 
1609   SString ems = translate ("Opened: ");
1610   ems.append (SS_LB_LRE);
1611   ems.append ("'");
1612   ems.append (filename);
1613   ems.append ("'");
1614   ems.append (SS_LB_PDF);
1615   ems.append (".");
1616   if (sft)
1617   {
1618     ems.append (translate (" Line Break:"));
1619     ems.append (translate (toolbar->paragraphBreakStrings[ft]));
1620   }
1621   if (!hadlinebreak)
1622   {
1623     ems.append (translate(" Incomplete Last Line..."));
1624   }
1625 
1626   if (sft)
1627   {
1628     toolbar->setParagraphSeparator ((int) ft, false);
1629     SString currentParagraphSeparator =
1630          toolbar->paragraphBreaks[toolbar->currentParagraphSeparator];
1631     editor->setParagraphSeparator (currentParagraphSeparator, false);
1632   }
1633 
1634   toolbar->setModified (false);
1635   editor->setFocus();
1636 
1637   /*FIXME: load and set currentFileName */
1638   lastencoding = encode;
1639   command->clear();
1640   currentFileName = filename;
1641   toolbar->setEncrypted(encrypted);
1642   if (encrypted) {
1643     setHighlight("simple");
1644   } else {
1645     currentPassword = SString("");
1646   }
1647   editor->setAutoClipboard(encrypted ? false : SYUDIT_AUTO_KEYBOARD);
1648 
1649   toolbar->setFileName(currentFileName, lastencoding);
1650   setFileTitle ();
1651 
1652   messagelabel->setMessage (ems,
1653        sft ?  SMessageLabel::SS_WARN : SMessageLabel::SS_INFO);
1654   const STextIndex* sindex = caretIndex.get (filename);
1655   if (sindex)
1656   {
1657     editor->setCursorIndex(SCursorIndex(sindex->line, sindex->index));
1658   }
1659   editor->setFocus();
1660 }
1661 
1662 // 0 canceled by user
1663 SYudit::SStatus
decryptText(const SString & fileName,const SString & text,SString * out)1664 SYudit::decryptText (const SString& fileName, const SString& text, SString* out)
1665 {
1666   createPasswordDialog();
1667   passwordDialog->setFileName (fileName);
1668   bool ok = passwordDialog->getInput ("Yudit: Decrypt");
1669   if (ok) {
1670     SString password = passwordDialog->getPassword();
1671     *out = sedy.decrypt (text, password);
1672     //fprintf(stderr, "password %*.*s\n", SSARGS(password));
1673     if (sedy.getLastError().size()) {
1674         *out = SString("");
1675         //fprintf (stderr, "Sedy: %*.*s\n", SSARGS(sedy.getLastError()));
1676         return Failed;
1677     }
1678     currentPassword = password;
1679     return Succeeded;
1680   }
1681   *out = SString("");
1682   return Canceled;
1683 }
1684 
1685 void
save(const SStringVector & args,const SString & str)1686 SYudit::save (const SStringVector& args, const SString& str)
1687 {
1688   SString encode="utf-8";
1689   SString filename;
1690   unsigned int i;
1691   bool hasyes = false;
1692   for (i=1; i<args.size(); i++)
1693   {
1694     if (args[i] == "-e" && i+1 < args.size())
1695     {
1696       i++;
1697       encode = args[i];
1698     }
1699     else if (i+1 == args.size())
1700     {
1701       filename = completeFileName (args[i]);
1702     }
1703     else if (args[i] =="-yes")
1704     {
1705       hasyes = true;
1706     }
1707     else
1708     {
1709       break;
1710     }
1711   }
1712   if (filename.size()==0)
1713   {
1714     if (i<args.size())
1715     {
1716       messagelabel->setMessage (translate ("usage: save -e utf-8 -yes filename"),
1717           SMessageLabel::SS_ERR);
1718       return;
1719     }
1720     filename = completeFileName (currentFileName);
1721   }
1722 
1723   if (!hasyes && newFileExists (filename))
1724   {
1725     SString ems = translate ("File exists. Use -yes option.");
1726     messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1727     return;
1728   }
1729 
1730 
1731   SEncoder utf8("utf-8-s");
1732   SEncoder enc(encode);
1733   if (!enc.isOK())
1734   {
1735     SString ems = translate ("Unknown encoding: ");
1736     ems.append (SS_LB_LRE);
1737     ems.append ("'");
1738     ems.append (encode);
1739     ems.append ("'");
1740     ems.append (SS_LB_PDF);
1741     messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1742     return;
1743   }
1744   SString text = editor->getText();
1745   SString password = currentPassword;
1746   // Dealing with password changes for sedy files.
1747 //fprintf (stderr, "password size: %u\n", password.size());
1748   if (password.size() > 0 && !filename.match (cryptFileMatcher)) {
1749       SString ems = translate ("Output file is not .sedy file");
1750       messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1751       return;
1752   }
1753 
1754   SFile f(filename);
1755   bool encryptedCandidate = encrypted;
1756 
1757   SV_UCS4 ucs4 = utf8.decode (text);
1758   bool completed = false;
1759   if (ucs4.size()
1760     && ucs4[ucs4.size()-1] != (SS_UCS4) '\r'
1761     && ucs4[ucs4.size()-1] != (SS_UCS4) '\n'
1762     && ucs4[ucs4.size()-1] != (SS_UCS4) 0x2029)
1763   {
1764     completed = true;
1765   }
1766   text = enc.encode (ucs4);
1767 
1768 //fprintf(stderr, "Encrypted in=%d\n", encrypted);
1769   if (encrypted || (sedyLibrary.size() && filename.match (cryptFileMatcher))) {
1770     SString passwordCandidate = currentPassword;
1771     if (newFileExists (filename)) {
1772       SString ems = translate ("Output sedy file exists.");
1773       messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1774       return;
1775     }
1776     // Only file changes and new files can change password.
1777     if (filename != currentFileName || f.size()<0) {
1778         createPasswordDialog();
1779         passwordDialog->setFileName (filename);
1780         bool ok = passwordDialog->getInput ("Yudit: Change Password");
1781         if (!ok) {
1782             SString ems = translate ("Canceled by user.");
1783             messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1784             return;
1785         }
1786         passwordCandidate = passwordDialog->getPassword ();
1787         if (passwordCandidate.size() < CRYPT_MIN_PASSWORD_SIZE) {
1788             SString ems = translate ("New Password is too short.");
1789             messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1790             return;
1791         }
1792     }
1793     text = sedy.encrypt (text, passwordCandidate);
1794     if (sedy.getLastError().size()) {
1795         text = SString("");
1796        //fprintf(stderr, "Sedy: %*.*s\n", SSARGS(sedy.getLastError()));
1797         SString ems = translate ("Failded to set new password.");
1798         messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1799         return;
1800     }
1801     password = passwordCandidate;
1802     encryptedCandidate = true;
1803   }
1804   SOutputStream os = f.getOutputStream();
1805   if (!os.isOK())
1806   {
1807     SString ems = translate ("Can not write: ");
1808     ems.append (SS_LB_LRE);
1809     ems.append ("'");
1810     ems.append (filename);
1811     ems.append ("'");
1812     ems.append (SS_LB_PDF);
1813     messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1814     return;
1815   }
1816   SWriter writer(os);
1817   if ((text.size() > 0 && !writer.write (text)) || !writer.close())
1818   {
1819     SString ems = translate ("Error while writing: ");
1820     ems.append (SS_LB_LRE);
1821     ems.append ("'");
1822     ems.append (filename);
1823     ems.append ("'");
1824     ems.append (SS_LB_PDF);
1825     messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1826     return;
1827   }
1828   currentPassword = password;
1829   encrypted = encryptedCandidate;
1830 
1831   lastencoding = encode;
1832   currentFileName = filename;
1833   toolbar->setFileName(currentFileName, lastencoding);
1834   setFileTitle();
1835 
1836   toolbar->setEncrypted(encrypted);
1837   if (encrypted) {
1838     setHighlight("simple");
1839   } else {
1840     currentPassword = SString("");
1841   }
1842   editor->setAutoClipboard(currentPassword.size()
1843         ? false : SYUDIT_AUTO_KEYBOARD);
1844 
1845   command->clear();
1846   command->historyEnd();
1847 
1848   SString ems = translate ("Wrote: ");
1849   ems.append (SS_LB_LRE);
1850   ems.append ("'");
1851   ems.append (filename);
1852   ems.append ("'");
1853   ems.append (SS_LB_PDF);
1854   ems.append (".");
1855   if (completed) ems.append (translate(" Incomplete Last Line..."));
1856   messagelabel->setMessage (ems,
1857          (completed) ? SMessageLabel::SS_WARN : SMessageLabel::SS_INFO);
1858   toolbar->setModified (false);
1859   editor->setFocus();
1860   caretIndex.put (currentFileName, caretNow);
1861 }
1862 
1863 /**
1864  * move the cursor
1865  */
1866 void
goLineRow(const SStringVector & args,const SString & str)1867 SYudit::goLineRow (const SStringVector& args, const SString& str)
1868 {
1869   if (args.size () < 2 || args.size() > 3)
1870   {
1871     SString ems = translate ("usage: go line [column] ");
1872     messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1873     return;
1874   }
1875   SString l=args[1];
1876   SString c;
1877   if (args.size()==3) c=args[2];
1878   l.append ((char)0);
1879   c.append ((char)0);
1880   int li=0;
1881   int ci=0;
1882   sscanf (l.array(), "%d", &li);
1883   sscanf (c.array(), "%d", &ci);
1884   if (li <= 0)
1885   {
1886     editor->setCursorIndex(SCursorIndex(0, 0, true));
1887   }
1888   else if (ci <= 0)
1889   {
1890     editor->setCursorIndex(SCursorIndex((unsigned int)(li-1), 0, true));
1891   }
1892   else
1893   {
1894     editor->setCursorIndex(SCursorIndex((unsigned int)(li-1),
1895        (unsigned int) (ci-1), false));
1896   }
1897 }
1898 
1899 /**
1900  * find text
1901  */
1902 void
find(const SStringVector & args,const SString & str)1903 SYudit::find (const SStringVector& args, const SString& str)
1904 {
1905   if (args.size () != 2)
1906   {
1907     SString ems = translate ("usage: find text");
1908     messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1909     return;
1910   }
1911   if (!editor->find (args[1]))
1912   {
1913     SString ems = translate ("search string not found.");
1914     ems.append (SS_LB_LRE);
1915     ems.append ("'");
1916     ems.append (args[1]);
1917     ems.append ("'");
1918     ems.append (SS_LB_PDF);
1919     messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1920     return;
1921   }
1922 }
1923 
1924 /**
1925  * replace text
1926  */
1927 void
replace(const SStringVector & args,const SString & str)1928 SYudit::replace (const SStringVector& args, const SString& str)
1929 {
1930   if (args.size () != 3 || args[1].size()==0)
1931   {
1932     SString ems = translate ("usage: replace original new");
1933     messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1934     return;
1935   }
1936   if (!editor->replace (args[1], args[2]))
1937   {
1938     SString ems = translate ("search string not found.");
1939     ems.append (SS_LB_LRE);
1940     ems.append ("'");
1941     ems.append (args[1]);
1942     ems.append ("'");
1943     ems.append (SS_LB_PDF);
1944     messagelabel->setMessage (ems, SMessageLabel::SS_ERR);
1945   }
1946   return;
1947 }
1948 
1949 void
focusOutRequest(void * source)1950 SYudit::focusOutRequest (void *source)
1951 {
1952   if (source == editor)
1953   {
1954     command->setFocus();
1955   }
1956   else
1957   {
1958     editor->setFocus();
1959   }
1960 }
1961 void
focusChanged(void * source,bool in)1962 SYudit::focusChanged (void *source, bool in)
1963 {
1964 }
1965 void
caretMoved(void * source,unsigned int _line,unsigned int _column,bool _before)1966 SYudit::caretMoved (void *source,
1967    unsigned int _line, unsigned int _column, bool _before)
1968 {
1969   if (source != editor) return;
1970   caretMoved();
1971 }
1972 
1973 void
caretMoved()1974 SYudit::caretMoved ()
1975 {
1976   STextIndex ti = editor->getCaretArrowFrom ();
1977 
1978   if (ti.line != caretNow.line) messagebar->setRow(ti.line+1);
1979   if (ti.index != caretNow.index) messagebar->setColumn (ti.index);
1980 
1981   if ((caretNow.line != ti.line || caretNow.index != ti.index)
1982       && !toolbar->printing)
1983   {
1984     messagelabel->setMessage("");
1985   }
1986   caretNow = ti;
1987 
1988   toolbar->directionChanged (editor->isEmbedStateLR());
1989 
1990   if (ti.index == 0)
1991   {
1992     messagebar->setGlyphInfo (0, SString());
1993   }
1994   else
1995   {
1996     STextIndex tn (ti.line, ti.index-1);
1997     const SGlyph* g = editor->glyphAt(tn);
1998     SV_UCS4 chars;
1999     if (g!=0)
2000     {
2001       chars = g->getChars();
2002     }
2003     messagebar->setGlyphInfo (g, editor->encode (chars));
2004   }
2005 }
2006 
2007 /**
2008  * compose an escaped  file name.
2009  */
2010 SString
composeFileNameCommand(const SString & prefix,const SString & encoding,const SString & file)2011 SYudit::composeFileNameCommand (const SString& prefix,
2012         const SString &encoding, const SString& file)
2013 {
2014   SString ret (prefix);
2015   ret.append ("-e ");
2016   ret.append (encoding);
2017   ret.append (" ");
2018   ret.append (quoteFileName (file));
2019   return SString(ret);
2020 }
2021 
2022 SString
quoteFileName(const SString & file)2023 SYudit::quoteFileName (const SString& file)
2024 {
2025   SString ret;
2026   if (file.find(" ") < 0)
2027   {
2028     ret.append (file);
2029   }
2030   else if (file.find ("\"") < 0)
2031   {
2032     ret.append ("\"");
2033     ret.append (file);
2034     ret.append ("\"");
2035   }
2036   else
2037   {
2038     ret.append ("\'");
2039     ret.append (file);
2040     ret.append ("\'");
2041   }
2042   return SString(ret);
2043 }
2044 
2045 SString
completeFileName(const SString & _file)2046 SYudit::completeFileName(const SString& _file)
2047 {
2048   /* home directory substitution ~/ */
2049   SString file(_file);
2050   if (file.size() > 2 && file[0] == '~' && file[1]=='/')
2051   {
2052     file.remove (0, 2);
2053     SString homedir = getHome();
2054     homedir.append ("/");
2055     file.insert (0, homedir);
2056   }
2057   return SString(file);
2058 }
2059 
2060 /**
2061  * return false if it is not a new file or the file does not exist.
2062  */
2063 bool
newFileExists(const SString & filename)2064 SYudit::newFileExists (const SString& filename)
2065 {
2066   if (filename == currentFileName) return false;
2067   SFile f (filename);
2068   if (f.size() <0) return false;
2069   return true;
2070 }
2071 
2072 void
saveProperties()2073 SYudit::saveProperties ()
2074 {
2075   /* do not save proeprties if it is being edited */
2076   SString cfile = getHome();;
2077   cfile.append ("/.yudit/yudit.properties");
2078   if (currentFileName == cfile) return;
2079 
2080   //userProps.put ("yudit.default.printer", lastprinterOption);
2081   //userProps.put ("yudit.default.previewer", lastpreviewOption);
2082 
2083   SString s;
2084   s = toolbar->fonts[toolbar->currentFont];
2085   userProps.put ("yudit.editor.font", s);
2086   s = toolbar->inputs[toolbar->currentInput];
2087   userProps.put ("yudit.editor.input", s);
2088   s = toolbar->fontsizes[toolbar->currentFontSize];
2089   userProps.put ("yudit.editor.fontsize", s);
2090   s = "";
2091   s.print ((unsigned int) getSize().width);
2092   s.append ("x");
2093   s.print ((unsigned int) getSize().height);
2094   userProps.put ("yudit.default.geometry", s);
2095   if (freehand)
2096   {
2097     SString s = freehand->getConverter();
2098     if (s.size())
2099     {
2100       userProps.put ("yudit.freehand.converter", s);
2101     }
2102   }
2103 
2104   /* create a property file that has the original properties and
2105    * the ones that I changed.
2106    */
2107   /* create a property list that has changes since last save */
2108   SProperties changes;
2109   for (unsigned int i=0; i<userProps.size(); i++)
2110   {
2111     for (unsigned int j=0; j<userProps.size(i); j++)
2112     {
2113       if (userProps.get(i, j) ==0) continue;
2114       const SString& key = userProps.key(i, j);
2115       const SString& vle = *userProps.get(i, j);
2116       if (originalProperties.get (key) == 0)
2117       {
2118          changes.put (key, vle);
2119       }
2120       else  if (vle != originalProperties[key])
2121       {
2122          changes.put (key, vle);
2123       }
2124     }
2125   }
2126   SProperties full = originalProperties;
2127   SProperties current;
2128   ::loadProperties (configFile, &current);
2129   /* just save back everything - change in yudit 2.5 */
2130   full.merge (current);
2131   /* merge in changes */
2132   full.merge (changes);
2133   full.put ("00HEADER.version.yudit", SD_YUDIT_VERSION);
2134 
2135   /* That stupid old properties header comment. */
2136   const SString *pstr = full.get ("yudit.background.#");
2137   /* compatibility. remove this. */
2138   if (pstr!=0)
2139   {
2140     /* Test it */
2141     if (pstr->find ("#   Autosave will eliminate all comments and '\\' (line joiner) characters.") > 0)
2142     {
2143       SString a;
2144       a.append ("# From version 2.7.6 Yudit preserves comment lines\n");
2145       a.append ("# that start with a '#' and preceed the property  \n");
2146       a.append ("# line they refer to. ");
2147       full.put ("yudit.background.#", a);
2148     }
2149   }
2150 
2151   if (!::saveProperties (configFile, full))
2152   {
2153     SString str = translate ("Could not save preferences");
2154     str.append (" ");
2155     str.append (configFile);
2156     messagelabel->setMessage (str, SMessageLabel::SS_ERR);
2157     fprintf (stderr, "Could not save properties into %*.*s.\n",
2158        SSARGS(configFile));
2159   }
2160 }
2161 
2162 bool
dropped(void * p,const SString & mimetype,const SString & data)2163 SYudit::dropped (void* p, const SString& mimetype, const SString& data)
2164 {
2165   if (textDialog != 0 && textDialog->isShown()) return false;
2166   //fprintf (stderr, "SYudit::dropped %*.*s [%*.*s]\n", SSARGS(mimetype), SSARGS(data));
2167   SStringVector v (data, "\r\n");
2168   SString file=v[0];
2169   if (mimetype == "text/uri-list")
2170   {
2171     // FIX %XX
2172     SString ret;
2173     char* c = 0;
2174     char buff[3];
2175     for (unsigned i=0; i<file.size(); i++)
2176     {
2177       if (file[i] == '%' && i+2<file.size())
2178       {
2179         buff[0] = file[i+1];
2180         buff[1] = file[i+2];
2181         buff[2] = 0;
2182         c = 0;
2183         ret.append ((char)(unsigned char)strtol (buff, &c, 16));
2184         i=i+2;
2185       } else {
2186         ret.append ((char) file[i]);
2187       }
2188     }
2189     file = ret;
2190     if (file.size() < strlen ("file:")
2191        || strncmp (file.array(), "file:", strlen ("file:"))!=0)
2192     {
2193       SString msg = translate ("unsupported text/uri: ");
2194       msg.append (SS_LB_LRE);
2195       msg.append ("'");
2196       msg.append (file);
2197       msg.append ("'");
2198       msg.append (SS_LB_PDF);
2199       messagelabel->setMessage (msg, SMessageLabel::SS_ERR);
2200       return false;
2201     }
2202     file.remove (0, strlen ("file:"));
2203   }
2204   if (fileDialog != 0 && fileDialog->isShown())
2205   {
2206      fileDialog->center();
2207      fileDialog->setFileName (file);
2208      return true;
2209   }
2210   SString cm ("open -e ");;
2211   cm.append (lastencoding);
2212   cm.append (" ");
2213   if (toolbar->modified)
2214   {
2215     messagelabel->setMessage (translate ("Unsaved changes. Enter discards!"), SMessageLabel::SS_ERR);
2216     cm.append ("-yes ");
2217     cm.append (quoteFileName (file));
2218     command->setText(cm);
2219     command->setCursorIndex (SCursorIndex(0,10000));
2220     command->setFocus();
2221   }
2222   else
2223   {
2224     messagelabel->setMessage (translate ("open -yes -e encoding file"),
2225        SMessageLabel::SS_INFO);
2226     cm.append (quoteFileName (file));
2227     command->setText(cm);
2228     command->setCursorIndex (SCursorIndex(0,10000));
2229     command->putHistory(cm);
2230     SStringVector cv; cv.smartSplit (cm);
2231     load (cv, cm);
2232   }
2233   return true;
2234 }
2235 
2236 void
createPasswordDialog()2237 SYudit::createPasswordDialog () // If needed
2238 {
2239   if (passwordDialog) return;
2240 
2241   passwordDialog = new SPasswordDialog();
2242   passwordDialog->setModal (this);
2243   passwordDialog->setBackground (originalProperties["yudit.background"]);
2244   passwordDialog->setLabelForeground (originalProperties["yudit.label.foreground"]);
2245   passwordDialog->setTitleForeground (originalProperties["yudit.title.foreground"]);
2246   /* set the filetypes */
2247   SString font = originalProperties["yudit.default.font"];
2248   SString fontSizeString=originalProperties["yudit.default.fontsize"];
2249 
2250   double fontSize=0;
2251   fontSizeString.append ((char)0);
2252   sscanf (fontSizeString.array(), "%lf", &fontSize);
2253   if (fontSize < 2.0) fontSize = 2.0;
2254   passwordDialog->setFont (font, fontSize);
2255   SIcon* icon = SIconFactory::getIcon("Yudit");
2256   passwordDialog->setApplicationImage (icon->getImage ());
2257 }
2258 
2259 void
createFileDialog()2260 SYudit::createFileDialog () // If needed
2261 {
2262   if (fileDialog) return;
2263 
2264   fileDialog = new SFileDialog();
2265   fileDialog->setModal (this);
2266   fileDialog->setBackground (originalProperties["yudit.background"]);
2267   fileDialog->setLabelForeground (originalProperties["yudit.label.foreground"]);
2268   fileDialog->setTitleForeground (originalProperties["yudit.title.foreground"]);
2269   fileDialog->setSliderBackground (originalProperties["yudit.slider.background"]);
2270 
2271   SStringVector enc;
2272   if (originalProperties.get("yudit.editor.filetypes"))
2273   {
2274     //SString s = originalProperties["yudit.editor.filetypes"];
2275     //fprintf (stderr, "Specified filetypes: %*.*s\n", SSARGS (s));
2276     enc.append (SStringVector (originalProperties["yudit.editor.filetypes"]));
2277   }
2278   SBinHashtable<bool> ph;
2279   unsigned int ic=0;
2280 
2281   for (ic=0; ic<enc.size(); ic++)
2282   {
2283     ph.put (enc[ic], true);
2284   }
2285   SStringVector benc = SEncoder::builtin();
2286 
2287   unsigned int ib=0;
2288   for (ib=0; ib<benc.size(); ib++)
2289   {
2290     /* this is an input method and it is misleading. */
2291     if (benc[ib] == "unicode") continue;
2292     ph.put (benc[ib], true);
2293   }
2294   SStringVector bext = SEncoder::external();
2295 
2296   for (ib=0; ib<bext.size(); ib++)
2297   {
2298     /* this is an input method and it is misleading. */
2299     if (bext[ib].match("iso-8859*"))
2300     {
2301       ph.put (bext[ib], true);
2302     }
2303     if (bext[ib].match("mik"))
2304     {
2305       ph.put (bext[ib], true);
2306     }
2307     else if (bext[ib] == "viscii")
2308     {
2309       ph.put (bext[ib], true);
2310     }
2311     else if (bext[ib] == "wingreek")
2312     {
2313       ph.put (bext[ib], true);
2314     }
2315     else if (bext[ib] == "tcvn")
2316     {
2317       ph.put (bext[ib], true);
2318     }
2319     else if (bext[ib].match("koi8-*"))
2320     {
2321       ph.put (bext[ib], true);
2322     }
2323     else if (bext[ib] == "rovas")
2324     {
2325       ph.put (bext[ib], true);
2326     }
2327     else if (bext[ib] == "cp-1251")
2328     {
2329       ph.put (bext[ib], true);
2330     }
2331     else if (bext[ib] == "cp-1250")
2332     {
2333       ph.put (bext[ib], true);
2334     }
2335   }
2336 
2337   SStringVector addEnc;
2338   for (ic=0; ic<ph.size(); ic++)
2339   {
2340     for (ib=0; ib<ph.size(ic); ib++)
2341     {
2342        bool vle = ph.get (ic, ib);
2343        if (vle)
2344        {
2345          addEnc.append (ph.key (ic, ib));
2346        }
2347     }
2348   }
2349   /* set the filetypes */
2350   SString font = originalProperties["yudit.default.font"];
2351   SString fontSizeString=originalProperties["yudit.default.fontsize"];
2352 
2353   double fontSize=0;
2354   fontSizeString.append ((char)0);
2355   sscanf (fontSizeString.array(), "%lf", &fontSize);
2356   if (fontSize < 2.0) fontSize = 2.0;
2357   fileDialog->setFont (font, fontSize);
2358   fileDialog->setFileTypes (addEnc);
2359 
2360   SIcon* icon = SIconFactory::getIcon("Yudit");
2361   fileDialog->setApplicationImage (icon->getImage ());
2362 }
2363 
2364 void
createHighlightDialog()2365 SYudit::createHighlightDialog () // If needed
2366 {
2367   if (highlightDialog) return;
2368 
2369   highlightDialog = new SHighlightD();
2370   highlightDialog->setModal (this);
2371   highlightDialog->setBackground (originalProperties["yudit.background"]);
2372   highlightDialog->setLabelForeground (originalProperties["yudit.label.foreground"]);
2373   highlightDialog->setTitleForeground (originalProperties["yudit.title.foreground"]);
2374   highlightDialog->setSliderBackground (originalProperties["yudit.slider.background"]);
2375 
2376   /* set the filetypes */
2377   SString font = originalProperties["yudit.default.font"];
2378   SString fontSizeString=originalProperties["yudit.default.fontsize"];
2379   double fontSize=0;
2380   fontSizeString.append ((char)0);
2381   sscanf (fontSizeString.array(), "%lf", &fontSize);
2382   if (fontSize < 2.0) fontSize = 2.0;
2383   highlightDialog->setFont (font, fontSize);
2384 
2385   SIcon* icon = SIconFactory::getIcon("Yudit");
2386   highlightDialog->setApplicationImage (icon->getImage ());
2387 }
2388 
2389 void
createKMapDialog()2390 SYudit::createKMapDialog ()
2391 {
2392   if (kmapDialog) return;
2393   kmapDialog = new SKMapDialog ();
2394   kmapDialog->setModal (this);
2395   kmapDialog->setXInputs (originalProperties["yudit.editor.xinputs"]);
2396   kmapDialog->setBackground (originalProperties["yudit.background"]);
2397   kmapDialog->setLabelForeground (originalProperties["yudit.label.foreground"]);
2398   kmapDialog->setTitleForeground (originalProperties["yudit.title.foreground"]);
2399   kmapDialog->setSliderBackground (originalProperties["yudit.slider.background"]);
2400   /* set the filetypes */
2401   SString font = originalProperties["yudit.default.font"];
2402   SString fontSizeString=originalProperties["yudit.default.fontsize"];
2403 
2404   double fontSize=0;
2405   fontSizeString.append ((char)0);
2406   sscanf (fontSizeString.array(), "%lf", &fontSize);
2407   if (fontSize < 2.0) fontSize = 2.0;
2408   kmapDialog->setFont (font, fontSize);
2409   /* button size bug workaround */
2410   SDimension dim = kmapDialog->getPreferredSize();
2411   kmapDialog->resize(SDimension(dim.width+2, dim.height+2));
2412 
2413   SIcon* icon = SIconFactory::getIcon("Yudit");
2414   kmapDialog->setApplicationImage (icon->getImage ());
2415 }
2416 
2417 void
createTextDialog()2418 SYudit::createTextDialog ()
2419 {
2420   if (textDialog) return;
2421 
2422   textDialog = new STextDialog();
2423   textDialog->setModal (this);
2424 
2425   textDialog->setBackground (originalProperties["yudit.background"]);
2426   textDialog->setLabelForeground (originalProperties["yudit.label.foreground"]);
2427   textDialog->setTitleForeground (originalProperties["yudit.title.foreground"]);
2428 
2429   SString font = originalProperties["yudit.default.font"];
2430   SString fontSizeString=originalProperties["yudit.default.fontsize"];
2431 
2432   double fontSize=0;
2433   fontSizeString.append ((char)0);
2434   sscanf (fontSizeString.array(), "%lf", &fontSize);
2435   if (fontSize < 2.0) fontSize = 2.0;
2436 
2437   textDialog->setFont (font, fontSize);
2438 
2439   SIcon* icon = SIconFactory::getIcon("Yudit");
2440   textDialog->setApplicationImage (icon->getImage ());
2441 }
2442 
2443 /*
2444  * SFreeHandListener
2445  * FIXME:
2446  */
2447 void
freeHandTextChanged(void * source,const SString & lookup)2448 SYudit::freeHandTextChanged (void* source, const SString& lookup)
2449 {
2450   if (lookup.size()==0) return;
2451   if (editor->isFocused ())
2452   {
2453     editor->insertEditorText (lookup);
2454   }
2455   else if (command->isFocused())
2456   {
2457     command->insertEditorText (lookup);
2458   }
2459 }
2460 
2461 void
printl(const SLayout lo)2462 printl (const SLayout lo)
2463 {
2464   SLocation l = lo.getLocation();
2465   SDimension d = lo.getDimension();
2466   fprintf (stderr, "l= (%d,%d) d= (%u,%u)          l2 =(%d,%d)\n",
2467     l.x, l.y, d.width, d.height, l.x + (int) d.width, l.y + d.height);
2468 }
2469 
2470 bool
timeout(const SEventSource * s)2471 SYudit::timeout (const SEventSource* s)
2472 {
2473     if (s != deferredLoader) {
2474         return SFrame::timeout(s);
2475     }
2476     if (!deferredLoader) {
2477         return false;
2478     }
2479     editor->setEditable (true);
2480     if (isFirstLoad) {
2481         isFirstLoad = false;
2482         if (firstLoad.size()) {
2483             load (firstLoad, "");
2484         }
2485     }
2486     delete deferredLoader;
2487     deferredLoader = 0;
2488     // hacking, for X11 somehow focus is remembered.
2489     window->getKeyboardFocus();
2490     editor->setFocus ();
2491     return false;
2492 }
2493 
2494 void
showFreeHand(bool is)2495 SYudit::showFreeHand(bool is)
2496 {
2497   if (!(is ^ freeHandShown)) return;
2498   /* need to create */
2499   bool newhand = (freehand==0);
2500   freeHandShown = is;
2501   if (freehand==0)
2502   {
2503     freehand = new SFreeHand ();
2504     freehand->setBackground (originalProperties["yudit.background"]);
2505     freehand->setLabelForeground (originalProperties["yudit.label.foreground"], originalProperties["yudit.title.foreground"]);
2506     freehand->setForeground (originalProperties["yudit.title.foreground"], originalProperties["yudit.title.foreground"]);
2507     freehand->setDrawingForeground (SColor("green"), SColor("yellow"));
2508     freehand->setDrawingBackground (SColor("black"));
2509     freehand->setConverter (originalProperties["yudit.freehand.converter"]);
2510 
2511     freehand->setSliderBackground (
2512          originalProperties["yudit.slider.background"]);
2513     freehand->setFreeHandListener (this);
2514     SString font = originalProperties["yudit.default.font"];
2515     SString fontSize=originalProperties["yudit.default.fontsize"];
2516 
2517     double df=0;
2518     fontSize.append ((char)0);
2519     sscanf (fontSize.array(), "%lf", &df);
2520     if (fontSize < 2.0) df = 2.0;
2521     freehand->setButtonFont (font, df);
2522 
2523     font = toolbar->fonts[toolbar->currentFont];
2524     fontSize = toolbar->fontsizes[toolbar->currentFontSize];
2525     fontSize.append ((char)0);
2526 
2527     if (sscanf (fontSize.array(), "%lf", &df)==0 || df < 2.0) df = 2.0;
2528     freehand->setFont (font, df);
2529     freeHandHeight = freehand->getPreferredSize().height;
2530   }
2531 
2532   SLocation l = editorLayout.getLocation ();
2533   SDimension d = editorLayout.getDimension ();
2534   SLocation sl = sliderLayout.getLocation();
2535   SDimension sd = sliderLayout.getDimension();
2536   int hp = l.y + (int) d.height -(int)freeHandHeight;
2537 
2538   if (is)
2539   {
2540     editor->setLayout (
2541       SLayout (
2542        SLocation (l.x, l.y),
2543        SLocation (l.x+(int) d.width, hp),
2544         SLocation (0, 0),
2545         SLocation (100, 100)
2546       )
2547     );
2548     slider->setLayout (SLayout (
2549       SLocation (sl.x, sl.y),
2550       SLocation (sl.x+(int)sd.width, hp),
2551       SLocation (100, 0),
2552       SLocation (100, 100)
2553     ));
2554 
2555     freehand->setLayout (
2556       SLayout (
2557         SLocation (l.x, hp),
2558         SLocation (sl.x + (int) sd.width,
2559            hp+(int)freeHandHeight),
2560         SLocation (0, 100),
2561         SLocation (100, 100)
2562       )
2563     );
2564     SLocation ml = freehand->getLayout().getLocation (layout, getSize());
2565     SDimension md = freehand->getLayout().getDimension (layout, getSize());
2566   }
2567   else
2568   {
2569     editor->setLayout (editorLayout);
2570     slider->setLayout (sliderLayout);
2571     /* move it away */
2572     freehand->setLayout (
2573       SLayout (
2574         SLocation (l.x, -(int)hp -(int)freeHandHeight-1),
2575         SLocation (sl.x + (int) sd.width, -1),
2576         SLocation (0, 0),
2577         SLocation (0, 0)
2578       )
2579     );
2580   }
2581   if (newhand)
2582   {
2583     add (freehand);
2584     editor->setFocus();
2585   }
2586   _resized ();
2587 }
2588 
2589 /**
2590  * Try to prefix executable with mytool -pipecmd.
2591  * @return false if mytool not found.
2592  */
2593 bool
addMytoolPrefix(SString * executable)2594 SYudit::addMytoolPrefix (SString* executable)
2595 {
2596   if (executable->size()==0) return false;
2597 #ifdef USE_WINAPI
2598   SString pr = getPrefix();
2599   pr.append ("/bin/mytool.exe");
2600   SFile f (pr);
2601   if (f.size () <= 0)
2602   {
2603     SString message=translate ("Command not found: ");
2604     message.append (SS_LB_RLE);
2605     message.append ("'");
2606     message.append (pr);
2607     message.append ("'");
2608     message.append (SS_LB_PDF);
2609     messagelabel->setMessage (message, SMessageLabel::SS_ERR);
2610     return false;
2611   }
2612 #else
2613   SString pr = getPrefix();
2614   pr.append ("/bin/mytool");
2615   SFile f0 (pr);
2616   if (f0.size () <= 0)
2617   {
2618     pr = getPrefix();
2619     SStringVector pv(pr, "/");
2620     if (pv.size() > 1)
2621     {
2622       pv.truncate (pv.size()-2);
2623     }
2624     pr = pv.join ("/");
2625     pr.insert (0, "/");
2626     pr.append ("/bin/mytool");
2627     SFile f0 (pr);
2628     if (f0.size () <= 0)
2629     {
2630       SString message=translate ("Command not found: ");
2631       message.append (SS_LB_LRE);
2632       message.append ("'");
2633       message.append (pr);
2634       message.append ("'");
2635       message.append (SS_LB_PDF);
2636       messagelabel->setMessage (message, SMessageLabel::SS_ERR);
2637       return false;
2638     }
2639   }
2640 #endif
2641   SStringVector v;
2642   v.smartSplit (*executable);
2643   if (!commandExists (v[0]))
2644   {
2645     SString message=translate ("Command not found: ");
2646     message.append (SS_LB_LRE);
2647     message.append ("'");
2648     message.append (v[0]);
2649     message.append ("'");
2650     message.append (SS_LB_PDF);
2651     messagelabel->setMessage (message, SMessageLabel::SS_ERR);
2652     return false;
2653   }
2654   pr.insert (0, "\"");
2655   pr.append ("\"");
2656   pr.append (" -pipecmd ");
2657   executable->insert (0, pr);
2658   return true;
2659 }
2660 
2661 /**
2662  * Set the title to current filename.
2663  */
2664 void
setFileTitle()2665 SYudit::setFileTitle ()
2666 {
2667   SDir d;
2668   /* this will chop off filename */
2669   d.cd (currentFileName);
2670   SString dn = d.getName ();
2671   SString fn;
2672   SStringVector v(currentFileName, "/");
2673   if (v.size())
2674   {
2675     fn.append (v[v.size()-1]);
2676   }
2677 
2678   SString t = fn;
2679   // FIXME: do we need the directory?
2680   dn = "";
2681   if (dn.size () > 0)
2682   {
2683     t.append (" (");
2684     t.append (dn);
2685     t.append (")");
2686   }
2687   t.append ("  Yudit-");
2688   t.append (SD_YUDIT_VERSION);
2689   setTitle (t);
2690 }
2691 
2692 /**
2693  * Translate our string highlight mode to an integer
2694  * @return -1 if it can not be translated.
2695  */
2696 static SString
translateHighlightMode(const SString & hl)2697 translateHighlightMode (const SString& hl)
2698 {
2699   if (hl == "none" || hl == "simple" || hl == "simple-dark")
2700   {
2701     return SString(hl);
2702   }
2703   if (SSyntax::isSupported (hl)) return SString(hl);
2704   return SString("");
2705 }
2706 
2707 /**
2708  * \return negative on fail or the number if it is specified
2709  *  as +NUMBER.
2710  */
2711 static int
getLineNumber(const SString & s)2712 getLineNumber (const SString& s)
2713 {
2714   if (s.size() < 2 || s.peek(0) != '+') return -1;
2715   int line = 0;
2716   for (unsigned int i=1; i<s.size(); i++)
2717   {
2718     if (s.peek(i) >= '0' && s.peek(i) <= '9')
2719     {
2720       if (line < 100000000)
2721       {
2722         line = line * 10;
2723         line += (s.peek(i) - '0');
2724       }
2725     }
2726     else
2727     {
2728       return -1;
2729     }
2730   }
2731   return line;
2732 }
2733 
getPrintHelp()2734 static SString getPrintHelp ()
2735 {
2736    SString pstr =
2737      translate ("usage: print [-o file] [-p printer] [-e exec] [-break] [-hsize header-font-size]");
2738   pstr.append (" [-m A4] [-L]");
2739   return SString (pstr);
2740 }
2741