Archive for June, 2011

When watermark is not a drop in the ocean

Tuesday, June 14th, 2011

Some pdfs don’t allow you to copy their text:

I downloaded PDF Password Recovery from CNET (claimed to be spyware free). It removed all the restrictions:

That the shareware program added a watermark on each page did not matter since all I wanted to do was to copy text. To remove the watermark has a price tag of USD 19.95.

[Update]:

I found an even better program: PDFTools. I downloaded it from CNET (to hopefully avoid spyware).

PDFTools has this menu:

If you try the decrypt option it asks you for the password to remove, so that is not the option you want. However, if you split the pdf all restrictions are removed and it splits (by the way: pdfsam can not split a protected pdf file).

Conclusion: I will remove pdfsam, A-PDF merger, and  PDF Password Recovery from the computer and keep only PDFTools!

Creating and naming 155 text documents

Sunday, June 12th, 2011

(This post is a continuation of this post.)

My idea is to create a spreadsheet with Open Office Calc (if the spreadsheet does not already exists), write a form letter with Open Office Writer, merge the data in the spreadsheet with the form letter, and finally print individual documents, one for each student.

The procedure for doing this is clearly explained here. Note the field called “filename”.

There is only one problem with this,  the option “Save as individual documents” doesn’t work any more. It is a recognised bug!

As far as I can see, MS Word 2003 does not have the option to save as individual documents.

One way to make this work is to do the mail merge manually in a macro. In a spreadsheet I have two columns, one for the name of the student and one for his form. The top row has “student” and “form” as heading for these columns.

A report template, called reportcardtemplate.doc has the text “<student>” and “<form>” and they will be replaced manually by the current row read in the spreadsheet. Actually, to make life simpler, I am reading the entire spreadsheet into an array first.

The manual mail merge will save the created documents into a folder bearing the name of their form and they will be named after the student. For example will John Lennon in form 9 have his report card saved in the folder “9″ and be called “John Lennon.doc”.

Here is the entire code:

Sub test01()

' better to redim the array as we go along
Dim arr(2000, 2) ' max 2000 students
' better to read the folder the current word document is sitting in
cmainfolder = "C:\Documents and Settings\Jan\Escritorio\BTS report card programs\creating 155 word documents\"

' better to ask for the template in a dialog box
ctemplate = "reportcardtemplate.doc"

' ask the user for a folder
cfolder = GetFolderName("Please choose a folder to put the form folders in")
'MsgBox cfolder

If cfolder = "" Then
  MsgBox "fin"  
  Exit Sub
End If

' bring the spreadsheet into an array
' make an excel object    
' add a reference to the Excel-library; use the menu Tools - References    
Dim xlApp As Excel.Application    
Dim xlWB As Excel.Workbook        

' set it equal to the excel file    
Set xlApp = CreateObject("Excel.Application")    
' MsgBox cmainfolder + "students.xls"    
Set xlWB = xlApp.Workbooks.Open(cmainfolder + "students.xls")   

' go through each row from row 2 and put it into an array    
r = 2    
With xlWB.Worksheets(1)
        While Cells(r, 1).Formula <> ""
            arr(r - 1, 1) = Cells(r, 1).Value
            arr(r - 1, 2) = Cells(r, 2).Value
            r = r + 1
        Wend
    End With

' close    
xlWB.Close False ' close the workbook without saving  
xlApp.Quit ' close the Excel application    
Set xlWB = Nothing    
Set xlApp = Nothing
nstudents = r - 2
' go in a loop for number of records in the spreadsheet
For i = 1 To nstudents
 ' open the template    
  Documents.Open FileName:=cmainfolder + ctemplate
  ' replace <student> with arr(i,1), replace <form> with arr(i,2)    
For Each myStoryRange In ActiveDocument.StoryRanges ' this is overkill
        With myStoryRange.Find 
           .Text = "<student>"
            .Replacement.Text = arr(i, 1)
            .Wrap = wdFindContinue ' not needed since there is only one case, but does not hurt
            .Execute Replace:=wdReplaceAll
            .Text = "<form>"
            .Replacement.Text = arr(i, 2)
            .Wrap = wdFindContinue ' not needed since there is only one case, but does not hurt
            .Execute Replace:=wdReplaceAll
        End With
     Next myStoryRange
     ' save the template in the folder arr(i,2) and call it arr(i,1).doc
     ' find the complete paths
     If Right(cfolder, 1) <> "\" Then
          cfolder = cfolder + "\"
     End If
     arr(i, 1) = cfolder + arr(i, 2) + "\" + arr(i, 1)
     arr(i, 2) = cfolder + arr(i, 2)

     ' check if the folder arr(i,2) exists, if it does not then create it
     If Len(Dir(arr(i, 2), vbDirectory)) = 0 Then
          MkDir arr(i, 2)
     End If
     ActiveDocument.SaveAs (arr(i, 1))
     ActiveDocument.Close
     ' end of loop
Next i
MsgBox "fin"
End Sub

What is missing from the above code is what is needed to ask the user for a folder: the general declarations, the function GetFolderName, and the procedure TargetFolderName, all given in the first post of this series.

Using GoogleDocs for creating report cards

Saturday, June 11th, 2011

(This post is a continuation of this post.)

When my school’s server was down I was asked what we could do to enable the teachers to enter grades for the report card.

We discussed three possibilities:

  1. Send all 155 documents to the teachers and afterwards copy and paste to create the report card for each student. If each student has 10 teachers we are talking about 1,550 copy and paste operations. Estimated time: 9 hours. Sanity value: Negative.
  2. Share the documents using Dropbox. Dropbox gives you 2GB for free file sharing. The teachers would have to download and install the software. To open the Word documents and save them they would need Word 2003 or something that would not change any formatting of the original documents. Only one teacher could edit a student at a time. Before they could start work they would have to wait for the 155 files to be downloaded. After making changes they would have to keep their Internet connection open till the changes were uploaded. This solution avoids the copying and pasting challenge, but requires quite a bit computer knowledge and software to work well. Also, what for teachers not running Windows?
  3. Upload the Word documents to GoogleDocs. This would not have any of the drawbacks illustrated for Dropbox. However, I have had an instance where I could not save my changes and had to start all over again. Would this happen a lot? A positive point was that two teachers could edit the same report card at the same time.

The decision was to try GoogleDocs.

Big was my surprise when I tried to upload the Word document and get it converted to GoogleDocs.

The four columns in the Word document converted into five in GoogleDocs and the column widths were all nonsense! I went back to the Word table to see if it had more than four columns. It did not.

Internet search revealed that GoogleDocs reportedly is not doing a good job converting tables. However, when I tried to import a table in a test document it did not add any columns.

I went back to the original table and discovered something strange. The same column had different width depending on which row you were in! The change occurred between Art & Design and Science.

When I selected the table all rows were selected, so it was one table and not two. When I looked at the properties of the columns I discovered that the box “Preferred width” was not checked.

When I centered the table and checked “Preferred width” the table looked normal in Word and was converted correctly in GoogleDocs. The challenge was to do these changes in a macro.

To make a long story short, I did not manage! I could center the table, but all my attempts to check the preferred width boxes were unsuccessful. I tried to copy the code that was created when I recorded the macro manually, but to no avail.

' set columns widths of second table to preferred width
' this code did not work, it gave the error message:        
' "Cannot access individual columns in this collection because the table has mixed cell width
'ActiveDocument.Tables(2).Columns(1).PreferredWidthType = wdPreferredWidthPoints
'ActiveDocument.Tables(2).Columns(1).PreferredWidthType = wdPreferredWidthPoints        
'ActiveDocument.Tables(2).Columns(1).PreferredWidth = CentimetersToPoints(2.8)        
'ActiveDocument.Tables(2).Columns(2).PreferredWidthType = wdPreferredWidthPoints        
'ActiveDocument.Tables(2).Columns(2).PreferredWidth = CentimetersToPoints(9)        
'ActiveDocument.Tables(2).Columns(3).PreferredWidthType = wdPreferredWidthPoints        
'ActiveDocument.Tables(2).Columns(3).PreferredWidth = CentimetersToPoints(3.3)        
'ActiveDocument.Tables(2).Columns(4).PreferredWidthType = wdPreferredWidthPoints        
'ActiveDocument.Tables(2).Columns(4).PreferredWidth = CentimetersToPoints(1)

I also tried things like this:

Selection.SelectColumn        
Selection.Columns.PreferredWidthType = wdPreferredWidthPoints        
Selection.Columns.PreferredWidth = CentimetersToPoints(2.83)                
Selection.Move Unit:=wdColumn, Count:=1        
Selection.SelectColumn        
Selection.Columns.PreferredWidthType = wdPreferredWidthPoints      
Selection.Columns.PreferredWidth = CentimetersToPoints(9.63)

Since time was of an essence I ran my macro and then checked the boxes manually for all 155 Word documents. It took about an hour and was no great fun. I am still curious of how it can be achieved and will update this post if I find out.

[Update: see this forum post]

A last problem was that the Word document used a table to position text, but wanted no table border. Conversion always gave a border. I tried to set the border size to zero in Word and several other things, but GoogleDocs always showed a border. Manually I had to go in to all 155 GoogleDocs documents to change the border color to white. The smallest border size in GoogleDocs os 0.5 pt, not 0 pt.

Of course, if the Word document was made with GoogleDocs conversion in mind no manual corrections would have been necessary.

Here is an example of what the report looks like in GoogleDocs.

The next post will look at how the 155 individual Word documents can be created and named using mail merge and/or vbscript. (After that, I will look at more sensible approaches to the whole report card business.)

Time for reports cards with spelling mistakes

Saturday, June 11th, 2011

Many schools create one text document for each student. They then ask the teacher to enter grades on the local school network. An example in point: my present school.

This has some obvious disadvantages:

  1. If the school’s network is down no grades can be entered. This just happened at my school. The server was down for three weeks.
  2. Since the data is collected in a text document and not in a database table analysis of the data is not feasible.
  3. It is difficult to change the layout or text on the report when grades have been entered.
  4. Two teachers can not enter grades on the same student at the same time.
  5. By mistake teachers may create havoc to the report layout or content.
  6. The teachers have to wade through all students to find the ones they teach. They may miss someone and/or enter grades under the wrong subject heading. The teachers have no way of knowing that they have entered all the grades.

Here are its major advantages:

  1. It is rather easy to create the empty reports using mail merge, or even by adding the students’ names manually and naming the text document with their name.
  2. Teachers’  grades  and tutors’ comments can be entered in the same document.

Better ways of doing this do exist, of course, and some of them does not cost a fortune, but more about that later. Now I want to deal with disadvantage 3 above:

It is difficult to change the layout or text on the report when grades have been entered.

155 empty report cards had been put on the local server when thee mistakes were noted.

  1. The school’s name is “Academy St James” (fictional), but had been entered as “Academy of St James”.
  2. The text “Absent:” had not been put in bold. “Lates:” was correctly entered in bold.
  3. “classwork” should have been “class work”.

If the empty reports were created by mail merge, (I don’t know how they were created and there was no time to find out), one could easily fix these mistakes in the source document and merge again with the data. But if the 155 reports were created manually, or if these mistakes had been discovered after some or all of the grades had been entered, then what?

An obvious solution would be to manually fix the errors in all 155 documents. This could take any time from one to three hours and afterwards one might not remember the capital of France.

A more attractive solution was to write a macro that would do all the corrections automatically and that could be used if/when other mistakes, changes were called for. Since the reports were Word documents I made a Word macro.

The first task was to reinstall MS Word 2003 on my netbook. I had just made an oath not to use MS Office again, but this was an emergency. (I am more than happy with the free Open Office.)

The report cards were divided into folders. One folder per tutor group. Each folder had a document for each students. About 15-25 documents per folder.

My macro would ask me for the folder and perform the changes on all the documents in the folder. I would run the macro for the seven folders.

To ask the user for a folder, as opposed to a file, requires quite a lot of instructions in VBA (Visual Basic for Applications). I found usable code quite easily on the internet.

I put this code in General – Declarations:

Private Declare Function SHGetPathFromIDList Lib “shell32.dll” _    Alias “SHGetPathFromIDListA” (ByVal pidl As Long, ByVal pszPath As String) As LongPrivate Declare Function SHBrowseForFolder Lib “shell32.dll” _    Alias “SHBrowseForFolderA” (lpBrowseInfo As BROWSEINFO) As LongPrivate Type BROWSEINFO ‘ used by the function GetFolderName    hOwner As Long    pidlRoot As Long    pszDisplayName As String    lpszTitle As String    ulFlags As Long    lpfn As Long    lParam As Long    iImage As LongEnd TypePublic SubmissionStatus As StringPublic ValidationStatus As StringPublic Comp As StringPublic FolderName As String

The line breaks did not work out, but you get the gist.

Then a function was needed:

Function GetFolderName(Msg As String) As String’ returns the name of the folder selected by the userDim bInfo As BROWSEINFO, path As String, r As LongDim X As Long, pos As Integer    bInfo.pidlRoot = 0& ‘ Root folder = Desktop    If IsMissing(Msg) Then        bInfo.lpszTitle = “Select a folder.”        ’ the dialog title    Else        bInfo.lpszTitle = Msg ‘ the dialog title    End If    bInfo.ulFlags = &H1 ‘ Type of directory to return    X = SHBrowseForFolder(bInfo) ‘ display the dialog    ’ Parse the result    path = Space$(512)    r = SHGetPathFromIDList(ByVal X, ByVal path)    If r Then        pos = InStr(path, Chr$(0))        GetFolderName = Left(path, pos – 1)    Else        GetFolderName = “”    End IfEnd Function

And finally a procedure:

Sub TargetFolderName()
FolderName = GetFolderName("Select the Folder to Scan...")
If FolderName = "" Then
    MsgBox "You didn't select a folder. Please try again."
    End
End If
End Sub

Puuh! All that is needed for the simple call:

Sub test01()
' ask the user for a folder
cfolder = GetFolderName("Please choose a folder")

The next step is to open each document in turn:

Dim fsSearch As FileSearchSet 
fsSearch = Application.FileSearch
With fsSearch
    .FileName = "*.doc"
    .LookIn = cfolder
    .Execute    
    If .FoundFiles.Count = 0 Then
      MsgBox "No Word documents were found in " + cfolder
    Else
      For i = 1 To .FoundFiles.Count
          Documents.Open FileName:=.FoundFiles(i)
          ' code for making changes to the document just opened
          ActiveDocument.Close Savechanges:=wdSaveChanges
      Next i
    End If
End With
MsgBox "fin"
End Sub

To make changes are easy. Just add code  below the comment in red above.

Change “Academy of St James” to “Academy St James”:

For Each myStoryRange In ActiveDocument.StoryRanges
    With myStoryRange.Find
       .Text = "Academy of St James"
       .Replacement.Text = "Academy St James" 
       .Wrap = wdFindContinue
       .Execute Replace:=wdReplaceAll 
     End With
Next myStoryRange

The code is most likely overkill, but it works. To put text in bold I used this code:

' set a word in bold
Selection.Find.ClearFormatting
With Selection.Find
            .Text = "Absent:"
            .Replacement.Text = ""
            .Forward = True
            .Wrap = wdFindContinue
            .Format = True
            .MatchCase = False
            .MatchWholeWord = False
            .MatchKashida = False
            .MatchDiacritics = False
            .MatchAlefHamza = False
            .MatchControl = False
            .MatchWildcards = False
            .MatchSoundsLike = False
            .MatchAllWordForms = False
End With
Selection.Find.Execute
Selection.Font.Bold = True

Again, the code has probably too many instructions, but that is a minor concern in this case.

Next post will try to put the Word documents online as GoogleDocs documents.

Can not record video with Jing

Thursday, June 2nd, 2011

I just posted this here:

I use winxp and the latest Jing version. I can capture an image, but not a video. When I try the news reels show, but when I stop the recording the video witha start arrow does not appear. Just a white square. When I save the recording the swf file is 0KB. I also have Camtasia Studio installed. I don’t use Camtasia for recording as it slows the machine down a lot which is not ideal when you want to show features of programs you write. I have 1GB of RAM.

Regards,
Jan Nordgreen

A little bit of searching on the help site led to this. It suggested I go to desktop properties and: Move the Hardware Acceleration slider from Full to None and click Apply.

I did, and, sad to say, Jing still did not want to record videos. But, Columbus are you there?!, it solved the speed problem I had with Camtasia!

My reason for moving to Jing was the speed problem with Camtasia. Trying to get Jing to work I solved the original problem!

Morale: When trying to solve problem A solve a similar B and it may solve A.