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