1 /* 2 * Copyright 2006, Haiku. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 */ 8 9 #include "Exporter.h" 10 11 #include <fs_attr.h> 12 #include <new> 13 #include <stdio.h> 14 15 #include <Alert.h> 16 #include <File.h> 17 #include <Node.h> 18 #include <NodeInfo.h> 19 #include <Path.h> 20 #include <Roster.h> 21 #include <String.h> 22 23 #include "CommandStack.h" 24 #include "Document.h" 25 #include "Icon.h" 26 27 using std::nothrow; 28 29 // constructor 30 Exporter::Exporter() 31 : fDocument(NULL), 32 fClonedIcon(NULL), 33 fRef(), 34 fExportThread(-1), 35 fSelfDestroy(false) 36 { 37 } 38 39 // destructor 40 Exporter::~Exporter() 41 { 42 if (fExportThread >= 0 && find_thread(NULL) != fExportThread) { 43 status_t ret; 44 wait_for_thread(fExportThread, &ret); 45 } 46 47 delete fClonedIcon; 48 } 49 50 // Export 51 status_t 52 Exporter::Export(Document* document, const entry_ref& ref) 53 { 54 if (!document || ref.name == NULL) 55 return B_BAD_VALUE; 56 57 fDocument = document; 58 fClonedIcon = fDocument->Icon()->Clone(); 59 if (!fClonedIcon) 60 return B_NO_MEMORY; 61 62 fRef = ref; 63 64 fExportThread = spawn_thread(_ExportThreadEntry, "export", 65 B_NORMAL_PRIORITY, this); 66 if (fExportThread >= B_OK) 67 resume_thread(fExportThread); 68 69 return fExportThread; 70 } 71 72 // SetSelfDestroy 73 void 74 Exporter::SetSelfDestroy(bool selfDestroy) 75 { 76 fSelfDestroy = selfDestroy; 77 } 78 79 // #pragma mark - 80 81 // _ExportThreadEntry 82 int32 83 Exporter::_ExportThreadEntry(void* cookie) 84 { 85 Exporter* exporter = (Exporter*)cookie; 86 return exporter->_ExportThread(); 87 } 88 89 // _ExportThread 90 int32 91 Exporter::_ExportThread() 92 { 93 status_t ret = _Export(fClonedIcon, &fRef); 94 if (ret < B_OK) { 95 // inform user of failure at this point 96 BString helper("Saving your document failed!"); 97 helper << "\n\n" << "Error: " << strerror(ret); 98 BAlert* alert = new BAlert("bad news", helper.String(), 99 "Bleep!", NULL, NULL); 100 // launch alert asynchronously 101 alert->Go(NULL); 102 } else { 103 // success 104 105 // add to recent document list 106 be_roster->AddToRecentDocuments(&fRef); 107 // mark command stack state as saved, 108 fDocument->CommandStack()->Save(); 109 // NOTE: CommandStack is thread safe 110 111 if (fDocument->WriteLock()) { 112 // set ref and name of document 113 // fDocument->SetRef(fRef); 114 fDocument->SetName(fRef.name); 115 116 fDocument->WriteUnlock(); 117 } 118 } 119 120 if (fSelfDestroy) 121 delete this; 122 123 return ret; 124 } 125 126 // _Export 127 status_t 128 Exporter::_Export(const Icon* icon, 129 const entry_ref* docRef) 130 { 131 // TODO: reenable the commented out code, but make it work 132 // the opposite direction, ie *copy* the file contents 133 134 BEntry entry(docRef, true); 135 if (entry.IsDirectory()) 136 return B_BAD_VALUE; 137 138 const entry_ref* ref = docRef; 139 // entry_ref tempRef; 140 // 141 // if (entry.Exists()) { 142 // // if the file exists create a temporary file in the same folder 143 // // and hope that it doesn't already exist... 144 // BPath tempPath(docRef); 145 // if (tempPath.GetParent(&tempPath) >= B_OK) { 146 // BString helper(docRef->name); 147 // helper << system_time(); 148 // if (tempPath.Append(helper.String()) >= B_OK 149 // && entry.SetTo(tempPath.Path()) >= B_OK 150 // && entry.GetRef(&tempRef) >= B_OK) { 151 // // have the output ref point to the temporary 152 // // file instead 153 // ref = &tempRef; 154 // } 155 // } 156 // } 157 158 status_t ret = B_BAD_VALUE; 159 160 // do the actual save operation into a file 161 BFile outFile(ref, B_CREATE_FILE | B_READ_WRITE | B_ERASE_FILE); 162 ret = outFile.InitCheck(); 163 if (ret == B_OK) { 164 try { 165 // export using the virtual Export() version 166 ret = Export(icon, &outFile); 167 } catch (...) { 168 printf("Exporter::_Export() - " 169 "unkown exception occured!\n"); 170 ret = B_ERROR; 171 } 172 if (ret < B_OK) { 173 printf("Exporter::_Export() - " 174 "failed to export icon: %s\n", strerror(ret)); 175 } 176 } else { 177 printf("Exporter::_Export() - " 178 "failed to create output file: %s\n", strerror(ret)); 179 } 180 outFile.Unset(); 181 182 // if (ret < B_OK && ref != docRef) { 183 // // in case of failure, remove temporary file 184 // entry.Remove(); 185 // } 186 // 187 // if (ret >= B_OK && ref != docRef) { 188 // // move temp file overwriting actual document file 189 // BEntry docEntry(docRef, true); 190 // // copy attributes of previous document file 191 // BNode sourceNode(&docEntry); 192 // BNode destNode(&entry); 193 // if (sourceNode.InitCheck() >= B_OK && destNode.InitCheck() >= B_OK) { 194 // // lock the nodes 195 // if (sourceNode.Lock() >= B_OK) { 196 // if (destNode.Lock() >= B_OK) { 197 // // iterate over the attributes 198 // char attrName[B_ATTR_NAME_LENGTH]; 199 // while (sourceNode.GetNextAttrName(attrName) >= B_OK) { 200 //// // skip the icon, since we probably wrote that 201 //// // before 202 //// if (strcmp(attrName, "BEOS:ICON") == 0) 203 //// continue; 204 // attr_info info; 205 // if (sourceNode.GetAttrInfo(attrName, &info) >= B_OK) { 206 // char *buffer = new (nothrow) char[info.size]; 207 // if (buffer && sourceNode.ReadAttr(attrName, info.type, 0, 208 // buffer, info.size) == info.size) { 209 // destNode.WriteAttr(attrName, info.type, 0, 210 // buffer, info.size); 211 // } 212 // delete[] buffer; 213 // } 214 // } 215 // destNode.Unlock(); 216 // } 217 // sourceNode.Unlock(); 218 // } 219 // } 220 // // clobber the orginal file with the new temporary one 221 // ret = entry.Rename(docRef->name, true); 222 // } 223 224 if (ret >= B_OK && MIMEType()) { 225 // set file type 226 BNode node(docRef); 227 if (node.InitCheck() == B_OK) { 228 BNodeInfo nodeInfo(&node); 229 if (nodeInfo.InitCheck() == B_OK) 230 nodeInfo.SetType(MIMEType()); 231 } 232 } 233 return ret; 234 } 235