DogMelon

Lesson 7: Managing Pages

filename: lesson07-manage_pages.py
getName() Lesson 07 - Manage Pages
getDescription() Lesson 07 - Learn how to manage pages via the plugin API


Let's be honest. Last lesson was a bit of a holiday. Only one new function - remove a book - not exactly a stretch. But now it's time to accelerate again. We're going to learn all about pages. Writing pages is really the core purpose of Note Studio, so this is probably the most important lesson in the whole series - it's just that we've had to get through the all of the previous lessons for this lesson to make sense!

Something Old, Something New

Let's refresh our minds with some stuff we covered a while ago. In lesson 3, we saw how to get page names and page contents. If we have a WikiBook object called 'book', then we can get them like so:

Page Name:

	numPages = book.getNumPages()
	for i in range( numPages ):
		pageName = book.getPageName( i )

Page Contents:

	page = book.getPage( i )
	rawText = page .getText()

Another Page Name

You're going to see another way to get the page name. In the above method, it's accessed by calling 'getPageName()', which is a method of the WikiBook object.

There's also a 'getName()' method on the WikiPage object itself:

	page = book.getPage( i )
	pageName = page.getName()

So, when would you use each method? Why are there two methods?

Well, it comes down to performance.

If you are iterating through all pages in a book, WikiBook.getPageName() method can be significantly faster than WikiPage.getName(). This is because when you create a book object, it immediately contains all of the page names. So WikiBook.getPageName() simply requires the book to access an array element from RAM.

WikiPage.getName(), on the other hand, creates a page object for each page. This means a file has to be read from the disk, and a lot of initialization has to be done on the page object, before you can query its name.


So which method to use? If you need to create the page object for other reasons anyway, you may as well use WikiPage.getName(). But if you can avoid creating the page object, it's preferable to use WikiBook.getPageName().

Creating a Page

Alright, enough background. Let's look at the plugin code for this lesson. First, it does the same preliminary setup as the previous lesson, creating a new book, with a default home page, and adding it to your first collection. Nothing new there.


So how do we add a new page to an existing book? Well, you might have some idea already. Remember how when we created a book, and we had to add a page to ensure that the book was valid? Well, that's how you do it. We add a few different pages to the book as follows:

	book.addPageWithNameAndContents( "page 1", "This is page 1" )
	book.addPageWithNameAndContents( "page 2", "This is page 2"  )
	book.addPageWithNameAndContents( "page 3", "This is page 3"  )

Now we the book has a total of four pages - the home page plus the three new pages. Note that we did not have to connect these new pages to any others. They are effectively floating pages, visible only via the Navigator or 'Go To Page' command. This is completely valid.


We can then verify that:

	numPages = theAppData.library.getNumPages()
	outputFile.write( "Current Number of Pages: %d\n"%(numPages) )

	outputFile.write( "Page Summary\n" )
	outputFile.write( "#: Name - Contents\n" )
	for i in range( numPages ):
		page = book.getPage(i)
		name = page.getName()
		text = page.getText()
		outputFile.write( "%d: '%s' - '%s'\n"%(i,name,text) )

Writing Page Contents

Modifying a page is done with the 'setText' function. Let's see it in action.


To each of the new pages, we're going to add a footer which points back to the Home Page. Here's how we do it. We set up an outer loop, iterating through all pages in the book. We do it so that we can skip over the Home Page, which we've decided does not need a footer:

def lesson07_addFooterToNewPages( outputFile, book ):
	outputFile.write( "\n\nin lesson07_addFooterToNewPages()\n" )
	numPages = book.getNumPages()
	homePageName = book.getHomePage()
	for i in range( numPages ):
		page = book.getPage(i)
		name = page.getName()
		if( name == homePageName ):
			outputFile.write( "skipping home page '%s'\n"%homePageName )
		else:
			outputFile.write( "adding footer to '%s'\n"%name )
			addFooter( page, homePageName )

Appending a footer onto each page is done in the 'addFooter()' routine:

def addFooter( page, homePageName ):
	text = page.getText()
	text = text + "\n___\n=[[%s][go Home]]=\n"%homePageName
	page.setText( text )

Note that there is no special way to append or prepend text. All we can do is set the entire page contents. So if we want to append a footer, we must first read the current contents, then manually append our text, then write the new contents.


Now, because we're having so much fun, let's modify the Home Page so that it acts as a directory listing all other pages in the book. We construct the contents of the page, step by step:

	homeText = "=This page was automatically created by a plugin=\n"
	homeText = homeText + "___\n"
	homeText = homeText + "++Directory of Pages\n"
	homeText = homeText + "=number of pages in directory: %d=\n"%(numPages-1)

We loop through page names, so that we can skip the Home Page:

	for i in range( numPages ):
		name = book.getPageName(i)
		if( name == homePageName ):
			outputFile.write( "skipping home page '%s'\n"%homePageName )
		else:
			outputFile.write( "adding directory entry for '%s'\n"%name )
			homeText = homeText + "- [%s]\n"%name

Finally, when the text is complete, we set the page contents:

	homePage.setText( homeText )

The directory is now complete.

Renaming a Page

Renaming a page is easy. We'll make a page called 'page 4', and rename it to 'page wookie'. The plugin code contains a lot of logging statements, to prove that the page is actually renamed. Stripping out those logging statements, it essentially reads:

	book.addPageWithNameAndContents( oldName, "This page is going to be renamed" )
	book.renamePage( oldName, newName )

As well as renaming the page, a rename page operation goes through the entire book, renaming any link which pointed to the old page name, so you don't have to worry about doing that.

Removing a Page

No sooner have we created that page and renamed it, that we're going to remove it. By the time the plugin ends, you won't be able to see any evidence that the page exists. Except in the output log file ('lesson07.txt'). Here's how we remove a page:

	doomedPage = book.findPage( pageName )
	book.removePage( doomedPage )

Like with removing a book, there is no warning message or opportunity for confirmation. The page is simply removed.

Conclusion

This has been the last part of our series on managing Note Studio data. It is not the last lesson - we haven't even popped up a dialog or interracted with the user yet. But we have all the basic tools we need to manipulate our data. Have fun!

API Functions:

WikiBook.findPage( pageName )

WikiBook.getHomePage()

WikiBook.removePage( page )

WikiBook.renamePage( oldName, newName )

WikiPage.getName()

WikiPage.setText()


View Plugin Source