From a2e21f79f2ea136b6b4f6de5b03618ee1ccc7635 Mon Sep 17 00:00:00 2001 From: Jean-Marie Verdun Date: Mon, 26 Aug 2019 00:16:58 +0200 Subject: [PATCH] Add initial version of the Cloud workbench --- src/App/Document.cpp | 46 ++ src/App/Document.h | 4 + src/Base/Reader.cpp | 12 + src/Base/Reader.h | 13 +- src/Gui/Document.cpp | 44 +- src/Mod/CMakeLists.txt | 17 + src/Mod/Cloud/App/AppCloud.cpp | 696 ++++++++++++++++++ src/Mod/Cloud/App/AppCloud.h | 145 ++++ src/Mod/Cloud/App/CMakeLists.txt | 34 + src/Mod/Cloud/App/PreCompiled.cpp | 24 + src/Mod/Cloud/App/PreCompiled.h | 61 ++ src/Mod/Cloud/CMakeLists.txt | 30 + src/Mod/Cloud/Cloud.dox | 3 + src/Mod/Cloud/Gui/AppCloudGui.cpp | 82 +++ src/Mod/Cloud/Gui/CMakeLists.txt | 46 ++ src/Mod/Cloud/Gui/Command.cpp | 63 ++ src/Mod/Cloud/Gui/PreCompiled.cpp | 24 + src/Mod/Cloud/Gui/PreCompiled.h | 70 ++ src/Mod/Cloud/Gui/Resources/Cloud.qrc | 4 + .../Gui/Resources/icons/CloudWorkbench.svg | 17 + src/Mod/Cloud/Gui/Workbench.cpp | 65 ++ src/Mod/Cloud/Gui/Workbench.h | 47 ++ src/Mod/Cloud/Init.py | 2 + src/Mod/Cloud/InitGui.py | 17 + 24 files changed, 1538 insertions(+), 28 deletions(-) create mode 100644 src/Mod/Cloud/App/AppCloud.cpp create mode 100644 src/Mod/Cloud/App/AppCloud.h create mode 100644 src/Mod/Cloud/App/CMakeLists.txt create mode 100644 src/Mod/Cloud/App/PreCompiled.cpp create mode 100644 src/Mod/Cloud/App/PreCompiled.h create mode 100644 src/Mod/Cloud/CMakeLists.txt create mode 100644 src/Mod/Cloud/Cloud.dox create mode 100644 src/Mod/Cloud/Gui/AppCloudGui.cpp create mode 100644 src/Mod/Cloud/Gui/CMakeLists.txt create mode 100644 src/Mod/Cloud/Gui/Command.cpp create mode 100644 src/Mod/Cloud/Gui/PreCompiled.cpp create mode 100644 src/Mod/Cloud/Gui/PreCompiled.h create mode 100644 src/Mod/Cloud/Gui/Resources/Cloud.qrc create mode 100644 src/Mod/Cloud/Gui/Resources/icons/CloudWorkbench.svg create mode 100644 src/Mod/Cloud/Gui/Workbench.cpp create mode 100644 src/Mod/Cloud/Gui/Workbench.h create mode 100644 src/Mod/Cloud/Init.py create mode 100644 src/Mod/Cloud/InitGui.py diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 2a7ec9f301..0d2b38365b 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -1268,6 +1268,52 @@ bool Document::isTransactionEmpty() const return true; } +void Document::emptyDocument() +{ + this->d->activeObject = 0; + + if(this->d->objectArray.size()) { + GetApplication().signalDeleteDocument(*this); + this->d->objectArray.clear(); + for(auto &v : this->d->objectMap) { + v.second->setStatus(ObjectStatus::Destroy, true); + delete(v.second); + } + this->d->objectMap.clear(); + this->d->objectIdMap.clear(); + GetApplication().signalNewDocument(*this,false); + } + + Base::FlagToggler<> flag(_IsRestoring,false); + + setStatus(Document::PartialDoc,false); + + this->d->clearRecomputeLog(); + this->d->objectArray.clear(); + this->d->objectMap.clear(); + this->d->objectIdMap.clear(); + this->d->lastObjectId = 0; +} + +void Document::resetTouched() +{ +/* + for (std::map::iterator It= this->d->objectMap.begin();It!=this->d->objectMap.end();++It) { + It->second->connectRelabelSignals(); + try { + It->second->onDocumentRestored(); + It->second->ExpressionEngine.onDocumentRestored(); + } + catch (const Base::Exception& e) { + Base::Console().Error("Error in %s: %s\n", It->second->Label.getValue(), e.what()); + } + It->second->purgeTouched(); + } +*/ +} + + + void Document::clearUndos() { if(isPerformingTransaction() || d->committing) { diff --git a/src/App/Document.h b/src/App/Document.h index 8b2e5f3b8c..c8ab105e71 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -179,6 +179,10 @@ public: boost::signals2::signal signalChangePropertyEditor; //@} + + void resetTouched(); + void emptyDocument(); + /** @name File handling of the document */ //@{ /// Save the Document under a new Name diff --git a/src/Base/Reader.cpp b/src/Base/Reader.cpp index 8346c225a3..1e0b554a10 100644 --- a/src/Base/Reader.cpp +++ b/src/Base/Reader.cpp @@ -335,6 +335,8 @@ void Base::XMLReader::readFiles(zipios::ZipInputStream &zipstream) const try { Base::Reader reader(zipstream, jt->FileName, FileVersion); jt->Object->RestoreDocFile(reader); + if ( reader.getLocalReader() != nullptr ) + reader.getLocalReader()->readFiles(zipstream); } catch(...) { // For any exception we just continue with the next file. @@ -576,3 +578,13 @@ std::istream& Base::Reader::getStream() return this->_str; } +void Base::Reader::initLocalReader(Base::XMLReader *ptr) +{ + + this->localreader=ptr; +} + +Base::XMLReader *Base::Reader::getLocalReader() +{ + return(this->localreader); +} diff --git a/src/Base/Reader.h b/src/Base/Reader.h index 08c96018f8..4950d02564 100644 --- a/src/Base/Reader.h +++ b/src/Base/Reader.h @@ -207,6 +207,11 @@ public: bool testStatus(ReaderStatus pos) const; /// set the status bits void setStatus(ReaderStatus pos, bool on); + struct FileEntry { + std::string FileName; + Base::Persistence *Object; + }; + std::vector FileList; protected: /// read the next element @@ -281,11 +286,6 @@ protected: bool _valid; bool _verbose; - struct FileEntry { - std::string FileName; - Base::Persistence *Object; - }; - std::vector FileList; std::vector FileNames; std::bitset<32> StatusBits; @@ -298,11 +298,14 @@ public: std::istream& getStream(); std::string getFileName() const; int getFileVersion() const; + void initLocalReader(Base::XMLReader *ptr); + Base::XMLReader *getLocalReader(); private: std::istream& _str; std::string _name; int fileVersion; + Base::XMLReader *localreader=nullptr; }; } diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index af51f2acd7..8a7118561e 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -1189,20 +1189,21 @@ void Document::Restore(Base::XMLReader &reader) void Document::RestoreDocFile(Base::Reader &reader) { // We must create an XML parser to read from the input stream - Base::XMLReader xmlReader("GuiDocument.xml", reader); - xmlReader.FileVersion = reader.getFileVersion(); + Base::XMLReader *localreader; + localreader = new Base::XMLReader("GuiDocument.xml", reader); + localreader->FileVersion = reader.getFileVersion(); - xmlReader.readElement("Document"); - long scheme = xmlReader.getAttributeAsInteger("SchemaVersion"); - xmlReader.DocumentSchema = scheme; + localreader->readElement("Document"); + long scheme = localreader->getAttributeAsInteger("SchemaVersion"); + localreader->DocumentSchema = scheme; - bool hasExpansion = xmlReader.hasAttribute("HasExpansion"); + bool hasExpansion = localreader->hasAttribute("HasExpansion"); if(hasExpansion) { auto tree = TreeWidget::instance(); if(tree) { auto docItem = tree->getDocumentItem(this); if(docItem) - docItem->Restore(xmlReader); + docItem->Restore(*localreader); } } @@ -1212,32 +1213,32 @@ void Document::RestoreDocFile(Base::Reader &reader) // SchemeVersion "1" if (scheme == 1) { // read the viewproviders itself - xmlReader.readElement("ViewProviderData"); - int Cnt = xmlReader.getAttributeAsInteger("Count"); + localreader->readElement("ViewProviderData"); + int Cnt = localreader->getAttributeAsInteger("Count"); for (int i=0; ireadElement("ViewProvider"); + std::string name = localreader->getAttribute("name"); bool expanded = false; - if (!hasExpansion && xmlReader.hasAttribute("expanded")) { - const char* attr = xmlReader.getAttribute("expanded"); + if (!hasExpansion && localreader->hasAttribute("expanded")) { + const char* attr = localreader->getAttribute("expanded"); if (strcmp(attr,"1") == 0) { expanded = true; } } ViewProvider* pObj = getViewProviderByName(name.c_str()); if (pObj) // check if this feature has been registered - pObj->Restore(xmlReader); + pObj->Restore(*localreader); if (pObj && expanded) { Gui::ViewProviderDocumentObject* vp = static_cast(pObj); this->signalExpandObject(*vp, Gui::ExpandItem,0,0); } - xmlReader.readEndElement("ViewProvider"); + localreader->readEndElement("ViewProvider"); } - xmlReader.readEndElement("ViewProviderData"); + localreader->readEndElement("ViewProviderData"); // read camera settings - xmlReader.readElement("Camera"); - const char* ppReturn = xmlReader.getAttribute("settings"); + localreader->readElement("Camera"); + const char* ppReturn = localreader->getAttribute("settings"); cameraSettings.clear(); if(ppReturn && ppReturn[0]) { saveCameraSettings(ppReturn); @@ -1255,13 +1256,10 @@ void Document::RestoreDocFile(Base::Reader &reader) } } - xmlReader.readEndElement("Document"); - - // In the file GuiDocument.xml new data files might be added - if (!xmlReader.getFilenames().empty()) - xmlReader.readFiles(static_cast(reader.getStream())); + localreader->readEndElement("Document"); // reset modified flag + reader.initLocalReader(localreader); setModified(false); } diff --git a/src/Mod/CMakeLists.txt b/src/Mod/CMakeLists.txt index a6906e165b..5d127f1ecc 100644 --- a/src/Mod/CMakeLists.txt +++ b/src/Mod/CMakeLists.txt @@ -102,6 +102,23 @@ if(BUILD_FEM) add_subdirectory(Fem) endif(BUILD_FEM) +if(BUILD_CLOUD) +#------------------------------ OpenSSL and CURL ------------------------- + IF (APPLE) + set(OPENSSL_ROOT_DIR ${HOMEBREW_PREFIX}/Cellar/openssl/*) + ENDIF(APPLE) + find_package(OPENSSL REQUIRED) + IF(OPENSSL_FOUND) + message(STATUS "openssl-${OPENSSL_VERSION} has been found\n") + ENDIF(OPENSSL_FOUND) + find_package(CURL REQUIRED) + IF(CURL_FOUND) + message(STATUS "CURL has been found\n") + ENDIF(CURL_FOUND) +# ------------------------------------------------------------------------ + add_subdirectory(Cloud) +endif(BUILD_CLOUD) + if(BUILD_SANDBOX) add_subdirectory(Sandbox) endif(BUILD_SANDBOX) diff --git a/src/Mod/Cloud/App/AppCloud.cpp b/src/Mod/Cloud/App/AppCloud.cpp new file mode 100644 index 0000000000..6297be283a --- /dev/null +++ b/src/Mod/Cloud/App/AppCloud.cpp @@ -0,0 +1,696 @@ +/*************************************************************************** + * Copyright (c) 2019 Jean-Marie Verdun jmverdun3@gmail.com * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "AppCloud.h" + +using namespace App; + +/* Python entry */ +PyMOD_INIT_FUNC(Cloud) +{ + // ADD YOUR CODE HERE + // + // + PyObject* mod = Cloud::initModule(); + Base::Console().Log("Loading Cloud module... done\n"); + PyMOD_Return(mod); +} + +Py::Object Cloud::Module::sCloudUrl(const Py::Tuple& args) +{ + char *Url; + if (!PyArg_ParseTuple(args.ptr(), "et","utf-8",&Url)) // convert args: Python->C + return Py::None(); + if (this->Url.getStrValue() != Url) { + this->Url.setValue(Url); + } + return Py::None(); +} + +Py::Object Cloud::Module::sCloudAccessKey(const Py::Tuple& args) +{ + char *AccessKey; + if (!PyArg_ParseTuple(args.ptr(), "et","utf-8", &AccessKey)) // convert args: Python->C + return Py::None(); + if (this->AccessKey.getStrValue() != AccessKey) { + this->AccessKey.setValue(AccessKey); + } + return Py::None(); +} + +Py::Object Cloud::Module::sCloudSecretKey(const Py::Tuple& args) +{ + char *SecretKey; + if (!PyArg_ParseTuple(args.ptr(), "et","utf-8", &SecretKey)) // convert args: Python->C + return Py::None(); + if (this->SecretKey.getStrValue() != SecretKey) { + this->SecretKey.setValue(SecretKey); + } + return Py::None(); +} + +Py::Object Cloud::Module::sCloudTcpPort(const Py::Tuple& args) +{ + char *TcpPort; + if (!PyArg_ParseTuple(args.ptr(), "et","utf-8", &TcpPort)) // convert args: Python->C + return Py::None(); + if (this->TcpPort.getStrValue() != TcpPort) { + this->TcpPort.setValue(TcpPort); + } + return Py::None(); +} + +Py::Object Cloud::Module::sCloudSave(const Py::Tuple& args) +{ + char *pDoc; + if (!PyArg_ParseTuple(args.ptr(), "et","utf-8", &pDoc)) // convert args: Python->C + return Py::None(); + cloudSave(pDoc); + return Py::None(); +} + + +Py::Object Cloud::Module::sCloudRestore(const Py::Tuple& args) +{ + char *pDoc; + if (!PyArg_ParseTuple(args.ptr(), "et", "utf-8", &pDoc)) // convert args: Python->C + return Py::None(); + cloudRestore(pDoc); + return Py::None(); +} + + +Cloud::CloudWriter::CloudWriter(const char* Url, const char* AccessKey, const char* SecretKey, const char* TcpPort, const char* Bucket) +{ + this->Url=Url; + this->AccessKey=AccessKey; + this->SecretKey=SecretKey; + this->TcpPort=TcpPort; + this->Bucket=Bucket; + this->FileName=""; + // Amazon S3 and Swift require the timezone to be define to + // GMT. As to simplify the conversion this is performed through the TZ + // environment variable and a call to localtime as to convert output of gettimeofday + setenv("TZ","GMT",1); +} + +Cloud::CloudWriter::~CloudWriter() +{ +} + +size_t CurlWrite_CallbackFunc_StdString(void *contents, size_t size, size_t nmemb, std::string *s) +{ + size_t newLength = size*nmemb; + try + { + s->append((char*)contents, newLength); + } + catch(std::bad_alloc &e) + { + //handle memory problem + return 0; + } + return newLength; +} + +void Cloud::CloudReader::checkElement(DOMElement* element) { + char* name = XMLString::transcode(element->getTagName()); + if ( strcmp(name, "Key") == 0 ) + print=1; + XMLString::release(&name); + +} + +void Cloud::CloudReader::checkText(DOMText* text) { + + XMLCh* buffer = new XMLCh[XMLString::stringLen(text->getData()) + 1]; + XMLString::copyString(buffer, text->getData()); + XMLString::trim(buffer); + struct Cloud::CloudReader::FileEntry *new_entry; + char* content=XMLString::transcode(buffer); + delete[] buffer; + if ( print ) + { + new_entry=new Cloud::CloudReader::FileEntry; + strcpy(new_entry->FileName,content); + Cloud::CloudReader::FileList.push_back(new_entry); + } + print=0; + XMLString::release(&content); +} + +void Cloud::CloudReader::addFile(struct Cloud::CloudReader::FileEntry *new_entry) +{ + Cloud::CloudReader::FileList.push_back(new_entry); +} + +void Cloud::CloudReader::checkXML(DOMNode* node) { + if (node) { + switch (node->getNodeType()) { + case DOMNode::ELEMENT_NODE: + checkElement(static_cast(node)); + break; + case DOMNode::TEXT_NODE: + checkText(static_cast(node)); + break; + default: + break; + } + DOMNode* child = node->getFirstChild(); + while (child) { + DOMNode* next = child->getNextSibling(); + checkXML(child); + child = next; + } + } +} + + + +struct data_buffer +{ + const char *ptr; + size_t remaining_size; +}; + +Cloud::CloudReader::~CloudReader() +{ +} + +Cloud::CloudReader::CloudReader(const char* Url, const char* AccessKey, const char* SecretKey, const char* TcpPort, const char* Bucket) +{ + + struct timeval tv; + struct tm *tm; + char date_formatted[256]; + char StringToSign[1024]; + unsigned char *digest; + CURL *curl; + CURLcode res; + + std::string s; + + + this->Url=Url; + this->AccessKey=AccessKey; + this->SecretKey=SecretKey; + this->TcpPort=TcpPort; + this->Bucket=Bucket; + + // Amazon S3 and Swift require the timezone to be define to + // GMT. As to simplify the conversion this is performed through the TZ + // environment variable and a call to localtime as to convert output of gettimeofday + setenv("TZ","GMT",1); + + // We must get the directory content + + + gettimeofday(&tv,NULL); + tm = localtime(&tv.tv_sec); + strftime(date_formatted,256,"%a, %d %b %Y %T %z", tm); + + sprintf(StringToSign,"GET\n\napplication/xml\n%s\n/%s/", date_formatted, this->Bucket); + + // We have to use HMAC encoding and SHA1 + digest=HMAC(EVP_sha1(),this->SecretKey,strlen(this->SecretKey), + (const unsigned char *)&StringToSign,strlen(StringToSign),NULL,NULL); + + // Let's build the Header and call to curl + curl_global_init(CURL_GLOBAL_ALL); + curl = curl_easy_init(); + if ( curl ) + { + struct curl_slist *chunk = NULL; + char header_data[1024]; + // Let's build our own header + sprintf(header_data,"Host: %s:%s", strtok((char *)this->Url,"http://"), + this->TcpPort); + chunk = curl_slist_append(chunk, header_data); + sprintf(header_data,"Date: %s", date_formatted); + chunk = curl_slist_append(chunk, header_data); + chunk = curl_slist_append(chunk, "Content-Type: application/xml"); + std::string digest_str; + digest_str=Base::base64_encode(digest,strlen((const char *)digest)); + sprintf(header_data,"Authorization: AWS %s:%s", this->AccessKey, + digest_str.c_str()); + chunk = curl_slist_append(chunk, header_data); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); + sprintf(header_data,"%s:%s/%s/", this->Url,this->TcpPort, + this->Bucket); + curl_easy_setopt(curl, CURLOPT_URL, header_data); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_StdString); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s); + // curl read a file not a memory buffer (it shall be able to do it) + + res = curl_easy_perform(curl); + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + curl_easy_cleanup(curl); + std::stringstream input(s); + + try { XMLPlatformUtils::Initialize(); } + catch (const XMLException& toCatch) { + char* message = XMLString::transcode(toCatch.getMessage()); + cout << "Error during initialization! :\n" + << message << "\n"; + XMLString::release(&message); + return ; + } + + XercesDOMParser* parser = new XercesDOMParser(); + parser->setValidationScheme(XercesDOMParser::Val_Always); + parser->setDoNamespaces(true); + + xercesc::MemBufInputSource myxml_buf((const XMLByte *const)s.c_str(), s.size(), + "myxml (in memory)"); + + parser->parse(myxml_buf); + DOMDocument* dom=parser->getDocument(); + checkXML(dom); + // Dumping the filelist name + } + + +} + +void Cloud::CloudReader::DownloadFile(Cloud::CloudReader::FileEntry *entry) +{ + struct timeval tv; + struct tm *tm; + char date_formatted[256]; + char StringToSign[1024]; + unsigned char *digest; + CURL *curl; + CURLcode res; + + std::string s; + + // We must get the directory content + + + gettimeofday(&tv,NULL); + tm = localtime(&tv.tv_sec); + strftime(date_formatted,256,"%a, %d %b %Y %T %z", tm); + + // CHANGEME + sprintf(StringToSign,"GET\n\napplication/octet-stream\n%s\n/%s/%s", date_formatted, this->Bucket, entry->FileName); + + // We have to use HMAC encoding and SHA1 + digest=HMAC(EVP_sha1(),this->SecretKey,strlen(this->SecretKey), + (const unsigned char *)&StringToSign,strlen(StringToSign),NULL,NULL); + + // Let's build the Header and call to curl + curl_global_init(CURL_GLOBAL_ALL); + curl = curl_easy_init(); + if ( curl ) + { + struct curl_slist *chunk = NULL; + char header_data[1024]; + // Let's build our own header + sprintf(header_data,"Host: %s:%s", strtok((char *)this->Url,"http://"), + this->TcpPort); + chunk = curl_slist_append(chunk, header_data); + sprintf(header_data,"Date: %s", date_formatted); + chunk = curl_slist_append(chunk, header_data); + chunk = curl_slist_append(chunk, "Content-Type: application/octet-stream"); + std::string digest_str; + digest_str=Base::base64_encode(digest,strlen((const char *)digest)); + sprintf(header_data,"Authorization: AWS %s:%s", this->AccessKey, + digest_str.c_str()); + chunk = curl_slist_append(chunk, header_data); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); + sprintf(header_data,"%s:%s/%s/%s", this->Url,this->TcpPort, + this->Bucket,entry->FileName); + curl_easy_setopt(curl, CURLOPT_URL, header_data); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_StdString); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s); + // curl read a file not a memory buffer (it shall be able to do it) + + res = curl_easy_perform(curl); + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + curl_easy_cleanup(curl); + + entry->FileStream << s; + } + +} + +struct Cloud::CloudReader::FileEntry * Cloud::CloudReader::GetEntry(std::string FileName) +{ + struct Cloud::CloudReader::FileEntry *current_entry=NULL; + list::const_iterator it1; + + for(it1 = FileList.begin(); it1 != FileList.end(); ++it1) { + if ( strcmp(FileName.c_str(), (*it1)->FileName) == 0 ) + { + current_entry = (*it1); + break; + } + } + + if ( current_entry != NULL ) + { + (*it1)->touch=1; + DownloadFile(*it1); + } + + return(current_entry); +} + +int Cloud::CloudReader::isTouched(std::string FileName) +{ + list::const_iterator it1; + for(it1 = FileList.begin(); it1 != FileList.end(); ++it1) { + if ( strcmp(FileName.c_str(), (*it1)->FileName) == 0 ) + { + if ( (*it1)->touch ) + return(1); + else + return(0); + } + } + return(0); +} + + + +void Cloud::CloudWriter::putNextEntry(const char* file) +{ + this->FileName = file; + this->FileStream.str(""); + this->FileStream << std::fixed; + this->FileStream.precision(std::numeric_limits::digits10 + 1); + this->FileStream.setf(ios::fixed,ios::floatfield); + this->FileStream.imbue(std::locale::classic()); + +} + +bool Cloud::CloudWriter::shouldWrite(const std::string& , const Base::Persistence *) const +{ + return true; +} + +static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream) +{ + + struct data_buffer *local_ptr = (struct data_buffer *)stream; + size_t data_to_transfer = size * nmemb; + + if(local_ptr->remaining_size) { + // copy as much as possible from the source to the destination + size_t copy_this_much = local_ptr->remaining_size; + if(copy_this_much > data_to_transfer) + copy_this_much = data_to_transfer; + memcpy(ptr, local_ptr->ptr, copy_this_much); + + local_ptr->ptr += copy_this_much; + local_ptr->remaining_size -= copy_this_much; + return copy_this_much; + } + + return 0; +} + +void Cloud::CloudWriter::pushCloud(const char *FileName, const char *data, long size) +{ + struct timeval tv; + struct tm *tm; + char date_formatted[256]; + char StringToSign[1024]; + unsigned char *digest; + // char my_data[1024]="a que coucou"; + + CURL *curl; + CURLcode res; + + struct data_buffer curl_buffer; + + gettimeofday(&tv,NULL); + tm = localtime(&tv.tv_sec); + strftime(date_formatted,256,"%a, %d %b %Y %T %z", tm); + + // CHANGEME + sprintf(StringToSign,"PUT\n\napplication/octet-stream\n%s\n/%s/%s", date_formatted, this->Bucket, FileName); + + // We have to use HMAC encoding and SHA1 + digest=HMAC(EVP_sha1(),this->SecretKey,strlen(this->SecretKey), + (const unsigned char *)&StringToSign,strlen(StringToSign),NULL,NULL); + + // Let's build the Header and call to curl + curl_global_init(CURL_GLOBAL_ALL); + curl = curl_easy_init(); + if ( curl ) + { + struct curl_slist *chunk = NULL; + char header_data[1024]; + // Let's build our own header + sprintf(header_data,"Host: %s:%s", strtok((char *)this->Url,"http://"), + this->TcpPort); + chunk = curl_slist_append(chunk, header_data); + sprintf(header_data,"Date: %s", date_formatted); + chunk = curl_slist_append(chunk, header_data); + chunk = curl_slist_append(chunk, "Content-Type: application/octet-stream"); + std::string digest_str; + digest_str=Base::base64_encode(digest,strlen((const char *)digest)); + sprintf(header_data,"Authorization: AWS %s:%s", this->AccessKey, + digest_str.c_str()); + chunk = curl_slist_append(chunk, header_data); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + sprintf(header_data,"%s:%s/%s/%s", this->Url,this->TcpPort, + this->Bucket,FileName); + curl_easy_setopt(curl, CURLOPT_URL, header_data); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(curl, CURLOPT_PUT, 1L); + // curl read a file not a memory buffer (it shall be able to do it) + curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); + curl_buffer.ptr = data; + curl_buffer.remaining_size = (size_t) size; + + curl_easy_setopt(curl, CURLOPT_READDATA, &curl_buffer); + + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, + (curl_off_t)size); + + + res = curl_easy_perform(curl); + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + curl_easy_cleanup(curl); + } +} + +void Cloud::CloudWriter::writeFiles(void) +{ + + // use a while loop because it is possible that while + // processing the files new ones can be added + std::string tmp=""; + char *cstr; + size_t index = 0; + if ( strlen(this->FileName.c_str()) > 1 ) + { + // We must push the current buffer + const std::string tmp = this->FileStream.str(); + const char* cstr = tmp.data(); + pushCloud((const char *)this->FileName.c_str(),cstr, tmp.size()); + } + while (index < FileList.size()) { + FileEntry entry = FileList.begin()[index]; + + if (shouldWrite(entry.FileName, entry.Object)) { + this->FileStream.str(""); + this->FileStream.precision(std::numeric_limits::digits10 + 1); + this->FileStream.setf(ios::fixed,ios::floatfield); + this->FileStream.imbue(std::locale::classic()); + entry.Object->SaveDocFile(*this); + tmp = this->FileStream.str(); + cstr = (char *)tmp.data(); + pushCloud((const char *)entry.FileName.c_str(), (const char *)cstr, tmp.size()); + this->FileStream.str(""); + } + + index++; + } + + +} + + +bool Cloud::Module::cloudSave(const char *BucketName) +{ + Document* doc = GetApplication().getActiveDocument(); + + auto hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document"); + + // Save the name of the tip object in order to handle in Restore() + if (doc->Tip.getValue()) { + doc->TipName.setValue(doc->Tip.getValue()->getNameInDocument()); + } + + std::string LastModifiedDateString = Base::TimeInfo::currentDateTimeString(); + doc->LastModifiedDate.setValue(LastModifiedDateString.c_str()); + // set author if needed + bool saveAuthor = App::GetApplication().GetParameterGroupByPath + ("User parameter:BaseApp/Preferences/Document")->GetBool("prefSetAuthorOnSave",false); + if (saveAuthor) { + std::string Author = App::GetApplication().GetParameterGroupByPath + ("User parameter:BaseApp/Preferences/Document")->GetASCII("prefAuthor",""); + doc->LastModifiedBy.setValue(Author.c_str()); + } + if ( strcmp(BucketName, doc->Label.getValue()) != 0 ) + doc->Label.setValue(BucketName); + + Cloud::CloudWriter mywriter((const char*)this->Url.getStrValue().c_str(), + (const char*)this->AccessKey.getStrValue().c_str(), + (const char*)this->SecretKey.getStrValue().c_str(), + (const char*)this->TcpPort.getStrValue().c_str(), + BucketName); + + mywriter.putNextEntry("Document.xml"); + + if (hGrp->GetBool("SaveBinaryBrep", false)) + mywriter.setMode("BinaryBrep"); + mywriter.Stream() << "" << endl + << "" << endl; + doc->Save(mywriter); + + // Special handling for Gui document. + doc->signalSaveDocument(mywriter); + + // write additional files + mywriter.writeFiles(); + + return(true); +} + +void readFiles(Cloud::CloudReader reader, Base::XMLReader *xmlreader) +{ + // It's possible that not all objects inside the document could be created, e.g. if a module + // is missing that would know these object types. So, there may be data files inside the Cloud + // file that cannot be read. We simply ignore these files. + // On the other hand, however, it could happen that a file should be read that is not part of + // the zip file. This happens e.g. if a document is written without GUI up but is read with GUI + // up. In this case the associated GUI document asks for its file which is not part of the + // file, then. + // In either case it's guaranteed that the order of the files is kept. + + std::vector::const_iterator it = xmlreader->FileList.begin(); + while ( it != xmlreader->FileList.end()) { + if ( reader.isTouched(it->FileName.c_str()) == 0 ) + { + Base::Reader localreader(reader.GetEntry(it->FileName.c_str())->FileStream,it->FileName, xmlreader->FileVersion); + it->Object->RestoreDocFile(localreader); + if ( localreader.getLocalReader() != nullptr ) + { + readFiles(reader, localreader.getLocalReader()); + } + } + it++; + } +} + + +bool Cloud::Module::cloudRestore (const char *BucketName) +{ + + Document* doc = GetApplication().getActiveDocument(); + // clean up if the document is not empty + // !TODO mind exceptions while restoring! + + doc->clearUndos(); + + doc->emptyDocument(); + + std::stringstream oss; + + Cloud::CloudReader myreader((const char*)this->Url.getStrValue().c_str(), + (const char*)this->AccessKey.getStrValue().c_str(), + (const char*)this->SecretKey.getStrValue().c_str(), + (const char*)this->TcpPort.getStrValue().c_str(), + BucketName); + + // we shall pass there the intial Document.xml file + + Base::XMLReader reader("Document.xml", myreader.GetEntry("Document.xml")->FileStream); + + if (!reader.isValid()) + throw Base::FileException("Error reading Document.xml file","Document.xml"); + + + GetApplication().signalStartRestoreDocument(*doc); + doc->setStatus(Document::Restoring, true); + + try { + // Document::Restore(reader); + doc->Restore(reader); + } + catch (const Base::Exception& e) { + Base::Console().Error("Invalid Document.xml: %s\n", e.what()); + } + + // Special handling for Gui document, the view representations must already + // exist, what is done in Restore(). + // Note: This file doesn't need to be available if the document has been created + // without GUI. But if available then follow after all data files of the App document. + + doc->signalRestoreDocument(reader); + + readFiles(myreader,&reader); + + // reset all touched + + doc->resetTouched(); + +// if(!doc->delaySignal) + doc->afterRestore(true); + + GetApplication().signalFinishRestoreDocument(*doc); + doc->setStatus(Document::Restoring, false); + return(true); + +} + diff --git a/src/Mod/Cloud/App/AppCloud.h b/src/Mod/Cloud/App/AppCloud.h new file mode 100644 index 0000000000..840d846d06 --- /dev/null +++ b/src/Mod/Cloud/App/AppCloud.h @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +using namespace App; +using namespace std; +using namespace xercesc; + +namespace Cloud { + +class BaseExport CloudReader +{ +public: + CloudReader(const char* Url, const char* AccessKey, const char* SecretKey, const char* TcpPort, const char* Bucket); + virtual ~CloudReader(); + int print=0; + + struct FileEntry + { + char FileName[1024]; + std::stringstream FileStream; + int touch=0; + }; + void checkText(DOMText* text); + void checkXML(DOMNode* node); + void checkElement(DOMElement* element); + void addFile(struct Cloud::CloudReader::FileEntry *new_entry); + struct FileEntry *GetEntry(std::string FileName); + void DownloadFile(Cloud::CloudReader::FileEntry *entry); + int isTouched(std::string FileName); +protected: + std::list FileList; + const char* Url; + const char* TcpPort; + const char* AccessKey; + const char* SecretKey; + const char* Bucket; +}; + +class Module : public Py::ExtensionModule +{ +public: + Module() : Py::ExtensionModule("Cloud") + { + add_varargs_method("cloudurl",&Module::sCloudUrl, + "cloudurl(string) -- Connect to a Cloud Storage service." + ); + + add_varargs_method("cloudaccesskey",&Module::sCloudAccessKey, + "cloudurl(string) -- Connect to a Cloud Storage service." + ); + + add_varargs_method("cloudsecretkey",&Module::sCloudSecretKey, + "cloudurl(string) -- Connect to a Cloud Storage service." + ); + + add_varargs_method("cloudtcpport",&Module::sCloudTcpPort, + "cloudurl(string) -- Connect to a Cloud Storage service." + ); + + add_varargs_method("cloudsave",&Module::sCloudSave, + "cloudurl(string) -- Connect to a Cloud Storage service." + ); + + add_varargs_method("cloudrestore",&Module::sCloudRestore, + "cloudurl(string) -- Connect to a Cloud Storage service." + ); + + initialize("This module is the Cloud module."); // register with Python + } + + virtual ~Module() {} + + App::PropertyString Url; + App::PropertyString TcpPort; + App::PropertyString AccessKey; + App::PropertyString SecretKey; + bool cloudSave(const char* BucketName); + bool cloudRestore(const char* BucketName); + +private: + Py::Object sCloudUrl (const Py::Tuple& args); + Py::Object sCloudAccessKey (const Py::Tuple& args); + Py::Object sCloudSecretKey (const Py::Tuple& args); + Py::Object sCloudTcpPort (const Py::Tuple& args); + Py::Object sCloudSave (const Py::Tuple& args); + Py::Object sCloudRestore (const Py::Tuple& args); + + +}; + +PyObject* initModule() +{ + return (new Module)->module().ptr(); +} + + +// This class is writing files to an S3 cloud storage class + +class BaseExport CloudWriter : public Base::Writer +{ +public: + CloudWriter(const char* Url, const char* AccessKey, const char* SecretKey, const char* TcpPort, const char* Bucket); + virtual ~CloudWriter(); + void pushCloud(const char *FileName, const char *data, long size); + void putNextEntry(const char* file); + virtual void writeFiles(void); + + virtual std::ostream &Stream(void){return FileStream;} + virtual bool shouldWrite(const std::string& name, const Base::Persistence *Object) const; + +protected: + std::string FileName; + const char* Url; + const char* TcpPort; + const char* AccessKey; + const char* SecretKey; + const char* Bucket; + std::stringstream FileStream; +}; + + +} + +void readFiles(Cloud::CloudReader reader, Base::XMLReader *xmlreader); diff --git a/src/Mod/Cloud/App/CMakeLists.txt b/src/Mod/Cloud/App/CMakeLists.txt new file mode 100644 index 0000000000..d51883b4f5 --- /dev/null +++ b/src/Mod/Cloud/App/CMakeLists.txt @@ -0,0 +1,34 @@ + +include_directories( + ${Boost_INCLUDE_DIRS} + ${OCC_INCLUDE_DIR} + ${PYTHON_INCLUDE_DIRS} + ${ZLIB_INCLUDE_DIR} + ${XercesC_INCLUDE_DIRS} + ${OPENSSL_INCLUDE_DIR} + ${CURL_INCLUDE_DIR} +) + +set(Cloud_LIBS + FreeCADApp + ${OPENSSL_LIBRARIES} + ${CURL_LIBRARIES} + ${XercesC_LIBRARIES} + ${Boost_LIBRARIES} + ${ZLIB_LIBRARIES} +) + +SET(Cloud_SRCS + AppCloud.cpp + PreCompiled.cpp + PreCompiled.h +) + +add_library(Cloud SHARED ${Cloud_SRCS}) +target_link_libraries(Cloud ${Cloud_LIBS}) + + +SET_BIN_DIR(Cloud Cloud /Mod/Cloud) +SET_PYTHON_PREFIX_SUFFIX(Cloud) + +install(TARGETS Cloud DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/src/Mod/Cloud/App/PreCompiled.cpp b/src/Mod/Cloud/App/PreCompiled.cpp new file mode 100644 index 0000000000..c32e030c6d --- /dev/null +++ b/src/Mod/Cloud/App/PreCompiled.cpp @@ -0,0 +1,24 @@ +/*************************************************************************** + * Copyright (c) YEAR YOUR NAME * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" diff --git a/src/Mod/Cloud/App/PreCompiled.h b/src/Mod/Cloud/App/PreCompiled.h new file mode 100644 index 0000000000..e03c28e313 --- /dev/null +++ b/src/Mod/Cloud/App/PreCompiled.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (c) YEAR YOUR NAME * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef APP_PRECOMPILED_H +#define APP_PRECOMPILED_H + +#include + +// Exporting of App classes +#ifdef FC_OS_WIN32 +# define CloudAppExport __declspec(dllexport) +#else // for Linux +# define CloudAppExport +#endif + +#ifdef _PreComp_ + +// standard +#include +#include +#include + +// STL +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Xerces +#include + +#endif //_PreComp_ + +#endif + diff --git a/src/Mod/Cloud/CMakeLists.txt b/src/Mod/Cloud/CMakeLists.txt new file mode 100644 index 0000000000..95457658e5 --- /dev/null +++ b/src/Mod/Cloud/CMakeLists.txt @@ -0,0 +1,30 @@ + +add_subdirectory(App) +if(BUILD_GUI) + add_subdirectory(Gui) +endif(BUILD_GUI) + +set(Cloud_Scripts + Init.py +) + +if(BUILD_GUI) + list (APPEND Cloud_Scripts InitGui.py) +endif(BUILD_GUI) + +add_custom_target(CloudScripts ALL + SOURCES ${Cloud_Scripts} +) + +fc_target_copy_resource_flat(CloudScripts + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_BINARY_DIR}/Mod/Cloud + ${Cloud_Scripts} +) + +install( + FILES + ${Cloud_Scripts} + DESTINATION + Mod/Cloud +) diff --git a/src/Mod/Cloud/Cloud.dox b/src/Mod/Cloud/Cloud.dox new file mode 100644 index 0000000000..b278c207c5 --- /dev/null +++ b/src/Mod/Cloud/Cloud.dox @@ -0,0 +1,3 @@ +/** \defgroup TEMPLATE Cloud + * \ingroup WORKBENCHES */ + diff --git a/src/Mod/Cloud/Gui/AppCloudGui.cpp b/src/Mod/Cloud/Gui/AppCloudGui.cpp new file mode 100644 index 0000000000..f14b070103 --- /dev/null +++ b/src/Mod/Cloud/Gui/AppCloudGui.cpp @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (c) YEAR YOUR NAME * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +#endif + +#include +#include +#include + +#include "Workbench.h" + +#include +#include + +// use a different name to CreateCommand() +void CreateCloudCommands(void); + + +namespace CloudGui { +class Module : public Py::ExtensionModule +{ +public: + Module() : Py::ExtensionModule("CloudGui") + { + initialize("This module is the CloudGui module."); // register with Python + } + + virtual ~Module() {} + +private: +}; + +PyObject* initModule() +{ + return (new Module)->module().ptr(); +} + +} // namespace CloudGui + + +/* Python entry */ +PyMOD_INIT_FUNC(CloudGui) +{ + if (!Gui::Application::Instance) { + PyErr_SetString(PyExc_ImportError, "Cannot load Gui module in console application."); + PyMOD_Return(0); + } + + // instantiating the commands + CreateCloudCommands(); + CloudGui::Workbench::init(); + + // ADD YOUR CODE HERE + // + // + PyObject* mod = CloudGui::initModule(); + Base::Console().Log("Loading GUI of Cloud module... done\n"); + PyMOD_Return(mod); +} diff --git a/src/Mod/Cloud/Gui/CMakeLists.txt b/src/Mod/Cloud/Gui/CMakeLists.txt new file mode 100644 index 0000000000..5e6688742c --- /dev/null +++ b/src/Mod/Cloud/Gui/CMakeLists.txt @@ -0,0 +1,46 @@ + +include_directories( + ${CMAKE_SOURCE_DIR}/src + ${CMAKE_CURRENT_BINARY_DIR} + ${Boost_INCLUDE_DIRS} + ${COIN3D_INCLUDE_DIRS} + ${ZLIB_INCLUDE_DIR} + ${PYTHON_INCLUDE_DIRS} + ${XercesC_INCLUDE_DIRS} +) + +set(CloudGui_LIBS + Cloud + FreeCADGui +) + +if (BUILD_QT5) + qt5_add_resources(Cloud_QRC_SRCS Resources/Cloud.qrc) +else() + qt4_add_resources(Cloud_QRC_SRCS Resources/Cloud.qrc) +endif() + +SET(CloudGui_SRCS + ${Cloud_QRC_SRCS} + AppCloudGui.cpp + Command.cpp + PreCompiled.cpp + PreCompiled.h + Workbench.cpp + Workbench.h +) + +SET(Cloud_SVG + Resources/icons/CloudWorkbench.svg +) + +add_library(CloudGui SHARED ${CloudGui_SRCS} ${Cloud_SVG}) +target_link_libraries(CloudGui ${CloudGui_LIBS}) + +fc_copy_sources(CloudGui "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Cloud" ${Cloud_SVG}) + +SET_BIN_DIR(CloudGui CloudGui /Mod/Cloud) +SET_PYTHON_PREFIX_SUFFIX(CloudGui) + +install(TARGETS CloudGui DESTINATION ${CMAKE_INSTALL_LIBDIR}) +INSTALL(FILES ${Cloud_SVG} DESTINATION "${CMAKE_INSTALL_DATADIR}/Mod/Cloud/Resources/icons") diff --git a/src/Mod/Cloud/Gui/Command.cpp b/src/Mod/Cloud/Gui/Command.cpp new file mode 100644 index 0000000000..91eed5443b --- /dev/null +++ b/src/Mod/Cloud/Gui/Command.cpp @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (c) YEAR YOUR NAME * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" +#ifndef _PreComp_ +#endif + +#include +#include +#include +#include + + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +//=========================================================================== +// CmdCloudTest THIS IS JUST A TEST COMMAND +//=========================================================================== +DEF_STD_CMD(CmdCloudTest) + +CmdCloudTest::CmdCloudTest() + :Command("Cloud_Test") +{ + sAppModule = "Cloud"; + sGroup = QT_TR_NOOP("Cloud"); + sMenuText = QT_TR_NOOP("Hello"); + sToolTipText = QT_TR_NOOP("Cloud Test function"); + sWhatsThis = "Cloud_Test"; + sStatusTip = QT_TR_NOOP("Cloud Test function"); + sPixmap = "Test1"; + sAccel = "CTRL+H"; +} + +void CmdCloudTest::activated(int) +{ + Base::Console().Message("Hello, World!\n"); +} + +void CreateCloudCommands(void) +{ + Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); + rcCmdMgr.addCommand(new CmdCloudTest()); +} diff --git a/src/Mod/Cloud/Gui/PreCompiled.cpp b/src/Mod/Cloud/Gui/PreCompiled.cpp new file mode 100644 index 0000000000..c32e030c6d --- /dev/null +++ b/src/Mod/Cloud/Gui/PreCompiled.cpp @@ -0,0 +1,24 @@ +/*************************************************************************** + * Copyright (c) YEAR YOUR NAME * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" diff --git a/src/Mod/Cloud/Gui/PreCompiled.h b/src/Mod/Cloud/Gui/PreCompiled.h new file mode 100644 index 0000000000..d2b3924106 --- /dev/null +++ b/src/Mod/Cloud/Gui/PreCompiled.h @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (c) YEAR YOUR NAME * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef GUI_PRECOMPILED_H +#define GUI_PRECOMPILED_H + +#include + +// Importing of App classes +#ifdef FC_OS_WIN32 +# define CloudAppExport __declspec(dllimport) +# define CloudGuiExport __declspec(dllexport) +#else // for Linux +# define CloudAppExport +# define CloudGuiExport +#endif + +#ifdef _PreComp_ + +// standard +#include +#include + +// STL +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Xerces +#include + +#ifdef FC_OS_WIN32 +# include +#endif + +// Qt Toolkit +#ifndef __Qt4All__ +# include +#endif + +#endif //_PreComp_ + +#endif // GUI_PRECOMPILED_H diff --git a/src/Mod/Cloud/Gui/Resources/Cloud.qrc b/src/Mod/Cloud/Gui/Resources/Cloud.qrc new file mode 100644 index 0000000000..6b5b3cd487 --- /dev/null +++ b/src/Mod/Cloud/Gui/Resources/Cloud.qrc @@ -0,0 +1,4 @@ + + + + diff --git a/src/Mod/Cloud/Gui/Resources/icons/CloudWorkbench.svg b/src/Mod/Cloud/Gui/Resources/icons/CloudWorkbench.svg new file mode 100644 index 0000000000..8c4abc2364 --- /dev/null +++ b/src/Mod/Cloud/Gui/Resources/icons/CloudWorkbench.svg @@ -0,0 +1,17 @@ + + + + +Created by Jean-Marie Verdun using potrace 1.15, written by Peter Selinger 2001-2017 + + + + + diff --git a/src/Mod/Cloud/Gui/Workbench.cpp b/src/Mod/Cloud/Gui/Workbench.cpp new file mode 100644 index 0000000000..e229d6cb82 --- /dev/null +++ b/src/Mod/Cloud/Gui/Workbench.cpp @@ -0,0 +1,65 @@ +/*************************************************************************** + * Copyright (c) YEAR YOUR NAME * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +#endif + +#include "Workbench.h" +#include +#include + +using namespace CloudGui; + +/// @namespace CloudGui @class Workbench +TYPESYSTEM_SOURCE(CloudGui::Workbench, Gui::StdWorkbench) + +Workbench::Workbench() +{ +} + +Workbench::~Workbench() +{ +} +/* +Gui::MenuItem* Workbench::setupMenuBar() const +{ + Gui::MenuItem* root = StdWorkbench::setupMenuBar(); + Gui::MenuItem* item = root->findItem( "&Windows" ); + Gui::MenuItem* test = new Gui::MenuItem; + root->insertItem( item, test ); + test->setCommand("Cloud"); + *test << "Cloud_Test"; + return root; +} + +Gui::ToolBarItem* Workbench::setupToolBars() const +{ + Gui::ToolBarItem* root = StdWorkbench::setupToolBars(); + Gui::ToolBarItem* test = new Gui::ToolBarItem(root); + test->setCommand( "Cloud Tools" ); + *test << "Cloud_Test"; + return root; +} +*/ diff --git a/src/Mod/Cloud/Gui/Workbench.h b/src/Mod/Cloud/Gui/Workbench.h new file mode 100644 index 0000000000..810ed5a5c4 --- /dev/null +++ b/src/Mod/Cloud/Gui/Workbench.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (c) YEAR YOUR NAME * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef Cloud_WORKBENCH_H +#define Cloud_WORKBENCH_H + +#include + +namespace CloudGui { + +class Workbench : public Gui::StdWorkbench +{ + TYPESYSTEM_HEADER(); + +public: + Workbench(); + virtual ~Workbench(); + +protected: +// Gui::MenuItem* setupMenuBar() const; +// Gui::ToolBarItem* setupToolBars() const; +}; + +} // namespace CloudGui + + +#endif // Cloud_WORKBENCH_H diff --git a/src/Mod/Cloud/Init.py b/src/Mod/Cloud/Init.py new file mode 100644 index 0000000000..f1b52c7ae9 --- /dev/null +++ b/src/Mod/Cloud/Init.py @@ -0,0 +1,2 @@ +# FreeCAD init script of the Cloud module +# (c) 2001 Juergen Riegel LGPL diff --git a/src/Mod/Cloud/InitGui.py b/src/Mod/Cloud/InitGui.py new file mode 100644 index 0000000000..4a76ee66f4 --- /dev/null +++ b/src/Mod/Cloud/InitGui.py @@ -0,0 +1,17 @@ +# Cloud gui init module +# (c) 2001 Juergen Riegel LGPL + +class CloudWorkbench ( Workbench ): + "Cloud workbench object" + def __init__(self): + self.__class__.Icon = FreeCAD.getResourceDir() + "Mod/Cloud/Resources/icons/CloudWorkbench.svg" + + MenuText = "Cloud" + ToolTip = "Cloud workbench" + def Initialize(self): + # load the module + import CloudGui + def GetClassName(self): + return "CloudGui::Workbench" + +Gui.addWorkbench(CloudWorkbench())