ForAll Loop breaks inline images of email in Lotus Notes - email

I do have a Lotus Notes email containing inline images. When I run the following lines of code which simply changes the subject of the email the inline images is lost.
Sub Initialize
Dim ns As New NotesSession
Dim nc As NotesDocumentCollection
Dim nd As NotesDocument
Set nc = ns.Currentdatabase.Unprocesseddocuments()
Set nd = nc.GetFirstDocument()
ForAll Items In nd.Items
End ForAll
Call nd.Replaceitemvalue("Subject", "Forall")
Call nd.Save(True, False)
End Sub
The problem is caused by the ForAll loop which actually doesn't do anything. If the loop is commented out the inline images still remain on the email.
I'm hoping any of you guys has an idea or advise how to solve this issue.
Cheers,
Martin

Your message body is probably being converted from Notes rich text to MIME when the item is accessed and then being re-saved, with a loss of fidelity.
Try setting ns.ConvertMIME = false at the beginning of your code.

Related

How to run a spell check on a string without user input?

I'm trying to run a spell check on a string using word, but I don't want to have to go through each word manually and determine the correct spelling. Is there a way to do this automatically, so that it corrects all the misspelled words on its own? Here is my code so far, this works but I have to go through each word and hit change...
If Address.Length > 0 Then
Dim word_server As New Word.Application
word_server.Visible = False
Dim doc As Word.Document = word_server.Documents.Add()
Dim rng As Word.Range
rng = doc.Range()
rng.Text = Address
doc.Activate()
doc.CheckSpelling()
Address = doc.Range().Text
doc.Close(SaveChanges:=False)
word_server.Quit()
doc = Nothing
rCell.Value = Address
End If
Use the GetSpellingSuggestions function to bypass the GUI. to see if there are any spelling suggestions, and then you can set it to the first suggestion (which could be a bad idea).
How do you want to determine what the correct spelling is? Should "spon" be spoon, span, spin, spun, or son? This code optimistically assumes that the first suggestion (if one exists) is the correct solution.
Declare:
Dim oError As Word.Range
And then replace:
doc.Activate()
doc.CheckSpelling()
with:
For Each oError In rng.SpellingErrors
If oError.GetSpellingSuggestions.Count > 0 Then
oError.Text = oError.GetSpellingSuggestions().Item(1).Name
Else
'Uh oh, no suggestions, do something here.
End If
Next
These websites might help. The example code in the website shows how to call Word to spell check. You should be able to modify it, to use with your code.
http://www.vb-helper.com/howto_net_spellcheck.html
http://www.vbforums.com/showthread.php?307151-SPELL-CHECK-and-WORD

(Vba) Ms Word: Work around the 255 characters limit

I'm new to programming and I'm trying to copy the content of a form field to another form field in the same Word document like this:
Sub Copyfield()
Dim Temp As String
Temp = ActiveDocument.FormFields("Field1").Result
ActiveDocument.FormFields("Field2").Result = Temp
End Sub
My problem is that my "Field1" is a piece of text of more than 255 characters which seems to be a problem with "Result". I know there is a very similar topic here: Passing MS-Access string >255 characters to MS-Word field but I still don't have the 50 reputation to comment on that thread.
Could anyone please help me understand how to implement the changes in my code?
Well, here's one possibility. Since I don't have your environment it was easier for me to test text in the document rather than another form field with so much content. You'll need to adjust the code accordingly.
The key is to get the Selection "inside" the form field so that it doesn't hit the "protection barrier". Just using FormField.Select puts the focus at the beginning of the field, which VBA is seeing as "protected". Moving one character to the right corrects that and long text can then be assigned to the Selection. But the field needs to have content.
So what my code is doing is "slicing off" the first word of the text to go into the form field. That's short enough to assign to the Result property and lets the Selection move to its right. Then the rest - the long text - can be assigned to the Selection.
You'll probably want to assign the entire FormField.Result to a string variable, then manipulate that string.
Sub WriteLongTextToFormField()
Dim ffld As word.FormField
Dim doc As word.Document
Dim rng As word.Range
Dim s1 As String, s2 As String
Set doc = ActiveDocument
'Get the long text
Set rng = doc.Range(doc.Paragraphs(1).Range.Start, doc.Paragraphs(6).Range.End)
'Split off a bit to go into FormField.Result
s1 = rng.Words(1)
rng.MoveStart wdWord, 1
'The rest of the long text, to be assigned to Selection.Text
s2 = rng.Text
Set ffld = doc.FormFields("Text1")
ffld.result = s1
ffld.Select
Selection.MoveRight wdCharacter, 1
Selection.Text = s2
End Sub
Ok, after 3 days at the border of madness, finally thanks to the help of #Cindy Meister (and some serious personal digging), I made it work. Maybe it's not a big deal for you geniouses out there but believe me for me it was like seeing everything in Matrix code (from the movie guys, the movie).
I want to post it and share because I tried to find it in every corner of our Internet and part of the extraterrestrial one and I couldn't. So hopefully it will be useful for another programming illiterate / dumb person (as myself).
Here is the code:
Sub CopyField()
Dim ffld As Word.FormField
Dim doc As Word.Document
Dim rng As String
Dim s1 As String, s2 As String
Set doc = ActiveDocument
'Get the long text
rng = ActiveDocument.FormFields("Field1").Result
'Split off a bit to go into FormField.Result
s1 = Left(rng, 4) 'Keeps the first 4 characters of the rng string starting from left to right this can be adapted
'The rest of the long text, to be assigned to Selection.Text
s2 = Mid(rng, 5) 'Starting from the 5th character from the left keeps the rest of the string
Set ffld = doc.FormFields("Field2")
ffld.Result = s1
ffld.Select
Selection.MoveRight wdCharacter, 1
ActiveDocument.Unprotect 'Unprotects the document!
Selection.Text = s2
ActiveDocument.Protect Type:=wdAllowOnlyFormFields, NoReset:=True 'Protects the document again!
ActiveDocument.Bookmarks("Field1").Select ' "Sends cursor" back to Field1
End Sub
Big part of the code is originally by #Cindy Meister... I just adapted it to my situation where I had 2 form fields instead of paragraphs. I also had to add some lines to unprotect the document at a certain point in order to make it work (ask the Pros for the reason) and a final instruction to come back to "Field1" (which is some pages up) after the process. Finally just a note for my dumb fellows: I added the macro "on exit" on the "Field1" properties to automatize the process.
Huge thanks Cindy again and I hope you help in my dark programming moments again ! (please do)
:)

Error 1004 - Vlookup in vba - Unable to get the Vlookup property of the WorksheetFunction class

I've browsed the various questions already asked with this issue other users have faced and none of the solutions seem to fix the error code coming up.
I have a form which prompts the user for a reference number - they input this into the text field and then press OK
'OK button from form1
Public Sub CommandButton1_Click()
refInput = refTextBox.Value
InputRef.Hide
ExportShipForm.Show
End Sub
Once this has been pressed, the next form appears which I would like to be populated with data based on the reference number input on the first form. I have an update button which will update the "labels" on the form to show the data - this is where I am getting an error.
The first label to update is through a Vlookup:
Below the users clicks the update button the 2nd form:
Public Sub btnUpdate_Click()
Call ICS_Caption
lbl_ICS.Caption = Label_ICS
End Sub
This calls a function below:
Public Sub ICS_Caption()
Dim ws1 As Worksheet
refInput = InputRef.refTextBox.Value
Set ws1 = Worksheets("MACRO")
dataRef = Worksheets("Shipping Data").Range("A:K")
Label_ICS = WorksheetFunction.VLookup(refInput, dataRef, 7, False)
End Sub
The error continues to come up each time - I have ran the vlookup manually in a cell outside of VBA and it works fine.
I have typed the range in the Vlookup whilst also using named ranges but each variation shows the same error.
Eventually, I would want the label on form 2 to update with the result of the Vlookup.
Any ideas?
You need to Dim dataRef as Range and then Set it.
See code Below:
Dim DataRef as Range
Set dataRef = Worksheets("Shipping Data").Range("A:K")
Just like a Workbook or Worksheet you need to Set the Range
Just as Grade 'Eh' Bacon suggest in comments its always best to Dim every reference.
The best way to do so is to put Option Explicit all the way at the top of your code. This forces you to define everything which helps it preventing mistakes/typo's etc.
Update edit:
The problem was you are looking for a Reference number in your Sheet (thus an Integer) but refInput is set as a String this conflicts and .VLookup throws an error because it can't find a match.
I have reworked your code:
Your sub is now a function which returns the .Caption String
Function ICS_Caption(refInput As Integer)
Dim dataRef As Range
Set dataRef = Worksheets("Shipping Data").Range("A:K")
ICS_Caption = WorksheetFunction.VLookup(refInput, dataRef, 7, False)
End Function
The update Button calls your Function and provides the data:
Public Sub btnUpdate_Click()
lbl_ICS.Caption = ICS_Caption(InputRef.refTextBox.Value)
End Sub
By using a Function you can provide the Integer value and get a return value back without the need of having Global Strings or Integers.
Which would have been your next obstacle as you can only transfer Variables between Modules/Userforms by using a Global Variable.
I would even advice to directly use the function in the Initialize Event of your 2nd Userform to load the data before the Userform shows this is more user friendly then needing to provide data and then still needing to push an update button.
Verify that you have no missing libraries in VBA IDE > Tools > References
Try using a worksheet cell as the place to store and retrieve refTextBox.Value, rather than refInput (which I assume is a global variable):
Public Sub CommandButton1_Click()
...
Worksheets("Shipping Data").Range($M$1).Value=refTextBox.Value
End Sub
Public Sub ICS_Caption()
Dim refInput as Long'My assumption
...
refInput=Worksheets("Shipping Data").Range($M$1).Value
...
End Sub
Make sure you have Option Explicit at the top of all of your code windows.

Creating a 'calendar matrix' in Access

I’m trying to create either a report or form that displays data in essentially a “calendar” form.
I have a course query that is (simplified) as “Course name”; “course days”; “course times”---
Course; Days; Times
PSY 1; MW; 8A-9A
SOC 150; M; 8A-11A
ANTH 2; Tu; 8A-9A
ANTH 199; MW; 8A-9A
In Access, I’m trying to create a form based on the query that would give me a matrix of the following:
Columns: Times in hour increments
Rows: Days of week
So, for example, with the above data, it would appear like this:
Edit: Yargh, I can't submit an image unfortunately. So, here is a link to a "course schedule" that is essentially what I'm trying to do: Schedule
I have no idea where to start with this. Any tips (or links)?
Edit:
One idea I have is to create a form with a field for every possible cell in the matrix (so, for example, there would be one "Monday, 8-9A" field--and that field would be a filter on the query that ONLY displays results where "day" contains "M" and BeginTime or EndTime or between 8A and 9A). Unfortunately, I'm not sure how to do that.
You can do something close to what you seem to want as an Access form, but it's not easy. This screen capture displays your sample data in a Datasheet View form whose record source is an ADO disconnected recordset. It uses conditional formatting to set the text box background color when the text box value is not Null. Your picture suggested a different color for each Course, but I didn't want to deal with that when more than one Course can be scheduled in the same time block ... my way was simpler for me to cope with. :-)
The code to create and load the disconnected recordset is included below as GetRecordset(). The form's open event sets its recordset to GetRecordset().
Private Sub Form_Open(Cancel As Integer)
Set Me.Recordset = GetRecordset
End Sub
Note I stored your sample data differently. Here is my Class_sessions table:
Course day_of_week start_time end_time
------ ----------- ---------- -----------
PSY 1 2 8:00:00 AM 9:00:00 AM
PSY 1 4 8:00:00 AM 9:00:00 AM
SOC 150 2 8:00:00 AM 11:00:00 AM
ANTH 2 3 8:00:00 AM 9:00:00 AM
ANTH 199 2 8:00:00 AM 9:00:00 AM
ANTH 199 4 8:00:00 AM 9:00:00 AM
This is the function to create the disconnected recordset which is the critical piece for this approach. I developed this using early binding which requires a reference for "Microsoft ActiveX Data Objects [version] Library"; I used version 2.8. For production use, I would convert the code to use late binding and discard the reference. I left it as early binding so that you may use Intellisense to help you understand how it works.
Public Function GetRecordset() As Object
Dim rsAdo As ADODB.Recordset
Dim fld As ADODB.Field
Dim db As DAO.Database
Dim dteTime As Date
Dim i As Long
Dim qdf As DAO.QueryDef
Dim rsDao As DAO.Recordset
Dim strSql As String
Set rsAdo = New ADODB.Recordset
With rsAdo
.Fields.Append "start_time", adDate, , adFldKeyColumn
For i = 2 To 6
.Fields.Append WeekdayName(i), adLongVarChar, -1, adFldMayBeNull
Next
.CursorType = adOpenKeyset
.CursorLocation = adUseClient
.LockType = adLockPessimistic
.Open
End With
strSql = "PARAMETERS block_start DateTime;" & vbCrLf & _
"SELECT day_of_week, Course, start_time, end_time" & vbCrLf & _
"FROM Class_sessions" & vbCrLf & _
"WHERE [block_start] BETWEEN start_time AND end_time" & vbCrLf & _
"ORDER BY day_of_week, Course;"
Set db = CurrentDb
Set qdf = db.CreateQueryDef(vbNullString, strSql)
dteTime = #7:00:00 AM#
Do While dteTime < #6:00:00 PM#
'Debug.Print "Block start: " & dteTime
rsAdo.AddNew
rsAdo!start_time = dteTime
rsAdo.Update
qdf.Parameters("block_start") = dteTime
Set rsDao = qdf.OpenRecordset(dbOpenSnapshot)
Do While Not rsDao.EOF
'Debug.Print WeekdayName(rsDao!day_of_week), rsDao!Course
rsAdo.Fields(WeekdayName(rsDao!day_of_week)) = _
rsAdo.Fields(WeekdayName(rsDao!day_of_week)) & _
rsDao!Course & vbCrLf
rsAdo.Update
rsDao.MoveNext
Loop
dteTime = DateAdd("h", 1, dteTime)
Loop
rsDao.Close
Set rsDao = Nothing
qdf.Close
Set qdf = Nothing
Set GetRecordset = rsAdo
End Function
Actually, if you look at the following video of mine, you can see a calendar created in Access that runs inside of a browser with the new Access Web publishing feature.
http://www.youtube.com/watch?v=AU4mH0jPntI
So, all you really need to do here is format a form with text boxes and setup some code to fill them. VBA or even the above video shows this is quite easy for Access.
I doubt that you will find an easy solution for this problem in Access forms or reports.
The issue is that you need to format different cells differently, and that cells can span multiple rows and have to be merged.
If I were you, I would go in either of these 2 directions:
Drive Excel from Access, because you can format and merge cells independently
Use the Web Browser Control to display HTML that you construct yourself using tables, or a more high-level library like FullCalendar
I would be partial to tryingthe Web Browser and find the right library that can properly format the data.
I know this post is quite old, but I had the same requirement but I got round it by doing the following:
I created a module that would write HTML code (as a text file) to produce the data using a table.
I used the colspan feature of tables to enable me to dynamically produce the view I needed.
The HTML file was created on the Form_Open event and by pointing the webbrowser control to the HTML file the view shows the latest data.
A css file is used to handle the visual display of the HTML file so that it looks similar to the Access forms already in use.
If anyone is interested I can post some code to further illustrate.

SWT Java placing/receiving stuff from clipboard

I am trying to write some strings to the clipboard in my Eclipse plugin and I have some strange behavior ...
I am using the predefined TextTransfer Transfer-class which should be sufficient for strings?!
My Problem is, that regardless of the number of strings I put in the clipboard only the very last is actually accessible afterwards - I cannot figure out why.
Placing my stuff in the clipboard seems to work, no exceptions. I doing it this way:
Clipboard cb = new Clipboard(Display.getCurrent());
Object[] data = transferObjects.toArray(); //My strings, looks good in debug
Transfer[] transfer = transferHandles.toArray(new Transfer[0]); //as many TextTransfer instances as objects in the data-array
cb.setContents(data, transfer, DND.CLIPBOARD);
cb.dispose();
I receive it this way:
TextTransfer textTransfer = TextTransfer.getInstance();
Object o = cb.getContents(textTransfer); // "o" contains the value of the above array at position n-1, so only the very last is actually returned
I don't get what I am doing wrong? Does anyone see my error?
May be it is because (from Java-doc):
More than one type of data can be placed on the system clipboard at the same time. Setting the data clears any previous data from the system clipboard, regardless of type.