COOPY » Guide
version 0.6.5
|
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