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