COOPY » Guide  version 0.6.5
/home/paulfitz/cvs/coopy_scm/coopy/src/gui/src/coopy.cpp
Go to the documentation of this file.
00001 // -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*-
00002 
00003 /*
00004  * Copyright (C) 2010 Paul Fitzpatrick
00005  * CopyPolicy: Released under the terms of the GNU GPL v2.0.
00006  *
00007  */
00008 
00009 // wxwidgets library version issue
00010 #ifdef __APPLE__
00011 #ifdef NDEBUG
00012 #undef NDEBUG
00013 #endif
00014 #endif
00015 
00016 #include <wx/wx.h>
00017 #include <wx/wxprec.h>
00018 #include <wx/dcbuffer.h>
00019 #include <wx/image.h>
00020 #include <wx/cmdline.h>
00021 #include <wx/dirdlg.h>
00022 #include <wx/textdlg.h>
00023 #include <wx/filefn.h>
00024 #include <wx/filename.h>
00025 #include <wx/file.h>
00026 #include <wx/textfile.h>
00027 #include <wx/textctrl.h>
00028 #include <wx/url.h>
00029 #include <wx/filepicker.h>
00030 #include <wx/process.h>
00031 #include <wx/stdpaths.h>
00032 #include <wx/txtstrm.h>
00033 #include <wx/arrstr.h>
00034 #include <wx/dir.h>
00035 #include <wx/listctrl.h>
00036 #include <wx/regex.h>
00037 
00038 #include <string>
00039 #include <list>
00040 #include <map>
00041 #include <iostream>
00042 
00043 #include <unistd.h>
00044 
00045 #include <coopy/Dbg.h>
00046 #include <coopy/Options.h>
00047 
00048 #include "MergeFrame.h"
00049 
00050 static bool verb() { return coopy_is_verbose(); }
00051 
00052 // hack to remove warning
00053 #define static const
00054 #include "icon/appicon.xpm"
00055 #undef static
00056 
00057 #define SITE_NAME "share.find.coop"
00058 #define SITE_NAME_CREATE "http://share.find.coop/repo/new"
00059 
00060 using namespace std;
00061 
00062 //long int g_hinstance = 0;
00063 //long int g_hwnd = 0;
00064 
00065 #include "WideSheetManager.h"
00066 
00067 static wxString conv_c(const char *s) {
00068     return wxString(s, wxConvUTF8);
00069 }
00070 
00071 static wxString conv(const std::string& s) {
00072     return wxString(s.c_str(), wxConvUTF8);
00073 }
00074 
00075 static std::string conv(const wxString& s) {
00076     return std::string(s.mb_str(wxConvUTF8));
00077 } 
00078 
00079 
00080 static void show(const wxString& view) {
00081 #ifndef WIN32
00082     wxString view2 = wxT("file://") + view;
00083     ::wxLaunchDefaultBrowser(view2);
00084 #else
00085     ::wxLaunchDefaultBrowser(view);
00086 #endif
00087 }
00088 
00089 static void show(const std::string& view) {
00090     wxString x = conv(view);
00091     show(x);
00092 }
00093 
00094 
00095 class CoopyApp: public wxApp {
00096 public:
00097     CoopyApp() {
00098         silent = false;
00099         force_happy = false;
00100     }
00101 
00102     virtual bool OnInit();
00103 
00104     virtual int OnRun() {
00105         if (!force_happy) {
00106             return wxApp::OnRun();
00107         }
00108         return 0;
00109     }
00110 
00111     virtual void OnInitCmdLine(wxCmdLineParser& parser);
00112     virtual bool OnCmdLineParsed(wxCmdLineParser& parser);
00113 
00114     static string fossil_object;
00115     static string fossil_action;
00116     static string fossil_message;
00117     static string fossil_key;
00118     static string fossil_repo;
00119     static string fossil_target;
00120     static bool fossil_autoend;
00121     static bool silent;
00122     static int fossil_result;
00123     static bool force_happy;
00124     static wxFrame *store_frame;
00125     static MergeFrame *store_mframe;
00126     static CoopyApp *store_app;
00127 
00128     void OnKey(wxKeyEvent&);
00129 
00130     DECLARE_EVENT_TABLE()
00131 };
00132 
00133 BEGIN_EVENT_TABLE(CoopyApp, wxApp)
00134   EVT_KEY_DOWN(CoopyApp::OnKey)
00135 END_EVENT_TABLE()
00136 
00137 string CoopyApp::fossil_object;
00138 string CoopyApp::fossil_action;
00139 string CoopyApp::fossil_message;
00140 string CoopyApp::fossil_key;
00141 string CoopyApp::fossil_repo;
00142 string CoopyApp::fossil_target;
00143 bool CoopyApp::fossil_autoend = false;
00144 bool CoopyApp::silent = false;
00145 bool CoopyApp::force_happy = false;
00146 int CoopyApp::fossil_result = 0;
00147 wxFrame *CoopyApp::store_frame = NULL;
00148 MergeFrame *CoopyApp::store_mframe = NULL;
00149 CoopyApp *CoopyApp::store_app = NULL;
00150 
00151 static const wxCmdLineEntryDesc g_cmdLineDesc [] = {
00152     { wxCMD_LINE_SWITCH, wxT("h"), wxT("help"), wxT("displays help on the command line parameters") },
00153     { wxCMD_LINE_SWITCH, wxT("H"), wxT("help-dox"), wxT("prepare doxygen help") },
00154     //wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
00155     { wxCMD_LINE_SWITCH, wxT("g"), wxT("gui"), wxT("force show GUI") },
00156     { wxCMD_LINE_SWITCH, wxT("n"), wxT("new"), wxT("new repository") },
00157     { wxCMD_LINE_OPTION, wxT("c"), wxT("clone"), wxT("clone repository"),
00158       wxCMD_LINE_VAL_STRING, 0  },
00159     { wxCMD_LINE_SWITCH, wxT("v"), wxT("verbose"), wxT("show debug information") },
00160     { wxCMD_LINE_SWITCH, wxT("l"), wxT("silent"), wxT("keep it quiet") },
00161     //{ wxCMD_LINE_OPTION, wxT("r"), wxT("res"), wxT("set resource location"),
00162     //wxCMD_LINE_VAL_STRING, 0  },
00163     { wxCMD_LINE_SWITCH, wxT("p"), wxT("pull"), wxT("pull in data") },
00164     { wxCMD_LINE_SWITCH, wxT("s"), wxT("push"), wxT("push out data") },
00165     { wxCMD_LINE_OPTION, wxT("k"), wxT("key"), wxT("key for adding/export"),
00166       wxCMD_LINE_VAL_STRING, 0  },
00167     { wxCMD_LINE_OPTION, wxT("r"), wxT("repo"), wxT("repository link"),
00168       wxCMD_LINE_VAL_STRING, 0  },
00169     { wxCMD_LINE_OPTION, wxT("a"), wxT("add"), wxT("add a spreadsheet/database"),
00170       wxCMD_LINE_VAL_STRING, 0  },
00171     { wxCMD_LINE_OPTION, wxT("e"), wxT("export"), wxT("export a spreadsheet/database"),
00172       wxCMD_LINE_VAL_STRING, 0,
00173     },
00174     { wxCMD_LINE_OPTION, wxT("m"), wxT("message"), wxT("message for log"),
00175       wxCMD_LINE_VAL_STRING, 0  },
00176     { wxCMD_LINE_PARAM, NULL, NULL, wxT("input file"), wxCMD_LINE_VAL_STRING,
00177       wxCMD_LINE_PARAM_OPTIONAL },
00178     { wxCMD_LINE_SWITCH, wxT("d"), wxT("delay"), wxT("add fossil delay") },
00179     { wxCMD_LINE_NONE },
00180 };
00181 
00182 
00183 void CoopyApp::OnInitCmdLine(wxCmdLineParser& parser) {
00184     parser.SetDesc (g_cmdLineDesc);
00185     // must refuse '/' as parameter starter or cannot use "/path" style paths
00186     parser.SetSwitchChars (wxT("--"));
00187 }
00188  
00189 bool CoopyApp::OnCmdLineParsed(wxCmdLineParser& parser) {
00190     bool help = parser.Found(wxT("h"));
00191     bool help_dox = parser.Found(wxT("H"));
00192     if (help||help_dox) {
00193         coopy::app::Options opt("coopy");
00194         if (help_dox) {
00195             opt.setBool("help-doxygen",true);
00196         }
00197         opt.setBool("show-patch",false);
00198         opt.setBool("show-input-format",false);
00199         opt.beginHelp();
00200         opt.addUsage("coopy [options]");
00201         opt.addUsage("coopy [options] DIRECTORY");
00202         opt.addDescription("Manage a repository of spreadsheets and databases. Usually run without options, for a graphical interface.");
00203         opt.showOptions(OPTION_FOR_COOPY);
00204         opt.addExample("coopy",
00205                        "run the coopy GUI from the current directory. All the actions in these examples can be achieved from the GUI.");
00206         opt.addExample("coopy --new",
00207                        "create a new empty repository in the current directory.");
00208         opt.addExample("coopy --key=people --add=people.xls",
00209                        "add people.xls to the repository, with key 'people'.");
00210         opt.addExample("coopy --key=orgs --export=organizations.sqlite",
00211                        "export organizations.sqlite from the repository, with key 'orgs'.");
00212         opt.endHelp();
00213         force_happy = true;
00214         return true;
00215     }
00216 
00217     silent = parser.Found(wxT("l"));
00218 
00219     //wxString location;
00220     //if (parser.Found(wxT("r"),&location)) {
00221     //string loc = conv(location);
00222     //  printf("*** should set resource location to [%s]\n", loc.c_str());
00223     //}
00224     wxString message, key;
00225     if (parser.Found(wxT("k"),&key)) {
00226         fossil_key = conv(key);
00227     }
00228     if (parser.Found(wxT("n"))) {
00229         fossil_action = "new";
00230     }
00231     if (parser.Found(wxT("d"))) {
00232         // command-line use of coopy currently can run into trouble
00233         // with timestamps if commands issued in quick succession
00234 #ifdef __WIN32__
00235         Sleep(1000);
00236 #else
00237         sleep(1);
00238 #endif
00239     }
00240     if (parser.Found(wxT("c"),&key)) {
00241         fossil_action = "clone";
00242         wxURL url = key;
00243         if (!url.HasScheme()) {
00244             wxFileName name = wxFileName::FileName(key);
00245             name.MakeAbsolute();
00246             fossil_target = conv(name.GetFullPath());
00247         } else {
00248             fossil_target = conv(key);
00249         }
00250     }
00251     if (parser.Found(wxT("r"),&key)) {
00252         fossil_repo = conv(key);
00253     }
00254     if (parser.Found(wxT("m"),&message)) {
00255         fossil_message = conv(message);
00256     }
00257     if (parser.Found(wxT("a"),&message)) {
00258         fossil_action = "add";
00259         wxFileName name = wxFileName::FileName(message);
00260         name.MakeAbsolute();
00261         fossil_message = conv(name.GetFullPath());
00262     }
00263     if (parser.Found(wxT("e"),&message)) {
00264         fossil_action = "export";
00265         wxFileName name = wxFileName::FileName(message);
00266         name.MakeAbsolute();
00267         fossil_message = conv(name.GetFullPath());
00268     }
00269     if (parser.Found(wxT("p"))) {
00270         fossil_action = "pull";
00271     }
00272     if (parser.Found(wxT("s"))) {
00273         fossil_action = "push";
00274     }
00275     if (parser.Found(wxT("v"))) {
00276         coopy_set_verbose(true);
00277     }
00278     fossil_autoend = false;
00279     if (fossil_action!="") {
00280         fossil_autoend = !parser.Found(wxT("g"));
00281         if (fossil_autoend) {
00282             silent = true;
00283         }
00284     }
00285     
00286     // to get at your unnamed parameters use
00287     wxArrayString files;
00288     for (size_t i = 0; i < parser.GetParamCount(); i++) {
00289         files.Add(parser.GetParam(i));
00290     }
00291 
00292     if (files.size()>0) {
00293         fossil_object = conv(files[0]);
00294     }
00295     
00296     // and other command line parameters
00297 
00298     // then do what you need with them.
00299     
00300     return true;
00301 }
00302 
00303 #ifdef WIN32
00304 IMPLEMENT_APP_NO_MAIN(CoopyApp);
00305 #else
00306 IMPLEMENT_APP(CoopyApp);
00307 #endif
00308 
00309 
00310 class CoopyFrame: public wxFrame
00311 {
00312     DECLARE_CLASS(CoopyFrame)
00313     DECLARE_EVENT_TABLE()
00314 
00315 public:
00316     bool background;
00317 
00318 private:
00319     wxBoxSizer *topsizer;
00320     //wxTextCtrl* m_textCtrl;
00321 
00322     wxTextCtrl *log_box;
00323     wxTextCtrl *src_box;
00324     wxTextCtrl *dest_box;
00325     wxDirPickerCtrl *dir_box;
00326     string dir_box_path;
00327     wxTimer *timer;
00328     wxListBox *list_box;
00329     wxInputStream *report;
00330     wxInputStream *reportErr;
00331 
00332     WideSheetManager ws;
00333 
00334     //UiFossilHandler handler; 
00335 
00336     bool askPath;
00337     bool askSource;
00338     bool askDestination;
00339 
00340     string path;
00341     string source;
00342     string destination;
00343     string commit_message;
00344     string fossil_path;
00345     ostream *stream;
00346     string next;
00347     string retry;
00348     bool logging;
00349     bool showing;
00350     bool writeAuthorizationFailed;
00351     bool writeWouldFork;
00352     wxString autoSyncTip;
00353     wxString projectCodeTip;
00354     list<string> results;
00355     list<string> fileCache;
00356     list<string> updateCache;
00357 
00358     void split(const string& str, 
00359                const string& delimiters, 
00360                list<string>& tokens) {
00361         size_t lastPos = str.find_first_not_of(delimiters, 0);
00362         size_t pos = str.find_first_of(delimiters, lastPos);
00363         while (string::npos != pos || string::npos != lastPos) {
00364             tokens.push_back(str.substr(lastPos, pos - lastPos));
00365             lastPos = str.find_first_not_of(delimiters, pos);
00366             pos = str.find_first_of(delimiters, lastPos);
00367         }
00368     }
00369 
00370     void beginLog() {
00371         results.clear();
00372         logging = true;
00373     }
00374 
00375     list<string> endLog() {
00376         list<string> r = results;
00377         results.clear();
00378         logging = false;
00379         return r;
00380     }
00381 
00382     void replace(std::string& str, const std::string& old, 
00383                  const std::string& rep) {
00384         size_t pos = 0;
00385         while((pos = str.find(old, pos)) != std::string::npos) {
00386             str.replace(pos, old.length(), rep);
00387             pos += rep.length();
00388         }
00389     }
00390 
00391     string safetxt(const char *txt) {
00392         string str(txt);
00393         //replace(str," ","\\ ");
00394 #ifdef WIN32
00395         replace(str,"\\","/");
00396 #endif
00397 #ifdef WIN32
00398         str = string("\"") + str + "\"";
00399 #endif
00400         return str;
00401     }
00402 
00403 public:
00404 
00405     CoopyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
00406 
00407     void OnQuit(wxCommandEvent& event);
00408     void OnAbout(wxCommandEvent& event);
00409 
00410     void OnExit(wxCloseEvent& event) {
00411         Destroy();
00412     }
00413 
00414     void OnReset(wxCommandEvent& event);
00415 
00416     virtual bool OnInit();
00417 
00418     void OnSync(wxCommandEvent& event);
00419     void OnPush(wxCommandEvent& event);
00420     void OnCommit(wxCommandEvent& event);
00421     void OnCreate(wxCommandEvent& event);
00422     bool OnCreateRepo(wxCommandEvent& event);
00423     bool OnCloneRepo(wxCommandEvent& event);
00424     bool OnOpenRepo(bool back = true);
00425     void OnUndo(wxCommandEvent& event);
00426 
00427     void OnDiff(wxCommandEvent& event);
00428     void OnPatch(wxCommandEvent& event);
00429     void OnMerge(wxCommandEvent& event);
00430     void OnDiffPatchMerge(wxCommandEvent& event);
00431 
00432     bool havePath();
00433     bool haveSource();
00434     bool haveDestination();
00435 
00436     char *fossil() {
00437         if (fossil_path=="") {
00438             wxFileName name = wxFileName::FileName(wxStandardPaths::Get().GetExecutablePath());
00439             name.SetName(_T("ssfossil"));
00440             fossil_path = conv(name.GetFullPath());
00441         }
00442         return (char*)fossil_path.c_str();
00443     }
00444 
00445     int ssfossil(int argc, char *argv[], bool sync=false);
00446 
00447     void OnProgressTimer(wxTimerEvent& WXUNUSED(event)) {
00448         //printf("Tick!\n");
00449         processInput();
00450     }
00451 
00452     void processSubInput(wxInputStream& in) {
00453         wxTextInputStream tis(in);
00454         wxString str = tis.ReadLine();
00455         //printf("Got %s\n", conv(str).c_str());
00456         //replace(str,string("\r"),string(" * "));
00457         //replace(str,"Received:","\nReceived:");
00458         if (logging) { 
00459             //printf("Logging\n");
00460             string cp(conv(str));
00461             split(cp,"\n",results);
00462             //printf("Logged\n");
00463         }
00464         //wxString n = conv(next);
00465         addLog(str);
00466     }
00467 
00468     void processInput() {
00469         while (report->CanRead()) {
00470             processSubInput(*report);
00471         }
00472         while (reportErr->CanRead()) {
00473             processSubInput(*reportErr);
00474         }
00475     }
00476 
00477     void addLog(const wxString& str, bool force = false) {
00478         if (verb()) {
00479             string s = conv(str);
00480             printf(">>> %s\n", s.c_str());
00481         }
00482         /*
00483         char buf[256];
00484         sprintf(buf,"[%d]", (int)str[0]);
00485         log_box->AppendText(wxT(">>>"));
00486         log_box->AppendText(str);
00487         log_box->AppendText(wxT("--"));
00488         log_box->AppendText(conv(string(buf)));
00489         log_box->AppendText(wxT("\n"));
00490         */
00491 
00492         if (str.Contains(wxT("Autosync: "))) {
00493             autoSyncTip = str.Mid(wxString(wxT("Autosync: ")).Len());
00494             autoSyncTip.Trim(false);
00495             autoSyncTip.Trim(true);
00496         }
00497         if (str.Contains(wxT("Server: "))) {
00498             autoSyncTip = str.Mid(wxString(wxT("Server: ")).Len());
00499             autoSyncTip.Trim(false);
00500             autoSyncTip.Trim(true);
00501         }
00502         if (str.Contains(wxT("project-code: "))) {
00503             projectCodeTip = str.Mid(wxString(wxT("project-code: ")).Len());
00504             projectCodeTip.Trim(false);
00505             projectCodeTip.Trim(true);
00506         }
00507         if (str.Contains(wxT("not authorized to write"))) {
00508             writeAuthorizationFailed = true;
00509         }
00510         if (str.Contains(wxT("would fork"))) {
00511             writeWouldFork = true;
00512         }
00513         if (str.Contains(wxT("login failed"))) {
00514             writeAuthorizationFailed = true;
00515         }
00516 
00517         bool needed = false;
00518         if (str.Contains(wxT("Error: "))) {
00519             needed = true;
00520         }
00521 
00522         if (showing||force||needed) {
00523             bool ok = true;
00524             if ((str[0]>='0'&&str[0]<='9')||str[0]<32) {
00525                 ok = false;
00526             }
00527             if (force) ok = true;
00528             if (ok) {
00529                 log_box->AppendText(str);
00530                 log_box->AppendText(_T("\n"));
00531                 Update();
00532                 log_box->SetSelection(log_box->GetLastPosition(),-1);
00533                 string s = conv(str);
00534                 const char *at = s.c_str();
00535                 while (at[0]=='\n'||at[0]==' ') at++;
00536                 printf("%s\n", at);
00537             }
00538         } 
00539     }
00540 
00541     void addLogFile(const wxFileName& fn) {
00542         string sfn = conv(fn.GetFullPath());
00543         //printf("Adding log file %s\n", sfn.c_str());
00544         wxTextFile f;
00545         if (!f.Open(fn.GetFullPath())) return;
00546         for (wxString str = f.GetFirstLine(); 
00547              !f.Eof(); 
00548              str = f.GetNextLine()) {
00549             addLog(str,true);
00550         }
00551     }
00552 
00553     void CheckEnd() {
00554         if (CoopyApp::fossil_autoend) {
00555             if (CoopyApp::fossil_action!="") {
00556                 wxCloseEvent ev;
00557                 OnExit(ev);
00558             }
00559         }
00560     }
00561 
00562     void OnTerminate(wxProcess *process, int status) {
00563         //printf("OnTerminate! next is [%s]\n", next.c_str());
00564         processInput();
00565         timer->Stop();
00566         showing = true;
00567         bool fail = false;
00568         if (status!=0) {
00569             addLog(wxT("TROUBLE in CoopyTown..."));
00570             if (!writeWouldFork) {
00571                 addLog(wxT("* Is repository link valid?"));
00572             }
00573             //addLog(wxString(wxT("  => ")) + conv(source));
00574             fail = true;
00575             if (retry!="") {
00576                 next = "retryable";
00577             }
00578             if (next!="revertable"&&next!="retryable") {
00579                 background = false;
00580                 CoopyApp::fossil_result = 1;
00581                 CheckEnd();
00582                 return;
00583             }
00584         }
00585         //printf(">>>>> PROCESS COMPLETE: next is [%s]\n", next.c_str());
00586         string n = next;
00587         next = "";
00588         if (n=="view_sync") {
00589             updateSettings(true);
00590             updateListing();
00591             pushListing(true);
00592             CheckEnd();
00593             background = false;
00594         } else if (n=="view") {
00595             updateSettings(true);
00596             updateListing();
00597             CheckEnd();
00598         } else if (n == "view2") {
00599             wxString view = conv(path);
00600 #ifndef WIN32
00601             view = wxT("file://") + view;
00602 #endif
00603             ::wxLaunchDefaultBrowser(view);
00604         } else if (n=="sync") {
00605             wxCommandEvent ev;
00606             OnSync(ev);
00607         } else if (n=="push") {
00608             wxCommandEvent ev;
00609             OnPush(ev);
00610         } else if (n=="revertable"||n=="retryable") {
00611             if (fail) {
00612                 if (n=="revertable") {
00613                     addLog(wxT("Reverting..."));
00614                     revert();
00615                     CheckEnd();
00616                 }
00617                 if (n=="retryable") {
00618                     addLog(wxT("Reverting..."));
00619                     revert();
00620                     string r = retry;
00621                     retry = "";
00622                     repush(r);
00623                 }
00624             } else {
00625                 retry = "";
00626                 updatePivots(true);
00627                 addLog(wxT("Online repository updated successfully."));
00628                 CheckEnd();
00629             }
00630             background = false;
00631         }
00632     }
00633 
00634     void revert() {
00635         int argc = 2;
00636         char *argv[] = {
00637             fossil(),
00638             (char*)"revert",
00639             NULL };
00640         ssfossil(argc,argv,true);
00641         updatePivots(false);
00642     }
00643 
00644     list<string> getChanges() {
00645         beginLog();
00646         if (havePath()) {
00647             int argc = 2;
00648             char *argv[] = {
00649                 fossil(),
00650                 (char*)"changes",
00651                 NULL };
00652             ssfossil(argc,argv,true);
00653         }
00654         return endLog();
00655     }
00656 
00657     list<string> getExtras() {
00658         beginLog();
00659         if (havePath()) {
00660             int argc = 2;
00661             char *argv[] = {
00662                 fossil(),
00663                 (char*)"extras",
00664                 NULL };
00665             ssfossil(argc,argv,true);
00666         }
00667         return endLog();
00668     }
00669 
00670     list<string> getFiles() {
00671         beginLog();
00672         if (havePath()) {
00673             int argc = 2;
00674             char *argv[] = {
00675                 fossil(),
00676                 (char*)"ls",
00677                 NULL };
00678             ssfossil(argc,argv,true);
00679         }
00680         fileCache = endLog();
00681         updateCache = list<string>();
00682         return fileCache;
00683     }
00684 
00685     list<string> getMissing(const list<string>& report) {
00686         list<string> missing;
00687         for (list<string>::const_iterator it = report.begin();
00688              it != report.end();
00689              it++) {
00690             if (it->find("MISSING")==0) {
00691                 missing.push_back(it->c_str()+strlen("MISSING    "));
00692             }
00693         }
00694         return missing;
00695     }
00696 
00697     ostream *startStream() {
00698         //endStream();
00699         if (log_box) {
00700             log_box->Clear();
00701             //stream = new ostream(log_box);
00702         }
00703         //handler.setStream(stream);
00704         //return stream;
00705         return NULL;
00706     }
00707 
00708     void endStream() {
00709         /*
00710         if (stream) {
00711             delete stream;
00712             stream = NULL;
00713         }
00714         handler.setStream(stream);
00715         */
00716     }
00717 
00718     void doFiles(const list<string>& files, const char *act) {
00719         if (files.size()>=1) {
00720             if (havePath()) {
00721                 int argc = files.size()+2;
00722                 char **argv = new char *[argc];
00723                 if (argv==NULL) {
00724                     fprintf(stderr,"Out of memory while adding files\n");
00725                     exit(1);
00726                 }
00727                 argv[0] = fossil();
00728                 argv[1] = (char*)act;
00729                 int i = 2;
00730                 int items = 0;
00731                 for (list<string>::const_iterator it = files.begin();
00732                      it != files.end();
00733                      it++) {
00734                     if (it->rfind(".csvs")!=string::npos) {
00735                         if (it->rfind(".mark")==string::npos) {
00736                             if (it->rfind(".pivot")==string::npos) {
00737                                 if (it->rfind(".log")==string::npos) {
00738                                     argv[i] = (char*)(it->c_str());
00739                                     i++;
00740                                     items++;
00741                                 }
00742                             }
00743                         }
00744                     }
00745                 }
00746                 argc = i;
00747                 if (items>0) {
00748                     ssfossil(argc,argv,true);
00749                 }
00750                 delete[] argv;
00751             }
00752         }
00753     }
00754 
00755     void OnListBox(wxCommandEvent &event) {
00756         wxString str = list_box->GetStringSelection();
00757         if (str[0]!='.') {
00758             addLog(wxT("Selected '") + event.GetString() + wxT("' (double-click to open)"));
00759         } else {
00760             addLog(wxT("Double-click ADD option to attach a new spreadsheet/table."));
00761         }
00762     }
00763 
00764     void OnListBoxDoubleClick( wxCommandEvent &event ) {
00765         wxString str = list_box->GetStringSelection();
00766         if (str[0]!='.') {
00767             addLog(wxT("Opening '") + event.GetString() + wxT("' ..."));
00768             openFile(event.GetString());
00769         } else {
00770             addFile();
00771         }
00772     }
00773 
00774     bool updateListing();
00775 
00776     bool pushListing(bool reverse = false);
00777 
00778     bool updatePivots(bool success);
00779 
00780     bool updateSettings(bool create);
00781 
00782     bool openFile(const wxString& str, bool export_only = false);
00783 
00784     bool createFile(const char *local_name = NULL,
00785                     const char *key_name = NULL);
00786 
00787     bool addFile();
00788 
00789     bool Sync();
00790 
00791     void repush(const string& retry2);
00792 
00793     void OnFocusDbList() {
00794         list_box->SetFocus();
00795     }
00796 enum
00797     {
00798         TEXT_Main = wxID_HIGHEST + 1,
00799         TEXT_Src,
00800         TEXT_Dest,
00801         TEXT_Dir,
00802         ID_LISTBOX,
00803 
00804         ID_Quit,
00805         ID_Commit,
00806         ID_Sync,
00807         ID_Undo,
00808         ID_About,
00809         ID_Tick,
00810         ID_Create,
00811         ID_Merge,
00812         ID_Diff,
00813         ID_Patch,
00814         ID_DiffPatchMerge,
00815         ID_Reset,
00816     };
00817 };
00818 
00819 
00820 class FossilProcess : public wxProcess
00821 {
00822 public:
00823     FossilProcess(CoopyFrame *parent, const wxString& cmd, bool sync)
00824         : wxProcess(parent), m_cmd(cmd), sync(sync)
00825     {
00826         m_parent = parent;
00827     }
00828 
00829     // instead of overriding this virtual function we might as well process the
00830     // event from it in the frame class - this might be more convenient in some
00831     // cases
00832     virtual void OnTerminate(int pid, int status);
00833 
00834 protected:
00835     CoopyFrame *m_parent;
00836     wxString m_cmd;
00837     bool sync;
00838 };
00839 
00840 
00841 
00842 void FossilProcess::OnTerminate(int pid, int status)
00843 {
00844     /*
00845     wxLogStatus(m_parent, wxT("Process %u ('%s') terminated with exit code %d."),
00846                 pid, m_cmd.c_str(), status);
00847     */
00848 
00849     if (!sync) {
00850         m_parent->OnTerminate(this,status);
00851     }
00852 }
00853 
00854 
00855 
00856 bool CoopyApp::OnInit()
00857 {
00858     store_app = this;
00859 
00860     CoopyFrame *frame = new CoopyFrame( _T("Coopy"), wxPoint(50,50), wxSize(450,340) );
00861 
00862     store_frame = frame;
00863 
00864     //g_hwnd = (long int)(frame->GetHandle());
00865 
00866     if (!wxApp::OnInit()) {
00867         return false;
00868     }
00869 
00870 
00871     MergeFrame *mframe = new MergeFrame(frame, _T("diff, patch, merge"), wxPoint(50,50), wxSize(450,340));
00872     store_mframe = mframe;
00873     if (!mframe->OnInit()) return false;
00874     mframe->Show(FALSE);
00875 
00876     SetVendorName(wxT("DataCommonsCooperative"));
00877     SetAppName(wxT("coopy"));
00878 
00879     wxConfigBase *pConfig = wxConfigBase::Get();
00880 
00881     // uncomment this to force writing back of the defaults for all values
00882     // if they're not present in the config - this can give the user an idea
00883     // of all possible settings for this program
00884     pConfig->SetRecordDefaults();
00885 
00886     if (!frame->OnInit()) {
00887         return false;
00888     }
00889     if (!silent) {
00890         frame->Show(TRUE);
00891         SetTopWindow(frame);
00892     } else {
00893         if (!frame->background) {
00894             //printf("Working in background...\n");
00895             //wxThread::Sleep(100);
00896             //}
00897             frame->Destroy();
00898             exit(fossil_result);
00899         }
00900     }
00901     return (fossil_result==0)?TRUE:FALSE;
00902 };
00903 
00904 
00905 
00906 IMPLEMENT_CLASS(CoopyFrame, wxFrame)
00907 
00908 BEGIN_EVENT_TABLE(CoopyFrame, wxFrame)
00909     EVT_MENU(ID_Quit, CoopyFrame::OnQuit)
00910     EVT_MENU(ID_Sync, CoopyFrame::OnSync)
00911     EVT_MENU(ID_Commit, CoopyFrame::OnCommit)
00912     EVT_MENU(ID_Create, CoopyFrame::OnCreate)
00913     EVT_MENU(ID_Merge, CoopyFrame::OnMerge)
00914     EVT_MENU(ID_Diff, CoopyFrame::OnDiff)
00915     EVT_MENU(ID_Patch, CoopyFrame::OnPatch)
00916     EVT_MENU(ID_About, CoopyFrame::OnAbout)
00917     EVT_BUTTON(ID_Reset, CoopyFrame::OnReset)
00918     EVT_BUTTON(ID_Quit, CoopyFrame::OnQuit)
00919     EVT_BUTTON(ID_Sync, CoopyFrame::OnSync)
00920     EVT_BUTTON(ID_Undo, CoopyFrame::OnUndo)
00921     EVT_BUTTON(ID_Commit, CoopyFrame::OnCommit)
00922     EVT_BUTTON(ID_Create, CoopyFrame::OnCreate)
00923     EVT_BUTTON(ID_DiffPatchMerge, CoopyFrame::OnDiffPatchMerge)
00924     EVT_CLOSE(CoopyFrame::OnExit)
00925     EVT_TIMER(ID_Tick, CoopyFrame::OnProgressTimer)
00926     EVT_LISTBOX(ID_LISTBOX, CoopyFrame::OnListBox)
00927     EVT_LISTBOX_DCLICK(ID_LISTBOX, CoopyFrame::OnListBoxDoubleClick)
00928 END_EVENT_TABLE()
00929 
00930 
00931 int CoopyFrame::ssfossil(int argc, char *argv[], bool sync) {
00932     //printf("**** Calling fossil with %d arguments, %s\n", argc,
00933     //sync?"sync":"background");
00934     if (!sync) {
00935         background = true;
00936     }
00937     wxArrayString arr;
00938     wxChar *cmd[256];
00939     wxString op;
00940     wxString op1;
00941     for (int i=0; i<argc; i++) {
00942         wxString p = conv(safetxt(argv[i]));
00943         arr.Add(p);
00944         if (i>0) {
00945             op = op + p + wxT(" ");
00946         }
00947         if (i==1) {
00948             op1 = conv(string(argv[i]));
00949         }
00950     }
00951     if (verb()) {
00952         addLog(wxT("Command: [") + op + wxT("]"));
00953     }
00954     if (op1 == wxT("update")) {
00955         addLog(wxT(" \n \nUpdating repository..."));
00956     } else if (op1 == wxT("new")) {
00957         addLog(wxT(" \n \nCreating new repository..."));
00958     } else if (op1 == wxT("push")) {
00959         addLog(wxT(" \n \nPushing changes from your computer..."));
00960     } else if (op1 == wxT("changes")) {
00961         addLog(wxT(" \n \nChecking for changes on this computer..."));
00962     } else if (op1 == wxT("commit")) {
00963         addLog(wxT(" \n \nSending changes from your computer..."));
00964     }
00965     showing = (op1 == wxT("update")) || (op1 == wxT("commit")) || (op1 == wxT("push")) || (op1 == wxT("pull")) || (op1 == wxT("clone")) || (op1 == wxT("new"));
00966     for (int i=0; i<argc; i++) {
00967         //printf("[%s] ", conv(arr[i]).c_str());
00968         cmd[i] = (wxChar*)((const wxChar *)arr[i]);
00969     }
00970     //printf("\n");
00971     cmd[argc] = NULL;
00972     /*
00973     string cmd;
00974     for (int i=0; i<argc; i++) {
00975         printf("[%s] ", argv[i]);
00976         cmd += safetxt(argv[i]);
00977         cmd += " ";
00978     }
00979     */
00980     //printf("\n");
00981     //printf("Doing: %s\n", cmd.c_str());
00982 
00983     // Create the process string
00984     //wxEvtHandler *eventHandler = NULL;
00985     //wxProcess *proc = new wxProcess(eventHandler);
00986     FossilProcess *proc = new FossilProcess(this,_T("ssfossil"),sync);
00987     proc->Redirect();
00988     //if(::wxExecute(conv(cmd), wxEXEC_ASYNC, proc) == 0){
00989     if(::wxExecute(cmd, wxEXEC_ASYNC, proc) == 0){
00990         fprintf(stderr,"Fossil error (1)\n");
00991         exit(1);
00992     }
00993     reportErr = proc->GetErrorStream();
00994     report = proc->GetInputStream();
00995     if (report==NULL||reportErr==NULL) {
00996         fprintf(stderr,"Fossil error (2)\n");
00997         exit(1);
00998     }
00999     if (!sync) {
01000         timer->Start(50);
01001     } else {
01002         while (!report->Eof()) {
01003             processInput();
01004         }
01005         //printf("Sync done\n");
01006         showing = true;
01007     }
01008     
01009     return 0;
01010     
01011     /*
01012       try {
01013       return external_ssfossil_call(argc,argv);
01014       } catch (int err) {
01015       printf("exit(%d) called in external_ssfossil_call\n", err);
01016       }
01017       return -1;
01018     */
01019 }
01020 
01021 bool CoopyFrame::OnInit() {
01022 
01023     stream = NULL;
01024     askPath = true;
01025     askSource = true;
01026     askDestination = true;
01027     showing = true;
01028 
01029     wxPanel *panel = new wxPanel(this, wxID_ANY,
01030                                  wxDefaultPosition, wxSize(400,400));
01031 
01032     timer = new wxTimer(panel,ID_Tick);
01033 
01034     SetIcon(wxIcon((char**)appicon_xpm));
01035 
01036     topsizer = new wxBoxSizer( wxVERTICAL );
01037 
01038     wxSizerFlags tflags = 
01039         wxSizerFlags(0).Align(wxALIGN_LEFT).Border(wxLEFT|wxRIGHT|wxTOP, 10);
01040     wxSizerFlags flags = 
01041         wxSizerFlags(0).Align(wxALIGN_CENTER).Border(wxALL, 10);
01042     wxSizerFlags rflags = 
01043         wxSizerFlags(0).Align(wxALIGN_RIGHT).Border(wxALL, 10);
01044     wxSizerFlags lflags = 
01045         wxSizerFlags(0).Align(wxALIGN_LEFT).Border(wxALL, 10);
01046 
01047     
01048     wxBoxSizer *dir_bar = new wxBoxSizer( wxHORIZONTAL );
01049 
01050     /*
01051     dir_box = new wxDirPickerCtrl(panel,TEXT_Dir, wxT(""),
01052                                   wxT("Select a folder"),
01053                                   wxDefaultPosition,
01054                                   wxSize(300,-1));
01055     */
01056     const wxString choices[] = {
01057     };
01058     list_box = new wxListBox(panel,ID_LISTBOX, wxPoint(10,10), wxSize(200,100),
01059                              0, choices, wxLB_SINGLE | wxLB_ALWAYS_SB |
01060                              wxHSCROLL);
01061 
01062     //dir_box->SetTextCtrlProportion(0);
01063 
01064     if (CoopyApp::fossil_object=="") {
01065         if (CoopyApp::fossil_autoend) {
01066             wxString name = wxFileName::GetCwd();
01067             CoopyApp::fossil_object = conv(name);
01068         }
01069     }
01070 
01071     if (CoopyApp::fossil_object!="") {
01072         wxFileName name = wxFileName::FileName(conv(CoopyApp::fossil_object));
01073         name.MakeAbsolute();
01074         if (!wxFile::Exists(name.GetFullPath())) {
01075             path = conv(name.GetFullPath());
01076         } else {
01077             path = conv(name.GetPath());
01078         }
01079         //dir_box->SetPath(conv(path));
01080         dir_box_path = path;
01081         askPath = false;
01082     } else {
01083 #ifdef __LINUX__
01084         //dir_box->SetPath(::wxGetCwd());
01085         dir_box_path = conv(::wxGetCwd());
01086 #else
01087         wxStandardPaths sp;
01088         //dir_box->SetPath(sp.GetDocumentsDir());
01089         dir_box_path = conv(sp.GetDocumentsDir());
01090 #endif
01091     }
01092 
01093     //dir_bar->Add(dir_box,lflags);
01094     dir_bar->Add(new wxButton( panel, ID_Sync, _T("Pull &in") ),
01095                     lflags);
01096     dir_bar->Add(new wxButton( panel, ID_Commit, _T("Push &out") ),
01097                     lflags);
01098     dir_bar->Add(new wxButton( panel, ID_Create, _T("&Set up repository") ),
01099                     lflags);
01100     dir_bar->Add(new wxButton( panel, ID_DiffPatchMerge, _T("&Diff, patch, merge") ),
01101                     lflags);
01102     topsizer->Add(dir_bar,wxSizerFlags(0).Align(wxALIGN_LEFT));
01103 
01104     
01105     log_box = new wxTextCtrl(panel, TEXT_Main, conv(string("Coopy facilitates cooperative data-collection projects. \nSee http://") + SITE_NAME + " if you need a repository link.\nWarning: this is alpha software, keep backups of your data.\n"), 
01106                              wxDefaultPosition, wxSize(620,200),  
01107                              wxTE_MULTILINE | wxTE_RICH, 
01108                              wxDefaultValidator, wxTextCtrlNameStr);
01109 
01110     //handler.setCtrl(*log_box);
01111 
01112     topsizer->Add(log_box);
01113     topsizer->Add(new wxStaticText(panel,-1,_T("Spreadsheets/Tables"),
01114                                   wxDefaultPosition,
01115                                   wxSize(200,-1)),lflags);
01116     topsizer->Add(list_box);
01117 
01118 
01119     wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
01120     
01121     //create two buttons that are horizontally unstretchable, 
01122     // with an all-around border with a width of 10 and implicit top alignment
01123     button_sizer->Add(
01124                       new wxButton( panel, ID_Reset, _T("&Reset") ),
01125                       wxSizerFlags(0).Align(wxALIGN_RIGHT).Border(wxALL, 10));       
01126     
01127     button_sizer->Add(
01128                       new wxButton( panel, ID_Quit, _T("E&xit") ),
01129                       wxSizerFlags(0).Align(wxALIGN_RIGHT).Border(wxALL, 10));    
01130 
01131 
01132 
01133     topsizer->Add(button_sizer,wxSizerFlags(0).Align(wxALIGN_RIGHT));
01134 
01135     panel->SetSizer(topsizer);
01136     topsizer->SetSizeHints(this);
01137 
01138     panel->SetFocus();
01139 
01140     if (!askPath) {
01141         updateSettings(true);
01142         updateListing();
01143     }
01144 
01145     if (CoopyApp::fossil_action!="") {
01146         if (CoopyApp::fossil_action=="push") {
01147             //printf("Should push\n");
01148             wxCommandEvent ev;
01149             OnCommit(ev);
01150         }
01151         if (CoopyApp::fossil_action=="new") {
01152             wxCommandEvent ev;
01153             OnCreateRepo(ev);
01154         }
01155         if (CoopyApp::fossil_action=="clone") {
01156             wxCommandEvent ev;
01157             OnCloneRepo(ev);
01158         }
01159         if (CoopyApp::fossil_action=="pull") {
01160             //printf("Should pull\n");
01161             wxCommandEvent ev;
01162             OnSync(ev);
01163         }
01164         if (CoopyApp::fossil_action=="add") {
01165             createFile(CoopyApp::fossil_message.c_str(),
01166                        CoopyApp::fossil_key.c_str());
01167             CheckEnd();
01168         }
01169         if (CoopyApp::fossil_action=="export") {
01170             openFile(conv(CoopyApp::fossil_key),true);
01171             CheckEnd();
01172         }
01173     }
01174     return true;
01175 }
01176 
01177 
01178 bool CoopyFrame::havePath() {
01179     //if (dir_box) 
01180     {
01181         string ref = dir_box_path; //conv(dir_box->GetPath());
01182         if (ref!=path) {
01183             path = ref;
01184         }
01185     }
01186 
01187     if (path=="" || askPath) {
01188         source = "";
01189         wxDirDialog dlg(NULL, wxT("Select directory to work in"), 
01190                         conv(path),
01191                         wxDD_DEFAULT_STYLE); // | wxDD_DIR_MUST_EXIST);
01192         while (path==""||askPath) {
01193             if (dlg.ShowModal()!=wxID_OK) {
01194                 return false;
01195             } else {
01196                 wxString result = dlg.GetPath();
01197                 
01198                 wxDir dir(result);
01199                 int ct = 0;
01200                 if (dir.IsOpened()) {
01201                     wxString filename;
01202                     bool cont = dir.GetFirst(&filename, wxEmptyString, 
01203                                              wxDIR_FILES|wxDIR_DIRS|wxDIR_HIDDEN);
01204                     while ( cont ) {
01205                         string fname = conv(filename);
01206                         //printf("%s\n", fname.c_str());
01207                         cont = dir.GetNext(&filename);
01208                         ct++;
01209                     }
01210                 }
01211                 if (ct>0) {
01212                     wxChar sep = wxFileName::GetPathSeparator();
01213                     wxString target = result + sep + wxT("repository.coopy");
01214                     if (!wxFileExists(target)) {
01215                         wxString target2 = result + sep + wxT("clone.fossil");
01216                         if (wxFileExists(target2)) {
01217                             target = target2;
01218                         }
01219                     }
01220  
01221                     if (!wxFileExists(target)) {
01222                         wxMessageDialog msg(NULL, wxT("Please select a fresh new directory to start a new repository, or a directory that already has a Coopy repository in it."),
01223                                             wxT("Sorry, cannot use selected directory"));
01224                         msg.ShowModal();
01225                         continue;
01226                     }
01227                 }
01228 
01229                 path = conv(result);
01230                 //printf("Selected a directory %s\n", path.c_str());
01231                 askPath = false;
01232 
01233                 /*
01234                 if (path!="") {
01235                     updateSettings(true);
01236                 }
01237                 */
01238             }
01239         }
01240     }
01241     if (path!="") {
01242         wxSetWorkingDirectory(conv(path));
01243     }
01244 
01245     //if (dir_box) 
01246     {
01247         string ref = dir_box_path; //conv(dir_box->GetPath());
01248         if (ref!=path && path!="") {
01249             //dir_box->SetPath(conv(path));
01250             dir_box_path = path;
01251         }
01252     }
01253 
01254     return path!="";
01255 }
01256 
01257 bool CoopyFrame::updateSettings(bool create) {
01258     wxChar sep = wxFileName::GetPathSeparator();
01259     wxString target = conv(path);
01260     if (target.length()>0) {
01261         target = target + sep;
01262     }
01263     target = target + wxT("local_settings.coopy");
01264     ws.connect(create,conv(target).c_str());
01265     string sep0 = conv(sep);
01266     ws.setDirectory(path.c_str(),sep0.c_str());
01267     //if (ws.isValid()) {
01268     //updateListing();
01269     //}
01270 }
01271 
01272 
01273 bool CoopyFrame::updateListing() {
01274     //printf("update listing\n");
01275     list<string> files = getFiles();
01276     map<string,int> present;
01277     string adder = "... Add ...";
01278     present[adder] = 1;
01279     for (list<string>::const_iterator it = files.begin();
01280          it != files.end();
01281          it++) {
01282         if (it->rfind(".csvs")!=string::npos) {
01283             string str = it->substr(0,it->rfind(".csvs"));
01284             //printf("file of interest %s -> %s\n", it->c_str(), str.c_str());
01285             wxString item = conv(str);
01286             int result = list_box->FindString(item);
01287             if (result==wxNOT_FOUND) {
01288                 list_box->InsertItems(1,&item,0);
01289             }
01290             present[str] = 1;
01291         }
01292     }
01293     {
01294         wxString item = conv(adder);
01295         int result = list_box->FindString(item);
01296         if (result==wxNOT_FOUND) {
01297             list_box->InsertItems(1,&item,0);
01298         }
01299     }
01300 
01301     int ct = list_box->GetCount();
01302     int offset = 0;
01303     for (int i=0; i<ct; i++) {
01304         wxString item = list_box->GetString(i-offset);
01305         string str = conv(item);
01306         if (present.find(str)==present.end()) {
01307             //printf("cannot find %s\n", str.c_str());
01308             list_box->Delete(i-offset);
01309             offset++;
01310         }
01311     }
01312     return true;
01313 }
01314 
01315 
01316 bool CoopyFrame::pushListing(bool reverse) {
01317     //printf("push listing %d\n", reverse);
01318     list<string> files = fileCache;
01319     for (list<string>::const_iterator it = files.begin();
01320          it != files.end();
01321          it++) {
01322         //printf("checking %s\n", it->c_str());
01323         if (it->rfind(".csvs")!=string::npos) {
01324             string str = it->substr(0,it->rfind(".csvs"));
01325             //printf("checking %s -> %s\n", it->c_str(), str.c_str());
01326             string local = ws.getFile(str.c_str());
01327             if (local=="") continue;
01328             string remote = *it;
01329 
01330             wxFileName localName = wxFileName::FileName(conv(local));
01331             wxFileName remoteName = wxFileName::FileName(conv(remote));
01332             if (!localName.FileExists()) continue;
01333             if (!remoteName.FileExists()) continue;
01334             //printf("local %s remote %s %d\n", local.c_str(),
01335             //     remote.c_str(), reverse);
01336             wxFileName pivotName = wxFileName::FileName(conv(remote+".pivot"));
01337             wxFileName markName = wxFileName::FileName(conv(remote+".mark"));
01338             wxFileName logName = wxFileName::FileName(conv(remote+".log"));
01339             wxDateTime localTime = localName.GetModificationTime();
01340             wxDateTime remoteTime = remoteName.GetModificationTime();
01341             wxDateTime markTime;
01342             bool haveMark = false;
01343             if (markName.FileExists()) {
01344                 markTime = markName.GetModificationTime();
01345                 haveMark = true;
01346             }
01347             bool act = false;
01348             if (!reverse) {
01349                 // local -> repository
01350 
01351                 if (haveMark) {
01352                     act = markTime.IsEarlierThan(localTime);
01353                 } else {
01354                     act = remoteTime.IsEarlierThan(localTime);
01355                 }
01356                 if (act) {
01357                     //printf("  local -> repository (%s, %s)\n", local.c_str(), remote.c_str());
01358                     bool ok = ws.importSheet(str.c_str());
01359                     if (ok) {
01360                         updateCache.push_back(str);
01361                         /*
01362                         if (!markName.FileExists()) {
01363                             wxFile f;
01364                             f.Create(markName.GetFullPath());
01365                         }
01366                         markName.Touch();
01367                         */
01368                     }
01369                 }
01370 
01371             } else {
01372                 // repository -> local
01373 
01374                 if (haveMark) {
01375                     act = markTime.IsEarlierThan(remoteTime);
01376                 } else {
01377                     act = localTime.IsEarlierThan(remoteTime);
01378                 }
01379                 if (act) {
01380                     //printf("  repository -> local (%s, %s)\n", remote.c_str(), local.c_str());
01381                     string l = conv(localName.GetFullPath());
01382                     string r = conv(remoteName.GetFullPath());
01383                     string p = conv(pivotName.GetFullPath());
01384                     string lg = conv(logName.GetFullPath());
01385                     bool pExists = pivotName.FileExists();
01386                     bool ok = false;
01387                     if (localName.FileExists()) {
01388                         ok = ws.mergeToLocal(l.c_str(),r.c_str(),
01389                                              pExists?p.c_str():NULL,
01390                                              lg.c_str());
01391                     } else {
01392                         ok = ws.exportSheet(str.c_str());
01393                     }
01394                     if (ok) {
01395                         wxCopyFile(remoteName.GetFullPath(),
01396                                    pivotName.GetFullPath(),
01397                                    true);
01398                         /*
01399                         if (!markName.FileExists()) {
01400                             wxFile f;
01401                             f.Create(markName.GetFullPath());
01402                         }
01403                         markName.Touch();
01404                         */
01405                         addLogFile(logName);
01406                     } else {
01407                         addLog(wxT("Could not merge with online version, there is a conflicting change"));
01408                         addLog(wxT("Not much help available for this condition yet, sorry, bug Paul about this"));
01409                         localName.MakeAbsolute();
01410                         addLog(wxT("Your file: ") + localName.GetFullPath());
01411                         remoteName.MakeAbsolute();
01412                         addLog(wxT("Online version: ") + remoteName.GetFullPath());
01413                         if (pExists) {
01414                             pivotName.MakeAbsolute();
01415                             addLog(wxT("Common ancestor: ") + pivotName.GetFullPath());
01416                         }
01417                     }
01418                 }
01419             }
01420         }
01421     }
01422 
01423     return true;
01424 }
01425 
01426 
01427 bool CoopyFrame::updatePivots(bool success) {
01428     list<string> files = updateCache;
01429     for (list<string>::const_iterator it = files.begin();
01430          it != files.end();
01431          it++) {
01432         string str = (*it);
01433 
01434         /*
01435         printf("update pivot for %s: %s\n", 
01436                success?"success":"failure",
01437                str.c_str());
01438         */
01439 
01440         string remote = str + ".csvs";
01441         wxCopyFile(conv(remote),conv(remote+".pivot"),true);
01442 
01443         if (success) {
01444             wxFileName markName(conv(remote+".mark"));
01445             if (!markName.FileExists()) {
01446                 wxFile f;
01447                 f.Create(markName.GetFullPath());
01448             }
01449             markName.Touch();
01450         }
01451     }
01452     return true;
01453 }
01454 
01455 
01456 bool CoopyFrame::createFile(const char *local_name, const char *key_name) {
01457     wxString meat = wxT("example_name");
01458     wxRegEx re(wxT("[^a-zA-Z0-9]"));
01459     if (local_name!=NULL) {
01460         std::string ll(local_name);
01461         if (key_name!=NULL) {
01462             ll = key_name;
01463         }
01464         wxString n(conv(ll));
01465         wxFileName f = wxFileName::FileName(n);
01466         meat = f.GetName();
01467         re.ReplaceAll(&meat,wxT("_"));
01468     }
01469     if (CoopyApp::fossil_action=="") {
01470         wxTextEntryDialog dlg(NULL, 
01471                               wxT("Enter a simple name for the file in the repository.\nAny spaces or punctuation will be replaced by '_' characters.\nYou'll be able to save with a different name on your computer."),
01472                               wxT("Set name"),
01473                               meat);
01474         if (dlg.ShowModal()!=wxID_OK) {
01475             return false;
01476         }
01477         meat = dlg.GetValue();
01478         re.ReplaceAll(&meat,wxT("_"));
01479     }
01480     wxString actName = meat + wxT(".csvs");
01481     string key = conv(meat);
01482     wxFileName name = wxFileName::FileName(actName);
01483     if (!name.FileExists()) {
01484         if (local_name==NULL) {
01485             wxFile f;
01486             f.Create(name.GetFullPath());
01487             f.Write(wxT("== Main ==\n"));
01488             f.Write(wxT("Name,Number\n"));
01489             f.Write(wxT("-----------\n"));
01490             f.Write(wxT("One,1\n"));
01491             f.Write(wxT("Two,2\n"));
01492             f.Write(wxT("Three,3\n"));
01493             f.Write(wxT("Four,4\n"));
01494             f.Write(wxT("Five,5\n"));
01495             f.Close();
01496         } else {
01497             wxFile f;
01498             f.Create(name.GetFullPath());
01499             f.Close();
01500             ws.setFile(key.c_str(),local_name);
01501             ws.exportSheet(key.c_str(),true);
01502         }
01503     }
01504     list<string> files;
01505     files.push_back(conv(actName));
01506     doFiles(files,"add");
01507     updateListing();
01508     CheckEnd();
01509     return true;
01510 }
01511 
01512 bool CoopyFrame::addFile() {
01513     wxFileDialog LoadDialog(this, _("Add File"), wxEmptyString, wxEmptyString,
01514                             _("Excel files (*.xls)|*.xls|Sqlite files (*.sqlite)|*.sqlite|CSV files (*.csv)|*.csv"),
01515                             wxFD_OPEN | wxFD_FILE_MUST_EXIST, wxDefaultPosition);
01516  
01517     if (LoadDialog.ShowModal() == wxID_OK) {
01518         wxFileName name = wxFileName::FileName(LoadDialog.GetPath());
01519         name.MakeAbsolute();
01520         string fname = conv(name.GetFullPath());
01521         return createFile(fname.c_str());
01522     }
01523 
01524     return false;
01525 }
01526 
01527 
01528 bool CoopyFrame::openFile(const wxString& str, bool export_only) {
01529     string key = conv(str);
01530     string fname = ws.getFile(key.c_str());
01531     bool exists = false;
01532     if (fname!="") {
01533         wxFileName name = wxFileName::FileName(conv(fname));
01534         exists = name.FileExists();
01535     }
01536     if (fname==""||!exists) {
01537         if (CoopyApp::fossil_message!="") {
01538             fname = CoopyApp::fossil_message;
01539         } else {
01540             wxFileDialog SaveDialog(this, _("Save File As _?"), wxEmptyString, conv(fname),
01541                                     _("Excel files (*.xls)|*.xls|Sqlite files (*.sqlite)|*.sqlite|CSV files (*.csv)|*.csv"),
01542                                     wxFD_SAVE | wxFD_OVERWRITE_PROMPT, wxDefaultPosition);
01543             
01544             if (SaveDialog.ShowModal() == wxID_OK) {
01545                 fname = conv(SaveDialog.GetFilename());
01546             } else {
01547                 return false;
01548             }
01549         }
01550         if (fname!="") {
01551             ws.setFile(key.c_str(),fname.c_str());
01552             ws.exportSheet(key.c_str());
01553             updateCache.push_back(key);
01554             updatePivots(true);
01555         } else {
01556             return false;
01557         }
01558     }
01559     if (fname=="") return false;
01560     addLog(wxT("... local file is ") + conv(fname));
01561 
01562     wxFileName name = wxFileName::FileName(conv(fname));
01563     if (!name.FileExists()) {
01564         ws.exportSheet(key.c_str());
01565     }
01566     name.MakeAbsolute();
01567     fname = conv(name.GetFullPath());
01568 
01569     if (!export_only) {
01570         show(fname);
01571     }
01572 
01573     return true;
01574 }
01575 
01576 
01577 bool CoopyFrame::haveSource() {
01578     if (src_box) {
01579         string ref = conv(src_box->GetValue());
01580         if (ref!=source) {
01581             source = ref;
01582         }
01583     }
01584     if (CoopyApp::fossil_repo.length()>0) {
01585         source = CoopyApp::fossil_repo;
01586         askSource = false;
01587     }
01588 
01589     if (source==""||askSource) {
01590         string suggest = source;
01591         if (suggest=="") {
01592             suggest = ""; 
01593             //suggest = "http://coopy.sourceforge.net/cgi-bin/wiki/home";
01594         }
01595         if (CoopyApp::silent) {
01596             addLog(wxT("No repository found"));
01597             CoopyApp::fossil_result = 1;
01598             CheckEnd();
01599             return false;
01600         }
01601         wxTextEntryDialog dlg(NULL, 
01602                               wxT("Enter the link for the repository to pull in to your computer.\nIf you do not have a link, try creating a repository first."),
01603                               wxT("Enter repository link"),
01604                               conv(suggest));
01605         if (dlg.ShowModal()==wxID_OK) {
01606             source = conv(dlg.GetValue());
01607             /*
01608 string("http://") +
01609                 FOSSIL_USERNAME + ":" + conv(dlg.GetValue()) + "@" +
01610                 FOSSIL_ROOT + FOSSIL_REPO;
01611             */
01612             //printf("Source set to %s\n", source.c_str());
01613             askSource = false;
01614         } else {
01615             source = "";
01616         }
01617     }
01618 
01619     if (src_box) {
01620         string ref = conv(src_box->GetValue());
01621         if (ref!=source && source!="") {
01622             src_box->ChangeValue(conv(source));
01623         }
01624     }
01625 
01626     //printf("Source is %s\n", source.c_str());
01627 
01628     return source!="";
01629 }
01630 
01631 bool CoopyFrame::haveDestination() {
01632     if (dest_box) {
01633         string ref = conv(dest_box->GetValue());
01634         if (ref!=destination) {
01635             destination = ref;
01636         }
01637     }
01638 
01639     if (destination==""||askDestination) {
01640         string suggest = destination;
01641         if (suggest=="") {
01642             suggest = source;
01643         }
01644         wxTextEntryDialog dlg(NULL, wxT("Enter destination URL"),
01645                               wxT("Enter destination URL"),
01646                               conv(suggest));
01647         if (dlg.ShowModal()==wxID_OK) {
01648             destination = conv(dlg.GetValue());
01649             askDestination = false;
01650         } else {
01651             destination = "";
01652         }
01653         /*
01654         wxPasswordEntryDialog dlg(NULL, wxT("Enter password"));
01655         if (dlg.ShowModal()==wxID_OK) {
01656             source = string("http://") +
01657                 FOSSIL_USERNAME + ":" + conv(dlg.GetValue()) + "@" +
01658                 FOSSIL_ROOT + FOSSIL_REPO;
01659             printf("Source set to %s\n", source.c_str());
01660         }
01661         */
01662     }
01663 
01664     if (dest_box) {
01665         string ref = conv(dest_box->GetValue());
01666         if (ref!=destination && destination!="") {
01667             dest_box->ChangeValue(conv(destination));
01668         }
01669     }
01670 
01671     return destination!="";
01672 }
01673 
01674 void CoopyFrame::OnReset(wxCommandEvent& ev) {
01675     askPath = true;
01676     askSource = true;
01677     askDestination = true;
01678     if (src_box) { src_box->ChangeValue(wxT("")); }
01679     if (dest_box) { dest_box->ChangeValue(wxT("")); }
01680 }
01681 
01682 bool CoopyFrame::OnCloneRepo(wxCommandEvent& event) {
01683     next = "";
01684     retry = "";
01685     string src = CoopyApp::fossil_target;
01686     wxURL url = conv(src);
01687     string scheme = conv(url.GetScheme());
01688     if (scheme.length()<=1) { // no scheme, or windows drive
01689         wxChar sep = wxFileName::GetPathSeparator();
01690         wxFileName name = wxFileName::FileName(conv(src));
01691         if (!wxFile::Exists(name.GetFullPath())) {
01692             src = src + conv(sep) + "repository.coopy";
01693         }
01694     }
01695     if (havePath()) {
01696         wxChar sep = wxFileName::GetPathSeparator();
01697         wxString target = conv(path) + sep + wxT("repository.coopy");
01698         if (!wxFileExists(target)) {
01699             int argc = 4;
01700             string t = conv(target);
01701             char *argv[] = {
01702                 fossil(),
01703                 (char*)"clone",
01704                 (char*)src.c_str(),
01705                 (char*)t.c_str(),
01706                 NULL };
01707             ssfossil(argc,argv,true);
01708         }
01709         if (!wxFileExists(target)) {
01710             exit(1);
01711         }
01712         return OnOpenRepo(false);
01713     }
01714     return false;
01715 }
01716 
01717 bool CoopyFrame::OnCreateRepo(wxCommandEvent& event) {
01718     next = "";
01719     retry = "";
01720     if (havePath()) {
01721         wxChar sep = wxFileName::GetPathSeparator();
01722         wxString target = conv(path) + sep + wxT("repository.coopy");
01723         if (!wxFileExists(target)) {
01724             int argc = 3;
01725             string t = conv(target);
01726             char *argv[] = {
01727                 fossil(),
01728                 (char*)"new",
01729                 (char*)t.c_str(),
01730                 NULL };
01731             ssfossil(argc,argv,true);
01732         }
01733         if (!wxFileExists(target)) {
01734             exit(1);
01735         }
01736         /*
01737         if (wxFileExists(target)) {
01738             Sync();
01739         }
01740         */
01741         next = "";
01742         return OnOpenRepo(false);
01743     }
01744     return false;
01745 }
01746 
01747 
01748 bool CoopyFrame::OnOpenRepo(bool back) {
01749     if (havePath()) {
01750         //printf("Should open %s\n", path.c_str());
01751         wxChar sep = wxFileName::GetPathSeparator();
01752         wxString target = conv(path) + sep + wxT("repository.coopy");
01753         string ctarget = conv(target);
01754         if (wxFileExists(target)) {
01755             wxString view_target = conv(path) + sep + wxT("_FOSSIL_");
01756             if (!wxFileExists(view_target)) {
01757                 //printf("No view yet %s\n", conv(view_target).c_str());
01758                 int argc = 3;
01759                 char *argv[] = {
01760                     fossil(),
01761                     (char*)"open",
01762                     (char*)ctarget.c_str(),
01763                     NULL };
01764                 if (back) {
01765                     next = "sync";
01766                 }
01767                 ssfossil(argc,argv,true);
01768                 //if (back) {
01769                 //return true;
01770                 //}
01771             }
01772             if (wxFileExists(view_target)) {
01773                 // make sure we have autosync
01774                 int argc = 4;
01775                 char *argv[] = {
01776                     fossil(),
01777                     (char*)"setting",
01778                     (char*)"autosync",
01779                     (char*)"1",
01780                     NULL };
01781                 ssfossil(argc,argv,true);
01782             }
01783             if (wxFileExists(view_target)) {
01784                 //printf("Simple sync\n");
01785                 int argc = 2;
01786                 char *argv[] = {
01787                     fossil(),
01788                     (char*)"update",
01789                     NULL };
01790                 if (back) {
01791                     next = "view_sync";
01792                 }
01793                 ssfossil(argc,argv,!back);
01794             }
01795         }
01796         if (!back) {
01797             updateSettings(true);
01798             updateListing();
01799             pushListing(true);
01800         }
01801     }
01802 }
01803 
01804 bool CoopyFrame::Sync() {
01805     //printf("Syncing...\n");
01806     retry = "clone";
01807     next = "retryable";
01808     if (havePath()) {
01809         //printf("Should pull %s\n", path.c_str());
01810         wxChar sep = wxFileName::GetPathSeparator();
01811         wxString target = conv(path) + sep + wxT("repository.coopy");
01812         string ctarget = conv(target);
01813         if (!wxFileExists(target)) {
01814             //printf("Could not find %s\n", ctarget.c_str());
01815             if (haveSource()) {
01816                 //printf("Need to clone %s\n", ctarget.c_str());
01817                 int argc = 4;
01818                 char *argv[] = {
01819                     fossil(),
01820                     (char*)"clone",
01821                     (char*)source.c_str(),
01822                     (char*)ctarget.c_str(),
01823                     NULL };
01824                 next = "sync";
01825                 ssfossil(argc,argv);
01826                 return true;
01827             } else {
01828                 return false;
01829             }
01830         }
01831         next = "sync";
01832         return OnOpenRepo(true);
01833     }
01834     return false;
01835 }
01836 
01837 void CoopyFrame::OnSync(wxCommandEvent& event) {
01838     retry = "pull";
01839     Sync();
01840 }
01841 
01842 
01843 void CoopyFrame::OnUndo(wxCommandEvent& event) {
01844     //printf("Should undo\n");
01845     startStream();
01846     if (havePath()) {
01847         int argc = 2;
01848         char *argv[] = {
01849             fossil(),
01850             (char*)"undo",
01851             NULL };
01852         ssfossil(argc,argv);
01853     }
01854     endStream();
01855 }
01856 
01857 void CoopyFrame::OnCreate(wxCommandEvent& event) {
01858     //printf("Create!\n");
01859     //::wxLaunchDefaultBrowser(wxT(SITE_NAME_CREATE));
01860     retry = "";
01861     repush("");
01862 }
01863 
01864 void CoopyFrame::OnDiff(wxCommandEvent& event) {
01865     CoopyApp::store_mframe->SetMode("diff");
01866     CoopyApp::store_mframe->Show(TRUE);
01867     CoopyApp::store_app->SetTopWindow(CoopyApp::store_mframe);
01868 }
01869 
01870 void CoopyFrame::OnPatch(wxCommandEvent& event) {
01871     CoopyApp::store_mframe->SetMode("patch");
01872     CoopyApp::store_mframe->Show(TRUE);
01873     CoopyApp::store_app->SetTopWindow(CoopyApp::store_mframe);
01874 }
01875 
01876 void CoopyFrame::OnMerge(wxCommandEvent& event) {
01877     CoopyApp::store_mframe->SetMode("merge");
01878     CoopyApp::store_mframe->Show(TRUE);
01879     CoopyApp::store_app->SetTopWindow(CoopyApp::store_mframe);
01880 }
01881 
01882 void CoopyFrame::OnDiffPatchMerge(wxCommandEvent& event) {
01883    wxString choices[] = { 
01884         wxT("Compare two data files"), 
01885         wxT("Patch a data file"), 
01886         wxT("Merge data files"), 
01887     };
01888 
01889     wxSingleChoiceDialog dlg(this, wxT("What would you like to do?"),
01890                              wxT("Diff, patch, merge"), 3, choices);
01891     
01892     if (dlg.ShowModal() != wxID_OK) {
01893         return;
01894     }
01895  
01896     int choice = dlg.GetSelection();
01897     switch (choice) {
01898     case 0:
01899         OnDiff(event);
01900         break;
01901     case 1:
01902         OnPatch(event);
01903         break;
01904     case 2:
01905         OnMerge(event);
01906         break;
01907     }
01908 }
01909 
01910 
01911 
01912 void CoopyFrame::repush(const string& retry2) {
01913     if (writeWouldFork) {
01914         wxMessageDialog dlg(NULL, wxT("There have been updates to the repository.\nPlease pull those updates in before pushing yours out."), wxT("Cannot push"), 
01915                             wxOK|wxICON_INFORMATION);
01916         dlg.ShowModal();
01917         CheckEnd();
01918         return;
01919     }
01920     CheckEnd();
01921 
01922     bool has_dir = (dir_box_path!="" && !askPath);
01923 
01924     wxString choices[] = { 
01925         wxT("Connect to an existing repository"), 
01926         wxT("Set username and password"), 
01927         wxT("Create empty new repository"), 
01928         wxT("Fork current repository"), 
01929         wxT("Change directory"),
01930         wxT("Show project code"),
01931     };
01932 
01933     int CHOICE_CONNECT=0;
01934     int CHOICE_USERNAME=1;
01935     int CHOICE_NEW=2;
01936     int CHOICE_FORK=3;
01937     int CHOICE_DIR=4;
01938     int CHOICE_CODE=5;
01939 
01940     wxSingleChoiceDialog dlg(this, (retry2!="")?wxT("Access denied.  What would you like to do?"):wxT("What would you like to do?"),
01941                              (retry2!="")?wxT("Access denied"):wxT("Set up repository"), has_dir?6:4, choices);
01942     
01943     if (dlg.ShowModal() != wxID_OK) {
01944         return;
01945     }
01946  
01947     {
01948         int argc = 2;
01949         char *argv[] = {
01950             fossil(),
01951             (char*)"info",
01952             NULL };
01953         ssfossil(argc,argv,true);
01954     }
01955 
01956     int choice = dlg.GetSelection();
01957 
01958     if (source=="") {
01959         source = conv(autoSyncTip);
01960     }
01961     wxURL url = conv(source);
01962     //printf("source is %s\n", source.c_str());
01963 
01964     if (choice==CHOICE_DIR) {
01965         askPath = true;
01966         havePath();
01967         return;
01968     }
01969 
01970     if (choice==CHOICE_CODE||choice==CHOICE_FORK) {
01971         if (projectCodeTip.IsEmpty()) {
01972             wxMessageDialog dlg(NULL, wxT("Please connect to an existing repository first"), wxT("No repository"), 
01973                                 wxOK|wxICON_ERROR);
01974             dlg.ShowModal();
01975             return;
01976         }
01977     }
01978 
01979     if (choice==CHOICE_CODE) {
01980         wxTextEntryDialog dlg(NULL, wxT("Here is the project code.\nThis may be needed when forking a repository."), wxT("Project code"), projectCodeTip);
01981         dlg.ShowModal();
01982         return;
01983     }
01984 
01985     wxString target = wxT("");
01986     if (choice==CHOICE_NEW||choice==CHOICE_FORK) {
01987         wxString choices[] = { 
01988             wxT("chiselapp.com"), 
01989             wxT("share.find.coop"), 
01990             wxT("I've already made the new repository"), 
01991         };
01992 
01993         wxString full_choices[] = {
01994             wxT("http://chiselapp.com"),
01995             wxT("http://share.find.coop/repo/new/"),
01996         };
01997         
01998         wxSingleChoiceDialog 
01999             dlg(this, wxT("Please select a host for your new repository."),
02000                 wxT("Select host"), (choice==CHOICE_FORK)?3:2, choices);
02001 
02002         if (dlg.ShowModal() != wxID_OK) {
02003             return;
02004         }
02005 
02006         int choice2 = dlg.GetSelection();
02007         if (choice2<2) {
02008             target = full_choices[choice2];
02009             ::wxLaunchDefaultBrowser(target);
02010         }
02011         if (choice!=CHOICE_FORK) {
02012             return;
02013         }
02014     }
02015 
02016     if (choice==CHOICE_FORK) {
02017         wxTextEntryDialog dlg4(NULL, wxT("If asked, here is the project code:"), wxT("Project code"), projectCodeTip);
02018         if (dlg4.ShowModal()!=wxID_OK) return;
02019 
02020         wxTextEntryDialog dlg3(NULL, wxT("Repository link"), wxT("Enter repository"), conv(source));
02021         if (dlg3.ShowModal()!=wxID_OK) return;
02022         url = dlg3.GetValue();
02023 
02024     }
02025     if (choice==CHOICE_CONNECT) {
02026         /*
02027         if (has_dir) {
02028         } else {
02029         */
02030         Sync();
02031         return;
02032     }
02033 
02034     wxString user = url.GetUser();
02035     wxTextEntryDialog dlg1(NULL, wxT("Username needed to access the repository"), wxT("Enter username"), user);
02036     if (dlg1.ShowModal()!=wxID_OK) return;
02037     wxPasswordEntryDialog dlg2(NULL, wxT("Password needed to access the repository"), wxT("Enter password"), url.GetPassword());
02038     if (dlg2.ShowModal()!=wxID_OK) return;
02039 
02040     wxString username = dlg1.GetValue();
02041     wxString pword = dlg2.GetValue();
02042     wxString protocol = url.GetScheme();
02043     if (protocol.IsEmpty()) {
02044         protocol = wxT("http");
02045     }
02046     wxString current = url.BuildURI();
02047     int firstAt = current.Find('@');
02048     if (firstAt!=wxNOT_FOUND) {
02049         current = current.Mid(firstAt+1);
02050     }
02051     firstAt = current.Find(wxT("://"));
02052     if (firstAt!=wxNOT_FOUND) {
02053         current = current.Mid(firstAt+3);
02054     }
02055     if (!username.IsEmpty()) {
02056         current = protocol + wxT("://") + username + wxT(":") + pword + 
02057             wxT("@") + current;
02058     } else {
02059         current = protocol + wxT("://") + current;
02060     }
02061     source = conv(current);
02062     //printf("Source set to %s\n", source.c_str());
02063 
02064     /*
02065         source = string("http://") +
02066             FOSSIL_USERNAME + ":" + conv(dlg.GetValue()) + "@" +
02067             FOSSIL_ROOT + FOSSIL_REPO;
02068         printf("Source set to %s\n", source.c_str());
02069     */
02070 
02071     {
02072         next = "retryable";
02073         retry = retry2;
02074         if (retry2!="clone") {
02075             int argc = 3;
02076             char *argv[] = {
02077                 fossil(),
02078                 (char*)retry2.c_str(),
02079                 (char*)source.c_str(),
02080                 NULL };
02081             ssfossil(argc,argv);
02082         } else {
02083             Sync();
02084         }
02085     }
02086 }
02087 
02088 void CoopyFrame::OnPush(wxCommandEvent& event) {
02089     int argc = 3;
02090     char *argv[] = {
02091         fossil(),
02092         (char*)"push",
02093         (char*)destination.c_str(),
02094         NULL };
02095     ssfossil(argc,argv);
02096 }
02097 
02098 void CoopyFrame::OnCommit(wxCommandEvent& event) {
02099     retry = "push";
02100     writeWouldFork = false;
02101     writeAuthorizationFailed = false;
02102     //printf("Should commit\n");
02103     //startStream();
02104     if (havePath()) {
02105         updateListing();
02106         pushListing();
02107         //if (haveDestination()) {
02108             doFiles(getExtras(),"add");
02109             list<string> changes = getChanges();
02110             list<string> missing = getMissing(changes);
02111             if (missing.size()>0) {
02112                 string msg = "";
02113                 for (list<string>::const_iterator it = missing.begin();
02114                      it != missing.end();
02115                      it++) {
02116                     msg += it->c_str();
02117                     msg += " is missing";
02118                     msg += "\n";
02119                 }
02120                 msg += "Should this/these be removed in the repository?";
02121                 //printf("Message is %s\n", msg.c_str());
02122                 wxMessageDialog dlg(NULL, conv(msg), wxT(""), 
02123                                     wxYES_NO|wxCANCEL);
02124                 if (dlg.ShowModal()!=wxID_YES) {
02125                     endStream();
02126                     return;
02127                 }
02128                 doFiles(missing,"rm");
02129                 changes = getChanges();
02130             }
02131             string msg = "";
02132             for (list<string>::const_iterator it = changes.begin();
02133                  it != changes.end();
02134                  it++) {
02135                 msg += it->c_str();
02136                 msg += "\n";
02137             }
02138             if (msg!="") {
02139                 msg += "Enter brief description of changes";
02140                 //printf("Message is %s\n", msg.c_str());
02141                 wxString message = conv(CoopyApp::fossil_message);
02142                 bool ok = true;
02143                 if (message == wxT("")) {
02144                     wxTextEntryDialog dlg(NULL, conv(msg));
02145                     ok = (dlg.ShowModal()==wxID_OK);
02146                     message = dlg.GetValue();
02147                 } else {
02148                     CoopyApp::fossil_message = "";
02149                 }
02150                 if (ok) {
02151                     commit_message = conv(message);
02152                     if (commit_message == "") {
02153                         commit_message = "[from coopy]";
02154                     }
02155                     int argc = 4;
02156                     // commit currently fails if called twice, unless username
02157                     // specified (need to remove some global state from fossil)
02158                     char *argv[] = {
02159                         fossil(),
02160                         (char*)"commit",
02161                         //(char*)"--user",
02162                         //(char*)FOSSIL_USERNAME,
02163                         (char*)"-m",
02164                         (char*)commit_message.c_str(),
02165                         NULL };
02166                     next = "revertable";
02167                     ssfossil(argc,argv);
02168                     return;
02169                 } else {
02170                     return;
02171                 }
02172             } else {
02173                 int argc = 2;
02174                 // commit currently fails if called twice, unless username
02175                 // specified (need to remove some global state from fossil)
02176                 char *argv[] = {
02177                     fossil(),
02178                     (char*)"push",
02179                     NULL };
02180                 next = "revertable";
02181                 ssfossil(argc,argv);
02182                 //msg = "No changes!";
02183                 //addLog(wxT("No changes to push"));
02184                 //CheckEnd();
02185             }
02186             //}
02187     }
02188     //endStream();
02189     //OnPush(event);
02190 }
02191 
02192 CoopyFrame::CoopyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
02193     : wxFrame((wxFrame *)NULL, -1, title, pos, size)
02194 {
02195     //m_textCtrl = NULL;
02196     background = false;
02197 
02198     logging = false;
02199     path = "";
02200     source = "";
02201     commit_message = "";
02202 
02203     writeWouldFork = false;
02204     writeAuthorizationFailed = false;
02205 
02206     wxMenu *menuFile = new wxMenu;
02207 
02208     menuFile->Append( ID_Sync, _T("Pull &in...") );
02209     menuFile->Append( ID_Commit, _T("Push &out...") );
02210     menuFile->Append( ID_Create, _T("Set up &repository...") );
02211     menuFile->Append( ID_Diff, _T("&Diff...") );
02212     menuFile->Append( ID_Patch, _T("&Patch...") );
02213     menuFile->Append( ID_Merge, _T("&Merge...") );
02214     menuFile->Append( ID_About, _T("&About...") );
02215     menuFile->AppendSeparator();
02216     menuFile->Append( ID_Quit, _T("E&xit") );
02217 
02218     wxMenuBar *menuBar = new wxMenuBar;
02219     menuBar->Append( menuFile, _T("&File") );
02220 
02221     SetMenuBar( menuBar );
02222 
02223     CreateStatusBar();
02224     SetStatusText( _T("Welcome to Coopy!") );
02225 }
02226 
02227 void CoopyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
02228 {
02229     //wxCloseEvent ev;
02230     //wxPostEvent(this,ev);
02231     Close(TRUE);
02232 }
02233 
02234 void CoopyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
02235 {
02236     wxMessageBox(_T("Welcome to coopy!\n\
02237 Now go back to work."),
02238                  _T("About coopy"), wxOK | wxICON_INFORMATION, this);
02239 }
02240 
02241 void CoopyApp::OnKey(wxKeyEvent& e) {
02242     if(e.GetModifiers() == wxMOD_ALT) {
02243         switch(e.GetKeyCode()) {
02244         case 'T':
02245             ((CoopyFrame *)store_frame)->OnFocusDbList();
02246             break;
02247         default:
02248             e.Skip();
02249             break;
02250         }
02251     } else {
02252         e.Skip();
02253     }
02254 }
02255 
02256 
02257 #ifdef _WIN32
02258 
02259 FILE *FOUT = NULL;
02260 
02261 int WINAPI WinMain(HINSTANCE hInstance,
02262                    HINSTANCE hPrevInstance,
02263                    LPSTR m_lpCmdLine, int nCmdShow) {
02264 
02265     //g_hinstance = (int)(hInstance);    
02266     return wxEntry(hInstance,hPrevInstance,m_lpCmdLine,nCmdShow);
02267 }
02268 
02269 #endif
02270 
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines