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_TRANSLATION_CONTEXT 29 #define B_TRANSLATION_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" << ErrorCodeToString(ret); 114 BAlert* alert = new BAlert(B_TRANSLATE_CONTEXT("Bad news", "Title of error alert"), 115 helper.String(), 116 B_TRANSLATE_COMMENT("Bleep!", "Exporter - Continue in error dialog"), 117 NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); 118 // launch alert asynchronously 119 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 120 alert->Go(NULL); 121 } else { 122 // success 123 124 // add to recent document list 125 be_roster->AddToRecentDocuments(&fRef); 126 // mark command stack state as saved, 127 fDocument->CommandStack()->Save(); 128 // NOTE: CommandStack is thread safe 129 130 if (fDocument->WriteLock()) { 131 // set ref and name of document 132 // fDocument->SetRef(fRef); 133 fDocument->SetName(fRef.name); 134 135 fDocument->WriteUnlock(); 136 } 137 } 138 139 if (fSelfDestroy) 140 delete this; 141 142 return ret; 143 } 144 145 146 status_t 147 Exporter::_Export(const Icon* icon, const entry_ref* docRef) 148 { 149 // TODO: reenable the commented out code, but make it work 150 // the opposite direction, ie *copy* the file contents 151 152 BEntry entry(docRef, true); 153 if (entry.IsDirectory()) 154 return B_BAD_VALUE; 155 156 const entry_ref* ref = docRef; 157 // entry_ref tempRef; 158 // 159 // if (entry.Exists()) { 160 // // if the file exists create a temporary file in the same folder 161 // // and hope that it doesn't already exist... 162 // BPath tempPath(docRef); 163 // if (tempPath.GetParent(&tempPath) >= B_OK) { 164 // BString helper(docRef->name); 165 // helper << system_time(); 166 // if (tempPath.Append(helper.String()) >= B_OK 167 // && entry.SetTo(tempPath.Path()) >= B_OK 168 // && entry.GetRef(&tempRef) >= B_OK) { 169 // // have the output ref point to the temporary 170 // // file instead 171 // ref = &tempRef; 172 // } 173 // } 174 // } 175 176 status_t ret = B_BAD_VALUE; 177 178 // do the actual save operation into a file 179 BFile outFile(ref, B_CREATE_FILE | B_READ_WRITE | B_ERASE_FILE); 180 ret = outFile.InitCheck(); 181 if (ret == B_OK) { 182 try { 183 // export using the virtual Export() version 184 ret = Export(icon, &outFile); 185 } catch (...) { 186 printf("Exporter::_Export() - " 187 "unkown exception occured!\n"); 188 ret = B_ERROR; 189 } 190 if (ret < B_OK) { 191 printf("Exporter::_Export() - " 192 "failed to export icon: %s\n", strerror(ret)); 193 } 194 } else { 195 printf("Exporter::_Export() - " 196 "failed to create output file: %s\n", strerror(ret)); 197 } 198 outFile.Unset(); 199 200 // if (ret < B_OK && ref != docRef) { 201 // // in case of failure, remove temporary file 202 // entry.Remove(); 203 // } 204 // 205 // if (ret >= B_OK && ref != docRef) { 206 // // move temp file overwriting actual document file 207 // BEntry docEntry(docRef, true); 208 // // copy attributes of previous document file 209 // BNode sourceNode(&docEntry); 210 // BNode destNode(&entry); 211 // if (sourceNode.InitCheck() >= B_OK && destNode.InitCheck() >= B_OK) { 212 // // lock the nodes 213 // if (sourceNode.Lock() >= B_OK) { 214 // if (destNode.Lock() >= B_OK) { 215 // // iterate over the attributes 216 // char attrName[B_ATTR_NAME_LENGTH]; 217 // while (sourceNode.GetNextAttrName(attrName) >= B_OK) { 218 //// // skip the icon, since we probably wrote that 219 //// // before 220 //// if (strcmp(attrName, "BEOS:ICON") == 0) 221 //// continue; 222 // attr_info info; 223 // if (sourceNode.GetAttrInfo(attrName, &info) >= B_OK) { 224 // char *buffer = new (nothrow) char[info.size]; 225 // if (buffer && sourceNode.ReadAttr(attrName, info.type, 0, 226 // buffer, info.size) == info.size) { 227 // destNode.WriteAttr(attrName, info.type, 0, 228 // buffer, info.size); 229 // } 230 // delete[] buffer; 231 // } 232 // } 233 // destNode.Unlock(); 234 // } 235 // sourceNode.Unlock(); 236 // } 237 // } 238 // // clobber the orginal file with the new temporary one 239 // ret = entry.Rename(docRef->name, true); 240 // } 241 242 if (ret >= B_OK && MIMEType()) { 243 // set file type 244 BNode node(docRef); 245 if (node.InitCheck() == B_OK) { 246 BNodeInfo nodeInfo(&node); 247 if (nodeInfo.InitCheck() == B_OK) 248 nodeInfo.SetType(MIMEType()); 249 } 250 } 251 return ret; 252 } 253