Does anyone know if there is a way outside of using a 3rd Party text box control, to enter HTML into a VB6 text box.
I havent found anything online.
Hopefully you'll be able to make use of this. We're doing it in .Net to allow a simple edit control on forms to send formatted emails. As such we have a RTF text box with a custom menu for creating the text, then we extract the RTF, convert it to HTML and add it as HTML content as the body of an email. The RTF to HTML conversion uses the code from this article: http://www.codeproject.com/Articles/27431/Writing-Your-Own-RTF-Converter
Here's the wrapper code we use to tie this together - it simply takes an RTF input and directly returns an HTML output:
Imports Itenso.Rtf
Imports Itenso.Rtf.Support
Imports Itenso.Rtf.Parser
Imports Itenso.Rtf.Interpreter
Imports Itenso.Rtf.Converter.Image
Imports Itenso.Rtf.Converter.Html
Imports Itenso.Sys.Application
Namespace Email
Public Class RtfToHtml
Public Function Convert(inText As String) As String
Dim struct = ParseRtf(inText)
Dim doc = InterpretRtf(struct)
Return ConvertHtml(doc)
End Function
Private Function ParseRtf(inText As String) As IRtfGroup
Dim structureBuilder As New RtfParserListenerStructureBuilder
Dim parser = New RtfParser(structureBuilder) With {.IgnoreContentAfterRootGroup = True}
Dim source = New RtfSource(inText)
parser.Parse(source)
Return structureBuilder.StructureRoot
End Function
Private Function InterpretRtf(rtfStructure As IRtfGroup) As IRtfDocument
Dim settings = New RtfInterpreterSettings With {.IgnoreDuplicatedFonts = True, .IgnoreUnknownFonts = True}
Return RtfInterpreterTool.BuildDoc(rtfStructure, settings)
End Function
Private Function ConvertHtml(document As IRtfDocument) As String
Dim settings As New RtfHtmlConvertSettings With {.Title = "Notification Of Shipment",
.IsShowHiddenText = False,
.UseNonBreakingSpaces = True}
Dim converter = New RtfHtmlConverter(document, settings)
'converter.StyleConverter = New RtfEmptyHtmlStyleConverter
Return converter.Convert
End Function
End Class
End Namespace
Depending on your application you could simply wrap this up in an assembly and call it from VB6. We've done this in the past and it's reasonably straightforward. Again, more info if you think it might be useful to you
Related
In my Vaadin Flow web app (version 14 or later), I want to present to my user a link that will download a data file to them. The default name of the file to be downloaded should be determined at the moment the user initiates the download.
I am aware of the Anchor widget in Vaadin Flow. With an Anchor, the default name for the downloaded file will be the resource name given in the URL of the link. Unfortunately, that is determined when the page loads rather than later when the user clicks the link. So this approach fails to meet my need to label the download with the date-time captured at the moment the user initiates the download.
String when = Instant.now().toString().replace( "-" , "" ).replace( ":" , "" ); // Use "basic" version of standard ISO 8601 format for date-time.
StreamResource streamResource = new StreamResource( "rows_" + when + ".txt" , ( ) -> this.makeContent() );
Anchor anchor = new Anchor( streamResource , "Download generated data" );
Perhaps the solution would be the use of a Button widget rather than an Anchor. Using a button for dynamically-created content is shown in the manual in the Advanced Topics > Dynamic Content page. Unfortunately, the example there loads a resource on the page rather than doing a download for the user.
➥ Can a Button in Vaadin Flow be used to initiate a download?
➥ Is there some other approach to initiating a download with a URL determined when the user initiates the download rather than when the page loads?
Can a Button in Vaadin Flow be used to initiate a download?
Sort of yes, but it requires some client side implementation. There is File Download Wrapper add-on in Directory, which does this. With it is possible to wrap e.g. Button. However I think it will not solve problem of yours fully. I suspect that the setting the filename in click event wont apply (it comes too late). But I do think, that it would be possible to add filename provider callback feature to this add-on.
Consider this HACK that simulates a click on a dynamically added Anchor on client-side:
private void downloadWorkaround(Component anyComponent, int delay) {
Anchor hiddenDownloadLink = new Anchor(createStreamResource(), "Workaround");
hiddenDownloadLink.setId("ExportLinkWorkaround_" + System.currentTimeMillis());
hiddenDownloadLink.getElement().setAttribute("style", "display: none");
var parent = anyComponent.getParent().orElseThrow();
var parenthc = (HasComponents) parent;
for (Component c : parent.getChildren().collect(Collectors.toList())) {
if (c.getId().orElse("").startsWith("ExportLinkWorkaround_")) {
// clean up old download link
parenthc.remove(c);
}
}
parenthc.add(hiddenDownloadLink);
UI.getCurrent().getPage().executeJs("setTimeout(function(){" + // delay as workaround for bug when dialog open before
"document.getElementById('" + hiddenDownloadLink.getId().orElseThrow() + "').click();"
+ "}, " + delay + ");"
);
}
Call the method on button click event or something. The additional delay is required sometimes. For me the delay was necessary to start the download from a modal dialog OK button that also closed the dialog. But perhaps you don't even need that.
I had no luck with the file download wrapper add-on mentioned by Tatu for my specific use case: I wanted to show a dialog under some circumstances before providing the download to user.
Based on the question of Clearing up Vaadin StreamResource after file download (which is partly the same as the answer of Steffen Harbich here in this question) I came to this solution (Vaadin 23):
Just provide a normal button with a normal clickHandler.
In the clickHandler you determine the file name, create a local StreamResource, add it to an invisible UI element and trigger a click event on this element.
Clickhandler:
private void doOnDownloadBtnClicked( Event e )
{
String filename = createFileName(); // implementation left to you
downloadFile( filename, this::inputStreamProvider );
}
InputStream provider:
private InputStream inputStreamProvider()
{
....
}
File download (may be extracted to an Utility class):
private final StreamResourceRegistry myStreamResourceRegistry;
private void downloadFile( String aFileName, InputStreamFactory aInputStreamFactory )
{
myStreamResourceRegistry = new StreamResourceRegistry(VaadinSession.getCurrent());
var executor = new DownloadExecutor( aInputStreamFactory );
var sr = new StreamResource( aFileName, executor );
StreamRegistration reg = myStreamResourceRegistry.registerResource( sr );
executor.myRegistration = reg;
var hiddenDownloadLink = new Anchor(sr, "Hidden");
var hiddenDownloadLinkId =
StringUtils.replaceChars( "DownloadLinkWorkaroundId-" + new SecureRandom().nextLong(),
'-',
'_' ) ;
hiddenDownloadLink.setId( hiddenDownloadLinkId);
var hiddenElement = hiddenDownloadLink.getElement();
executor.myHiddenElement = hiddenElement;
hiddenElement.setAttribute("style", "display: none");
var uiParent = UI.getCurrent().getElement();
executor.myParentElement = uiParent;
uiParent.appendChild(hiddenElement);
LOG.debug( "Going to simulate click event" );
UI.getCurrent().getPage().executeJs("$0.click();", hiddenElement );
}
/**
* Wrapper for the given InputStreamFactory.
* <p>
* It is needed to let Vaadin first give a chance to call the InputStream provider, before the
* temporary added hidden anchor is removed and the StreamRegistration is unregistered.
*/
private static final class DownloadExecutor implements InputStreamFactory
{
private InputStreamFactory myInputStreamFactory;
private StreamRegistration myRegistration;
private Element myHiddenElement;
private Element myParentElement;
private DownloadExecutor( InputStreamFactory aInputStreamFactory )
{
super();
myInputStreamFactory = aInputStreamFactory;
}
#Override
public InputStream createInputStream()
{
var result = myInputStreamFactory.createInputStream();
myParentElement.removeChild( myHiddenElement );
myRegistration.unregister();
return result;
}
}
Note: If the above fileDownload is extracted to an own helper class (e.g. a spring bean with #SessionScope), the initialization of myStreamResourceRegistry should be done in the constructor of the bean.
In some of my mails, I have stored some userproperties via Outlook...
item.UserProperties.Add("CustID", Outlook.OlUserPropertyType.olText)
item.UserProperties("CustID").Value = custID.ToString
On a Pc (server) without Outlook installed, I want to download mail as EML and store the userproperties (like 'CustID' etc.).
My code for saving the EML:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim service As New ExchangeService(ExchangeVersion.Exchange2013)
service.Credentials = New WebCredentials("my#email.com", "mypsw")
service.Url = New System.Uri("https://outlook.office365.com/EWS/Exchange.asmx")
Dim entryID As String = "00000000C802F40668D27342B788D508E9210A67005DF9A7DEF7194A418C8515031D4262280000E00005DF9A7DEF7194A418C8515031D4262280002A9D18B320000"
Dim id As New ItemId(Convert(service, "my#email.com", entryID))
Dim email As EmailMessage = EmailMessage.Bind(service, id)
Dim ps As PropertySet = New PropertySet(ItemSchema.MimeContent)
email.Load(ps)
Using fileStream = New IO.FileStream("D:\sandbox\_email_test.eml", IO.FileMode.Create)
fileStream.Write(email.MimeContent.Content, 0, email.MimeContent.Content.Length)
End Using
End Sub
Private Function Convert(service As ExchangeService, mailbox As String, entryID As String) As String
Dim originalID As New AlternateId()
originalID.Format = IdFormat.HexEntryId
originalID.Mailbox = mailbox
originalID.UniqueId = entryID 'EntryId retrieved from email in Outlook
Dim altBase As AlternateIdBase = service.ConvertId(originalID, IdFormat.EwsId)
Dim convertedID As AlternateId = DirectCast(altBase, AlternateId)
Dim strConvertedID As String = convertedID.UniqueId
Return strConvertedID
End Function
Is there a way I can store userproperties in an EML? If yes, if I double click the EML to open it in Outlook, can I read back the userproperties from the EML?
Thanks!
User Properties are Mapi/Extended properties which aren't include in the MimeStream of a Message. If you add the properties as X-headers instead then they would be available in the MimeSteam otherwise you would better to export the Message as a MSG file which will give you full fidelity on all MAPI properties. To export as a MSG you will need to use Outlook and maybe look at something like redemption http://www.dimastr.com/redemption/rdo_introduction.htm if you need automation.
Cheers
Glen
Consider the following code:
QTextDocument * doc = ui->textBrowser->document();
doc->addResource(QTextDocument::ImageResource, QUrl("img://smiley"), QImage("happy.png"));
QTextCursor cursor = ui->textBrowser->textCursor();
cursor.insertHtml("Sample text ");
cursor.insertImage("img://smiley");
ui->textBrowser->setTextCursor(cursor);
(ui->textBrowser is a pointer to a QTextBrowser object)
When I copy the image to the clipboard, it is represented by an object replacement character (U+FFFC). Is it possible to change this behavior and save e.g. ":-)" instead?
Note that I am using Qt 5.2, so it's fine to use any functions introduced in Qt 5.
I'm afraid there is no simple way. In a web browser alt attribute would help, but Qt doesn't support it.
You can track clipboard's changes and correct its content.
Initialization:
QClipboard* clipboard = QApplication::clipboard();
connect(clipboard, SIGNAL(changed(QClipboard::Mode)),
this, SLOT(clipboard_changed()));
Clipboard correction (example):
void MainWindow::clipboard_changed() {
QClipboard* clipboard = QApplication::clipboard();
const QMimeData* data = clipboard->mimeData();
QString html = data->html();
if (html.contains("<img src=\"img://smiley\" />")) {
QString new_html = html;
new_html.replace("<img src=\"img://smiley\" />", ":-)");
QTextDocument doc;
doc.setHtml(new_html);
QString text = doc.toPlainText();
if (text != data->text()) {
QMimeData* new_data = new QMimeData();
new_data->setHtml(html);
new_data->setText(doc.toPlainText());
clipboard->setMimeData(new_data);
}
}
}
Of course you will need more sophisticated implementation for a real program.
I use QTextDocument just to convert HTML to plain text.
I'm trying to send content to a campaign template in MailChimp using MailChimp.net API. My template contains `
<b>mc:edit="question"</b>`
And the MailChimp API wants a JSON string in a struct/associative array. However, I can't seem to get the data to show up in the editable section and I've tried several different ways:
CampaignSegmentOptions segmentOptions = new CampaignSegmentOptions();
segmentOptions.Match = "All";
CampaignCreateContent content = new CampaignCreateContent();
content.HTML = "<p>Testing</p>";
CampaignCreateOptions options = new CampaignCreateOptions();
options.Title = "Testing";
options.ListId = listID;
options.ToName = "Test Name";
options.FromEmail = "user#example.com";
options.FromName = "Testing from Example.com";
options.Subject = "Test Subject";
options.FacebookComments = false;
//Using struct attempt
sections s = new sections();
s.question = "What did the lion need?";
//Using string attempt
//String[] s = new string [] {"question\":\"What did the lion need?"};
//Using dictionary attempt
Dictionary<string,string> dict = new Dictionary<string,string>();
dict.Add("question","What did the lion need?");
content.Sections = dict;
Campaign result = mc.CreateCampaign("regular", options, content);
Any suggestions? Thank you in advance.
Solved. In my case the Dictionary approach was the only one that worked. I found that whenever I edited an existing MailChimp template, MailChimp appeared to rewrete my mc:edit fields after I saved them and added their own code making my mc:edit fields break. However, if I exported one of their templates to my desktop, and then imported it back as a new template, I found that editing the template on their website no longer changed my code after saving. I remember seeing a note in the documentation about exporting and importing, but nothing that implied that was the only way to keep my fields intact.
So I've created a page called "Settings". Obviously in this page is where the settings are for the app. In the Settings page I've added 2 ToggleSwitches and 1 Listpicker. Using the Nokia Developer website on basics of Saving and reading Settings i managed to pull it off so it saves the states of the toggleswitches and listpicker.
The problem i'm having right now is that i need a way to read these saved setting values on the first page when the app starts so it can prepare the app accordingly. Soo far this is what i have in the Settings page:
Imports System.IO.IsolatedStorage
Partial Public Class Settings
Inherits PhoneApplicationPage
Private AppSettings As IsolatedStorageSettings
Public Sub New()
InitializeComponent()
AppSettings = IsolatedStorageSettings.ApplicationSettings
ListPicker1.Items.Add("Saved Notes")
ListPicker1.Items.Add("Important")
End Sub
Protected Overrides Sub OnNavigatedTo(e As NavigationEventArgs)
Try
Tg1.IsChecked = CBool(AppSettings("UseAccentColor"))
Tg2.IsChecked = CBool(AppSettings("GoBack"))
ListPicker1.SelectedIndex = CByte(AppSettings("StartListFalse"))
Catch ex As KeyNotFoundException
AppSettings.Add("UseAccentColor", False)
AppSettings.Add("GoBack", False)
AppSettings.Add("StartListFalse", False)
AppSettings.Save()
End Try
End Sub
Protected Overrides Sub OnNavigatedFrom(e As NavigationEventArgs)
System.Diagnostics.Debug.WriteLine("Exiting, so save now")
AppSettings("UseAccentColor") = Tg1.IsChecked
AppSettings("GoBack") = Tg2.IsChecked
AppSettings("StartListFalse") = ListPicker1.SelectedIndex
AppSettings.Save()
End Sub
End Class
So soo far it saves on exit but i need a way to load these from startup i.e. my MainPage. Like a way to refer to this page and according to these settings change whatever needs to be changed.
How can i do this?
Thanks!
You managed to save Settings to IsolatedStorage, and IsolatedStorage is accesssible from any page of your application. So in MainPage, just read those setting from IsolatedStorage instead of the Settings Page.
EDIT :
You can do it just like in OnNavigatedTo method in Settings Page
Private AppSettings As IsolatedStorageSettings = IsolatedStorageSettings.ApplicationSettings
'Tg1.IsChecked is analog with useAccentColor
Dim useAccentColor As Boolean = CBool(AppSettings("UseAccentColor"))
'Tg2.IsChecked = goBack
Dim goBack As Boolean = CBool(AppSettings("GoBack"))
'ListPicker1.SelectedIndex = startListFalse
Dim startListFalse As Byte = CByte(AppSettings("StartListFalse"))