/*! copy the given subset of the given document to the system clipboard in a variety of formats. to minimize the effects of race-conditions, we create all of the buffers we need and then post them to the server (well sorta) all at one time. \param pDocRange a range of the document to be copied */ void AP_UnixApp::copyToClipboard(PD_DocumentRange * pDocRange, bool bUseClipboard) { UT_ByteBuf bufRTF; UT_ByteBuf bufHTML4; UT_ByteBuf bufXHTML; UT_ByteBuf bufTEXT; UT_ByteBuf bufODT; // create RTF buffer to put on the clipboard IE_Exp_RTF * pExpRtf = new IE_Exp_RTF(pDocRange->m_pDoc); if (pExpRtf) { pExpRtf->copyToBuffer(pDocRange,&bufRTF); DELETEP(pExpRtf); } // create XHTML buffer to put on the clipboard IE_Exp_HTML * pExpHtml = new IE_Exp_HTML(pDocRange->m_pDoc); if (pExpHtml) { pExpHtml->set_HTML4 (false); pExpHtml->copyToBuffer (pDocRange, &bufXHTML); DELETEP(pExpHtml); } // create HTML4 buffer to put on the clipboard pExpHtml = new IE_Exp_HTML(pDocRange->m_pDoc); if (pExpHtml) { pExpHtml->set_HTML4 (true); pExpHtml->copyToBuffer(pDocRange, &bufHTML4); DELETEP(pExpHtml); } // Look to see if the ODT plugin is loaded IEFileType ftODT = IE_Exp::fileTypeForMimetype("application/vnd.oasis.opendocument.text"); bool bExpODT = false; if(ftODT != IEFT_Unknown) { // ODT plugin is present construct an exporter // IE_Exp * pODT = NULL; IEFileType genIEFT = IEFT_Unknown; GsfOutput * outBuf = gsf_output_memory_new(); UT_Error err = IE_Exp::constructExporter(pDocRange->m_pDoc,outBuf, ftODT,&pODT,& genIEFT); if(pODT && (genIEFT == ftODT)) { // // Copy to the buffer // err = pODT->copyToBuffer(pDocRange, &bufODT); bExpODT = (err == UT_OK); UT_DEBUGMSG(("Putting ODF on the clipboard...e:%d bExpODT:%d\n", err, bExpODT )); #ifdef DUMP_CLIPBOARD_COPY std::ofstream oss("/tmp/abiword-clipboard-copy.odt"); oss.write( (const char*)bufODT.getPointer (0), bufODT.getLength () ); oss.close(); #endif } } // create UTF-8 text buffer to put on the clipboard IE_Exp_Text * pExpText = new IE_Exp_Text(pDocRange->m_pDoc, "UTF-8"); if (pExpText) { pExpText->copyToBuffer(pDocRange,&bufTEXT); DELETEP(pExpText); } // NOTE: this clearData() will actually release our ownership of // NOTE: the CLIPBOARD property in addition to clearing any // NOTE: stored buffers. I'm omitting it since we seem to get // NOTE: clr callback after we have done some other processing // NOTE: (like adding the new stuff). // m_pClipboard->clearData(true,false); // TODO: handle CLIPBOARD vs PRIMARY XAP_UnixClipboard::T_AllowGet target = ((bUseClipboard) ? XAP_UnixClipboard::TAG_ClipboardOnly : XAP_UnixClipboard::TAG_PrimaryOnly); if (bufRTF.getLength () > 0) m_pClipboard->addRichTextData (target, bufRTF.getPointer (0), bufRTF.getLength ()); if (bufXHTML.getLength () > 0) m_pClipboard->addHtmlData (target, bufXHTML.getPointer (0), bufXHTML.getLength (), true); if (bufHTML4.getLength () > 0) m_pClipboard->addHtmlData (target, bufHTML4.getPointer (0), bufHTML4.getLength (), false); if (bExpODT && bufODT.getLength () > 0) m_pClipboard->addODTData (target, bufODT.getPointer (0), bufODT.getLength ()); if (bufTEXT.getLength () > 0) m_pClipboard->addTextData (target, bufTEXT.getPointer (0), bufTEXT.getLength ()); { // TODO: we have to make a good way to tell if the current selection is just an image FV_View * pView = NULL; if(getLastFocussedFrame()) pView = static_cast<FV_View*>(getLastFocussedFrame()->getCurrentView()); if (pView && !pView->isSelectionEmpty()) { // don't own, don't g_free const UT_ByteBuf * png = 0; pView->saveSelectedImage (&png); if (png && png->getLength() > 0) { m_pClipboard->addPNGData(target, static_cast<const UT_Byte*>(png->getPointer(0)), png->getLength()); } } } m_pClipboard->finishedAddingData(); return; }
// // AbiPaint editImage // ------------------ // This is the function that we actually call to invoke the image editor. // // parameters are: // AV_View* v // EV_EditMethodCallData *d // static DECLARE_ABI_PLUGIN_METHOD(editImage) { UT_UNUSED(v); // Get the current view that the user is in. XAP_Frame *pFrame = XAP_App::getApp()->getLastFocussedFrame(); FV_View* pView = static_cast<FV_View*>(pFrame->getCurrentView()); // // get values from preference (initial plugin execution should have set sensible defaults) // UT_String imageApp; // holds MAXPATH\appName <space> MAXPATH\imagefilename bool bLeaveImageAsPNG; // read stuff from the preference value if (!prefsScheme->getValue(ABIPAINT_PREF_KEY_szProgramName, imageApp)) { UT_ASSERT(UT_SHOULD_NOT_HAPPEN); getDefaultApp(imageApp, bLeaveImageAsPNG); } // now that we have program name, try to get other flag (allows overriding default value) // Note: we allow overriding, otherwise if we don't adhere to user's setting // then the use BMP or not menu should be greyed to note it has no effect prefsScheme->getValueBool(ABIPAINT_PREF_KEY_bLeaveImageAsPNG, &bLeaveImageAsPNG); // // generate a temp file name... // char *szTempFileName = NULL; GError *err = NULL; gint fp = g_file_open_tmp ("XXXXXX", &szTempFileName, &err); if (err) { g_warning ("%s", err->message); g_error_free (err); err = NULL; return FALSE; } close(fp); UT_String szTmpPng = szTempFileName; szTmpPng += ".png"; UT_String szTmp = szTmpPng; // default: our temp file is the created png file PT_DocPosition pos = pView->saveSelectedImage((const char *)szTmpPng.c_str()); if(pos == 0) { remove(szTempFileName); g_free (szTempFileName); szTempFileName = NULL; pFrame->showMessageBox("You must select an Image before editing it", XAP_Dialog_MessageBox::b_O,XAP_Dialog_MessageBox::a_OK); return false; } #ifdef ENABLE_BMP // // Convert png into bmp for best compatibility with Windows programs // NOTE: probably looses detail/information though!!! so if possible use PNG // if (!bLeaveImageAsPNG) { szTmp = szTempFileName; szTmp += ".bmp"; // our temp file is a bmp file if (convertPNG2BMP(szTmpPng.c_str(), szTmp.c_str())) { pFrame->showMessageBox("Unable to convert PNG image data to BMP for external program use!", XAP_Dialog_MessageBox::b_O,XAP_Dialog_MessageBox::a_OK); UT_ASSERT(UT_SHOULD_NOT_HAPPEN); remove(szTempFileName); g_free (szTempFileName); szTempFileName = NULL; remove(szTmpPng.c_str()); return false; } // remove(szTmpPng.c_str()); } #endif // remove the temp file (that lacks proper extension) remove(szTempFileName); g_free (szTempFileName); szTempFileName = NULL; // // Get the initial file status. // struct stat myFileStat; int ok = stat(szTmp.c_str(),&myFileStat); if(ok < 0) { UT_ASSERT(UT_SHOULD_NOT_HAPPEN); remove(szTmpPng.c_str()); remove(szTmp.c_str()); // should silently fail if exporting as PNG file return false; } time_t mod_time = myFileStat.st_mtime; // // Fire up the image editor... // ProcessInfo procInfo; if (!createChildProcess(imageApp.c_str(), szTmp.c_str(), &procInfo)) { UT_String msg = "Unable to run program: "; msg += imageApp + " " + szTmp; pFrame->showMessageBox(msg.c_str(), XAP_Dialog_MessageBox::b_O,XAP_Dialog_MessageBox::a_OK); // failed to spawn stuff, so do some cleanup and return failure remove(szTmpPng.c_str()); remove(szTmp.c_str()); // should silently fail if exporting as PNG file return false; } lockGUI(d); while (isProcessStillAlive(procInfo)) { UT_usleep(10000); // wait 10 milliseconds pFrame->nullUpdate(); ok = stat(szTmp.c_str(),&myFileStat); if(ok == 0) { if(myFileStat.st_mtime != mod_time) { // wait for changes to settle (program done writing changes) // we use both modified time & file size, but really we // could just use file size as mod time doesn't appear to change for small images mod_time = myFileStat.st_mtime; off_t size = myFileStat.st_size; UT_usleep(100000); // wait 100 milliseconds (so program may have time to write something) ok = stat(szTmp.c_str(),&myFileStat); while((mod_time != myFileStat.st_mtime) || !size || (size > 0 && size != myFileStat.st_size)) { mod_time = myFileStat.st_mtime; size = myFileStat.st_size; ok = stat(szTmp.c_str(),&myFileStat); UT_usleep(500000); // wait a while, let program write its data // just make sure the program is still running, otherwise we could get stuck in a loop if (!isProcessStillAlive(procInfo)) { pFrame->showMessageBox("External image editor appears to have been terminated unexpectedly.", XAP_Dialog_MessageBox::b_O,XAP_Dialog_MessageBox::a_OK); //procInfo.hProcess = 0; goto Cleanup; } } mod_time = myFileStat.st_mtime; UT_usleep(100000); // wait a while just to make sure program is done with file // // OK replace the current image with this. // IEGraphicFileType iegft = IEGFT_Unknown; FG_Graphic* pFG; UT_Error errorCode; #ifdef ENABLE_BMP // // Convert bmp back to png (as we can not assume AbiWord has builtin BMP support [as its now an optional plugin]) // NOTE: probably looses detail/information though!!! so if possible use only PNG // if (!bLeaveImageAsPNG) { if (convertBMP2PNG(szTmp.c_str(), szTmpPng.c_str())) { pFrame->showMessageBox("Unable to convert BMP image data back to PNG for AbiWord to import!", XAP_Dialog_MessageBox::b_O,XAP_Dialog_MessageBox::a_OK); UT_ASSERT(UT_SHOULD_NOT_HAPPEN); goto Cleanup; } } #endif errorCode = IE_ImpGraphic::loadGraphic(szTmpPng.c_str(), iegft, &pFG); if(errorCode) { UT_ASSERT(UT_SHOULD_NOT_HAPPEN); pFrame->showMessageBox("Error making pFG. Could not put image back into Abiword", XAP_Dialog_MessageBox::b_O,XAP_Dialog_MessageBox::a_OK); goto Cleanup; } unlockGUI(d); pView->cmdUnselectSelection(); pView->setPoint(pos); pView->extSelHorizontal(true, 1); // move point forward one errorCode = pView->cmdInsertGraphic(pFG); if (errorCode) { pFrame->showMessageBox("Could not put image back into Abiword", XAP_Dialog_MessageBox::b_O,XAP_Dialog_MessageBox::a_OK); UT_ASSERT(UT_SHOULD_NOT_HAPPEN); DELETEP(pFG); goto Cleanup; } DELETEP(pFG); // // Reselect the image // pView->setPoint(pos); pView->extSelHorizontal(true, 1); // move point forward one lockGUI(d); } } } // // Normal exit, delete the tempfile and return success // remove(szTmpPng.c_str()); remove(szTmp.c_str()); // should silently fail if exporting as PNG file unlockGUI(d); return true; // // Something went wrong. // Cleanup: remove(szTmpPng.c_str()); remove(szTmp.c_str()); // should silently fail if exporting as PNG file unlockGUI(d); // // Kill the image editor. // endProcess(procInfo); return false; }
/*! get the current contents of the selection in the window last known to have a selection using one of the formats in the given list. \param formatList the list of acceptable formats \param ppData \param pLen a pointer to an integer representing the length \param pszFormatFound a pointer for the data to be returned in \return True if successful, false otherwise. */ bool AP_UnixApp::getCurrentSelection(const char** formatList, void ** ppData, UT_uint32 * pLen, const char **pszFormatFound) { int j; *ppData = NULL; // assume failure *pLen = 0; *pszFormatFound = NULL; if (!m_pViewSelection || !m_pFrameSelection || !m_bHasSelection) return false; // can't do it, give up. PD_DocumentRange dr; if (m_cacheSelectionView == m_pViewSelection) { dr = m_cacheDocumentRangeOfSelection; } else { // TODO if we ever support multiple view types, we'll have to // TODO change this. FV_View * pFVView = static_cast<FV_View *>(m_pViewSelection); pFVView->getDocumentRangeOfCurrentSelection(&dr); } m_selectionByteBuf.truncate(0); for (j=0; (formatList[j]); j++) { if ( AP_UnixClipboard::isRichTextTag(formatList[j]) ) { IE_Exp_RTF * pExpRtf = new IE_Exp_RTF(dr.m_pDoc); if (!pExpRtf) return false; // give up on memory errors pExpRtf->copyToBuffer(&dr,&m_selectionByteBuf); DELETEP(pExpRtf); goto ReturnThisBuffer; } if ( AP_UnixClipboard::isHTMLTag(formatList[j]) ) { IE_Exp_HTML * pExpHTML = new IE_Exp_HTML(dr.m_pDoc); if (!pExpHTML) return false; pExpHTML->set_HTML4 (!strcmp (formatList[j], "text/html")); pExpHTML->copyToBuffer(&dr,&m_selectionByteBuf); DELETEP(pExpHTML); goto ReturnThisBuffer; } if ( AP_UnixClipboard::isImageTag(formatList[j]) ) { // TODO: we have to make a good way to tell if the current selection is just an image FV_View * pView = NULL; if(getLastFocussedFrame()) pView = static_cast<FV_View*>(getLastFocussedFrame()->getCurrentView()); if (pView && !pView->isSelectionEmpty()) { // don't own, don't g_free const UT_ByteBuf * png = 0; pView->saveSelectedImage (&png); if (png && png->getLength() > 0) { m_selectionByteBuf.ins (0, png->getPointer (0), png->getLength ()); goto ReturnThisBuffer; } } } if ( AP_UnixClipboard::isTextTag(formatList[j]) ) { IE_Exp_Text * pExpText = new IE_Exp_Text(dr.m_pDoc, "UTF-8"); if (!pExpText) return false; pExpText->copyToBuffer(&dr,&m_selectionByteBuf); DELETEP(pExpText); goto ReturnThisBuffer; } // TODO add other formats as necessary } UT_DEBUGMSG(("Clipboard::getCurrentSelection: cannot create anything in one of requested formats.\n")); return false; ReturnThisBuffer: UT_DEBUGMSG(("Clipboard::getCurrentSelection: copying %d bytes in format [%s].\n", m_selectionByteBuf.getLength(),formatList[j])); *ppData = const_cast<void *>(static_cast<const void *>(m_selectionByteBuf.getPointer(0))); *pLen = m_selectionByteBuf.getLength(); *pszFormatFound = formatList[j]; return true; }
// // AbiPaint saveAsBmp // ------------------ // This is the function exports selected image as a Windows BMP file. // // parameters are: // AV_View* v // EV_EditMethodCallData *d) // static DECLARE_ABI_PLUGIN_METHOD(saveAsBmp) { // Get a frame (for error messages) and (to) get the current view that the user is in. XAP_Frame *pFrame = XAP_App::getApp()->getLastFocussedFrame(); FV_View* pView = static_cast<FV_View*>(pFrame->getCurrentView()); char *szTempFileName = NULL; GError *err = NULL; gint fp = g_file_open_tmp ("XXXXXX", &szTempFileName, &err); if (err) { g_warning (err->message); g_error_free (err); err = NULL; return FALSE; } close(fp); UT_String szTmpPng = szTempFileName; szTmpPng += ".png"; remove(szTempFileName); g_free (szTempFileName); szTempFileName = NULL; PT_DocPosition pos = pView->saveSelectedImage((const char *)szTmpPng.c_str()); if(pos == 0) { pFrame->showMessageBox("You must select an Image before trying to save it as a BMP file!", XAP_Dialog_MessageBox::b_O,XAP_Dialog_MessageBox::a_OK); return false; } // // Convert png into bmp // NOTE: probably looses detail/information though!!! // UT_String szBMPFile = pFrame->getFilename(); // perhaps a different default directory should be used??? { const char * szDescList[2]; const char * szSuffixList[2]; IEGraphicFileType ft[2]; { // IE_ImpGraphicBMP_Sniffer tmp; // tmp.getDlgLabels(szDescList, szSuffixList, ft); szDescList[0] = "Windows Bitmap (*.bmp)"; szSuffixList[0] = "*.bmp"; ft[0] = IEGFT_BMP; } szDescList[1] = szSuffixList[1] = NULL; ft[1] = IEGFT_Unknown; if (getFileName(szBMPFile, pFrame, XAP_DIALOG_ID_FILE_SAVEAS, szDescList, szSuffixList, ft)) { // user canceled remove(szTmpPng.c_str()); return true; } } if (convertPNG2BMP(szTmpPng.c_str(), szBMPFile.c_str())) { pFrame->showMessageBox("Unable to convert PNG image data to BMP.", XAP_Dialog_MessageBox::b_O,XAP_Dialog_MessageBox::a_OK); UT_ASSERT(UT_SHOULD_NOT_HAPPEN); remove(szTmpPng.c_str()); return false; } remove(szTmpPng.c_str()); return true; }