editor.cpp

来自「FreeFem++可以生成高质量的有限元网格。可以用于流体力学」· C++ 代码 · 共 474 行

CPP
474
字号
// -*- Mode : c++ -*-//// SUMMARY  :      // USAGE    :        // ORG      : // AUTHOR   : Antoine Le Hyaric -// E-MAIL   : lehyaric@ann.jussieu.fr///*  This file is part of Freefem++  Freefem++ is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.  Freefem++  is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.  You should have received a copy of the GNU Lesser General Public License along with Freefem++; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */// Editor functions// ----------------// Antoine Le Hyaric - LJLL Paris 6 - lehyaric@ann.jussieu.fr - 21/10/04// $Id: editor.cpp,v 1.13 2006-09-29 20:30:15 hecht Exp $#ifdef __MINGW32__#include <io.h> // chdir()#endif#include <errno.h> // errno on MacOs X#include <unistd.h> // chdir() on RedHat#include <cassert>#include <iostream>using namespace std;#include <FL/fl_file_chooser.H>#include "tostring.hpp"#include "spawn.hpp"#include "editor.hpp"#include "highlight.hpp"// Reference to main windowFl_Double_Window *mainwindow=NULL;// Tracking changes in the editor windowbool filecurrentlyloading=false;bool editorcontentchanged=false;// filename of the currently edited filestring filename;// Editor windowEditor::Editor(int x,int y,int w,int h,const char *label):  Fl_Text_Editor(x,y,w,h,label),dragndrop(false){}// Catches the mouse drag'n'drop eventsint Editor::handle(int event){  switch(event){  case FL_DND_ENTER:    // Tell FLTK that we want to know about drag'n'drop events    dragndrop=true;    return 1;  case FL_DND_DRAG:    // Tell FLTK (again!) that we want to know about drag'n'drop    // events    dragndrop=true;    return 1;  case FL_DND_RELEASE:    // We want to receive the corresponding data (sent to us via an    // FL_PASTE event)    dragndrop=true;    return 1;  case FL_DND_LEAVE:    dragndrop=false;    return 1;  case FL_PASTE:    // If there was no FL_DND_RELEASE, we don't know what to do with    // the pasted text. So we leave the above class deal with it.    if(!dragndrop) return Fl_Text_Editor::handle(event);    else {      dragndrop=false;      // The event text contains whatever the other application      // (Microsoft Internet Explorer, Mozilla, ...) sent. So we need      // to do some guesswork.      string file=Fl::event_text();      // Mozilla sometimes sends wide characters. We need to convert      // them back to regular (short) ones. We may loose some      // information in the process, but filenames should only use      // regular characters anyway.      if(Fl::event_length()>1 && file[1]==0){	const char *w=Fl::event_text();	file="";	while(w < Fl::event_text()+Fl::event_length()){	  file+=tostring(*w);	  w+=2;	}      }      // Internet browsers and file managers like to add "file:/" or      // "file://" before file paths      if(file.substr(0,5)=="file:") file.erase(0,5);      // There may be some extra "/" at the beginning, for instance      // if the format was "file://...".      while(file.substr(0,2)=="//") file.erase(0,1);      // Internet browsers (e.g. Firefox for Microsoft Windows) may      // also represent the drive letter as a directory (e.g. "/c:/")      if(file.size()>=4 && file[0]=='/' && file.substr(2,2)==":/")	file.erase(0,1);      // Drag'n'drop data may contain more than a filename. We just      // discard everything.      string::size_type cr=file.find('\n');      if(cr!=string::npos) file[cr]='\0';      if (discardcurrentfile()) readfile(file.c_str());    }    return 1;  default:    return Fl_Text_Editor::handle(event);  }  // The default treatment is to indicate that we are not interested  // in an event.  return 0;}// Reference to editor windowEditor *editor=NULL;Fl_Text_Buffer *editorbuffer=NULL;string mainwindowtitle;void setwindowtitle(){  mainwindowtitle="FreeFem++";  if(filename!="") mainwindowtitle+=string(" ")+filename;  if (editorcontentchanged) mainwindowtitle+=" (modified)";  mainwindow->label(mainwindowtitle.c_str());}void textchanged(int,int inserted,int deleted,int,const char*,void*){  if((inserted||deleted) && !filecurrentlyloading) editorcontentchanged=true;  setwindowtitle();  if(filecurrentlyloading) editor->show_insert_position();}// copy/pastevoid copy(Fl_Widget*,void*){Fl_Text_Editor::kf_copy(0,editor);}void cut(Fl_Widget*,void*){Fl_Text_Editor::kf_cut(0,editor);}void deletetext(Fl_Widget*,void*){editorbuffer->remove_selection();}void paste(Fl_Widget*,void*){Fl_Text_Editor::kf_paste(0,editor);}// findstring searchstring;void find(Fl_Widget*,void*);void findagain(Fl_Widget*,void*){  if(searchstring=="") find(NULL,NULL);  else{    int pos=editor->insert_position();    if(editorbuffer->search_forward(pos,searchstring.c_str(),&pos)){      editorbuffer->select(pos,pos+searchstring.size());      editor->insert_position(pos+searchstring.size());      editor->show_insert_position();    }    else fl_alert("\'%s\' not found!",searchstring.c_str());  }}void find(Fl_Widget*,void*){  const char *f=fl_input("Search string:",searchstring.c_str());  if(f!=NULL){    searchstring=f;    findagain(NULL,NULL);  }}// replaceFl_Window *replacedialog;Fl_Input *replacedialogfind;Fl_Input *replacedialogwith;Fl_Button *replacedialogall;Fl_Button *replacedialognext;Fl_Button *replacedialogcancel;void replace(Fl_Widget*,void*){  replacedialog->show();}void replaceagain(Fl_Widget*,void*){  string find=replacedialogfind->value();  if(find=="") replacedialog->show();  else{    string replace=replacedialogwith->value();    replacedialog->hide();    int pos=editor->insert_position();    if (editorbuffer->search_forward(pos,find.c_str(),&pos)){      editorbuffer->select(pos,pos+find.size());      editorbuffer->remove_selection();      editorbuffer->insert(pos,replace.c_str());      editorbuffer->select(pos,pos+replace.size());      editor->insert_position(pos+replace.size());      editor->show_insert_position();    }    else fl_alert("No occurrences of \'%s\' found!",find.c_str());  }}void replaceall(Fl_Widget*,void*){  string find=replacedialogfind->value();  if(find=="") replacedialog->show();  else{    string replace=replacedialogwith->value();    replacedialog->hide();    editor->insert_position(0);    // Did we find at least one occurrence?    bool foundone=false;    int found=1;    while(found){      int pos=editor->insert_position();      found=editorbuffer->search_forward(pos,find.c_str(),&pos);      if (found){	editorbuffer->select(pos,pos+find.size());	editorbuffer->remove_selection();	editorbuffer->insert(pos,replace.c_str());	editor->insert_position(pos+replace.size());	editor->show_insert_position();	foundone=true;      }    }    if(!foundone) fl_alert("\'%s\' not found!",find.c_str());  }}void replacecancel(Fl_Widget*,void*){  replacedialog->hide();}// file managementvoid savefile(Fl_Widget*,void*);void stopfreefemserver(Fl_Widget*,void*);bool discardcurrentfile(){  // Checks whether the FreeFem++ server is currently running.  freefemthreadcomm.WAIT();  bool running=freefemrunning;  freefemthreadcomm.Free();  if(running && fl_ask("Cancel current FreeFem++ computation?")!=1)    return false;  if(running) stopfreefemserver(NULL,NULL);  // Checks whether the editor contains anything to save  if (!editorcontentchanged) return true;  else{    int r=fl_choice("Save current file?","Cancel","Save","Discard");    switch(r){    case 2:// Discard      return true;    case 1:// Save      savefile(NULL,NULL);      return !editorcontentchanged;    case 0:// Cancel      return false;    default:      assert(false);      return false;    }  }}void newfile(Fl_Widget*,void*){  if(discardcurrentfile()){    filename="";    editorbuffer->select(0,editorbuffer->length());    editorbuffer->remove_selection();    editorcontentchanged=false;    editorbuffer->call_modify_callbacks();  }}// Do not use 'basename' or 'dirname', which are not available on some// platforms (e.g. Cygwin).void splitpath(const string path,string &dir,string &base){  // Find the last '/' or '\' in the path  string::size_type forwardslash=path.rfind('/',path.size());  string::size_type backwardslash=path.rfind('\\',path.size());  string::size_type slash=string::npos;  if(forwardslash!=string::npos) slash=forwardslash;  if(backwardslash!=string::npos) slash=backwardslash;  if(forwardslash!=string::npos && backwardslash!=string::npos)    slash=max(forwardslash,backwardslash);  // Split into directory and filename  dir="";  base=path;  if(slash!=string::npos){    // Always keeps the final slash in the directory name because "c:"    // and "c:\" do not have the same meaning under Microsoft Windows.    dir=path.substr(0,slash+1);    if(slash<path.size()-1) base=path.substr(slash+1,path.size()-slash-1);  }}// We change the default directory to be the one where the file is,// just for "include" directives to work properly.void changedir(){  string dir,base;  splitpath(filename,dir,base);  // Record new values  if(dir!=""){#ifndef NDEBUG    cerr<<"client: changing directory to \""<<dir<<"\""<<endl;#endif    chdir(dir.c_str());    messagebar->value((string("Current directory set to ")+dir).c_str());#ifndef NDEBUG    cerr<<"client: edp file base name is \""<<base<<"\""<<endl;#endif    filename=base;  }}void readfile(const string file){  filecurrentlyloading=true;  filename=file;  editorcontentchanged=false;  changedir();  if (editorbuffer->loadfile(filename.c_str()))    fl_alert("Error reading file \'%s\':\n%s.",	     filename.c_str(),strerror(errno));#if !defined(__MINGW32__)  // When not under plain Microsoft Windows (i.e. Mingw, not Cygwin),  // FLTK does not understand Windows CRLF codes. So we need to  // replace them with one regular LF.  int i=0;  while(i<editorbuffer->length()){    if(editorbuffer->character(i)=='\r') editorbuffer->remove(i,i+1);    else i++;  }#endif  filecurrentlyloading=false;  editorbuffer->call_modify_callbacks();}void writefile(const string file){  filename=file;  editorcontentchanged=false;  changedir();  if (editorbuffer->savefile(filename.c_str()))    fl_alert("Error writing file \'%s\':\n%s.",	     filename.c_str(),strerror(errno));  editorbuffer->call_modify_callbacks();}void openfile(Fl_Widget*,void*){  if (discardcurrentfile()){    char *newfile=fl_file_chooser("Open file?","*",filename.c_str());    if(newfile) readfile(newfile);  }}void savefileas(){  char *newfile=fl_file_chooser("Save file as?","*",filename.c_str());  if(newfile) writefile(newfile);}void savefile(Fl_Widget*,void*){  if(filename=="") savefileas();  else writefile(filename);}void quit(Fl_Widget*,void*){  if(discardcurrentfile()){    mainwindow->hide();    exit(0);  }}Fl_Text_Buffer *highlightbuffer;// Semaphore controlling when the editor text should be// re-highlighted.Semaphore highlightflag(0,1,"highlight");// Background thread for highlight computationsTHREADFUNC(computehighlight,){  try{    // Infinite loop to compute as many highlights as necessary    while(1){      // Wait for some work to do      highlightflag.Decr();#ifndef NDEBUG      cerr<<"client: running highlighting procedure\n";#endif      // Read the data to highlight from the editor      Fl::lock();      char *text=editorbuffer->text();      lexinput=text;      free(text);      Fl::unlock();      // Run the highlighting procedure (we do not care about any      // error return code: erroneous characters will be displayed      // with a special color anyway).      my_parse();      // Only replace the highlighting codes if the buffer contents      // are still close enough to what we worked with.      Fl::lock();      if(highlight.size()==editorbuffer->length()){	highlightbuffer->text(highlight.c_str());	editor->redisplay_range(0,editorbuffer->length());      }#ifndef NDEBUG      else cerr<<"client: highlight data size="<<highlight.size()	       <<" not equal to text size="<<editorbuffer->length()<<endl;#endif      Fl::unlock();      Fl::awake();    }  }  catch(string explanation){    cerr<<"client: exception in computehighlight thread:"<<endl	<<explanation<<endl;  }  return 0;}// Call the highlighting procedure for each modified part of the edited textvoid updatehighlight(int,int,int,int,const char *,void *){  // Just ask the highlighting thread (computehighlight()) to work on  // this  highlightflag.Incr();}void inithighlight(){  // The Lex+Yacc grammar  inithighlightparser();  // Start the highlighting thread  Thread::Start(computehighlight,NULL);}void unfinishedhighlight(int,void*){}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?