Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials - Web Development

1797 Articles
article-image-django-12-e-commerce-generating-pdf-reports-python-using-reportlab
Packt
19 May 2010
6 min read
Save for later

Django 1.2 E-commerce: Generating PDF Reports from Python using ReportLab

Packt
19 May 2010
6 min read
(Read more interesting articles on Django 1.2 e-commerce here.) ReportLab is an open source project available at http://www.reportlab.org. It is a very mature tool and includes binaries for several platforms as well as source code. It also contains extension code written in C, so it's relatively fast. It is possible for ReportLab to insert PNG and GIF image files into PDF output, but in order to do so we must have the Python Imaging Library (PIL) installed. We will not require this functionality in this article, but if you need it for a future project, see the PIL documentation for setup instructions. The starting point in the ReportLab API is drawing to canvas objects. Canvas objects are exactly what they sound like: blank slates that are accessible using various drawing commands that paint graphics, images, and words. This is sometimes referred to as a low-level drawing interface because generating output is often tedious. If we were creating anything beyond basic reporting output, we would likely want to build our own framework or set of routines on top of these low-level drawing functions. Drawing to a canvas object is a lot like working with the old LOGO programming language. It has a cursor that we can move around and draw points from one position to another. Mostly, these drawing functions work with two-dimensional (x, y) coordinates to specify starting and ending positions. This two-dimensional coordinate system in ReportLab is different from the typical system used in many graphics applications. It is the standard Cartesian plane, whose origin (x and y coordinates both equal to 0) begins in the lower-left hand corner instead of the typical upper-right hand corner. This coordinate system is used in most mathematics courses, but computer graphics tools, including HTML and CSS layouts, typically use a different coordinate system, where the origin is in the upper-left. ReportLab's low-level interface also includes functions to render text to a canvas. This includes support for different fonts and colors. The text routines we will see, however, may surprise you with their relative crudeness. For example, word-wrapping and other typesetting operations are not automatically implemented. ReportLab includes a more advanced set of routines called PLATYPUS, which can handle page layout and typography. Most low-level drawing tools do not include this functionality by default (hence the name "low-level"). This low-level drawing interface is called pdfgen and is located in the reportlab.pdfgen module. The ReportLab User's Guide includes extensive information about its use and a separate API reference is also available. The ReportLab canvas object is designed to work directly on files. We can create a new canvas from an existing open file object or by simply passing in a file name. The canvas constructor takes as its first argument the filename or an open file object. For example: from reportlab.pdfgen import canvasc = canvas.Canvas("myreport.pdf") Once we obtained a canvas object, we can access the drawing routines as methods on the instance. To draw some text, we can call the drawString method: c.drawString(250, 250, "Ecommerce in Django") This command moves the cursor to coordinates (250, 250) and draws the string "Ecommerce in Django". In addition to drawing strings, the canvas object includes methods to create rectangles, lines, circles, and other shapes. Because PDF was originally designed for printed output, consideration needs to be made for page size. Page size refers to the size of the PDF document if it were to be output to paper. By default, ReportLab uses the A4 standard, but it supports most popular page sizes, including letter, the typical size used in the US. Various page sizes are defined in reportlab.lib.pagesizes. To change this setting for our canvas object, we pass in the pagesize keyword argument to the canvas constructor. from reportlab.lib.pagesizes import letterc = canvas.Canvas('myreport.pdf', pagesize=letter) Because the units passed to our drawing functions, like rect, will vary according to what page size we're using, we can use ReportLab's units module to precisely control the output of our drawing methods. Units are stored in reportlab.lib.units. We can use the inch unit to draw shapes of a specific size: from reportlab.lib.units import inchc.rect(1*inch, 1*inch, 0.5*inch, 1*inch) The above code fragment draws a rectangle, starting one inch from the bottom and one inch from the left of the page, with sides that are length 0.5 inches and one inch, as shown in the following screenshot: Not particularly impressive is it? As you can see, using the low-level library routines require a lot of work to generate very little results. Using these routines directly is tedious. They are certainly useful and required for some tasks. They can also act as building blocks for your own, more sophisticated routines. Building our own library of routines would still be a lot of work. Fortunately ReportLab includes a built-in high-level interface for creating sophisticated report documents quickly. These routines are called PLATYPUS; we mentioned them earlier when talking about typesetting text, but they can do much more. PLATYPUS is an acronym for "Page Layout and Typography Using Scripts". The PLATYPUS code is located in the reportlab.platypus module. It allows us to create some very sophisticated documents suitable for reporting systems in an e-commerce application. Using PLATYPUS means we don't have to worry about things such as page margins, font sizes, and word-wrapping. The bulk of this heavy lifting is taken care of by the high-level routines. We can, if we wish, access the low-level canvas routines. Instead we can build a document from a template object, defining and adding the elements (such as paragraphs, tables, spacers, and images) to the document container. The following example generates a PDF report listing all the products in our Product inventory: from reportlab.platypus.doctemplate import SimpleDocTemplatefrom reportlab.platypus import Paragraph, Spacerfrom reportlab.lib import sytlesdoc = SimpleDocTemplate("products.pdf")Catalog = []header = Paragraph("Product Inventory", styles['Heading1']) Catalog.append(header)style = styles['Normal']for product in Product.objects.all(): for product in Product.objects.all(): p = Paragraph("%s" % product.name, style) Catalog.append(p) s = Spacer(1, 0.25*inch) Catalog.append(s)doc.build(Catalog) The previous code generates a PDF file called products.pdf that contains a header and a list of our product inventory. The output is displayed in the accompanying screenshot.
Read more
  • 0
  • 0
  • 4290

article-image-managing-audio-content-plone-33
Packt
17 May 2010
10 min read
Save for later

Managing Audio Content in Plone 3.3

Packt
17 May 2010
10 min read
(For more resources on Plone, see here.) There are at least four use cases when we think of integrating audio in a web application: We want to provide an audio database with static files for download. We have audio that we want to have streamed to the Internet (for example, as a podcast). We want a audio file/live show streamed to the Internet as an Internet radio service. We want some sound to be played when the site is loaded or shown. In this article series, we will discuss three of the four cases. The streaming support is limited to use case 2. We can stream to one client like a podcast does, but not to many clients at once like an Internet Radio does. We need special software such as Icecast or SHOUTcast for this purpose. Further, we will investigate how we solve use cases 1, 2, and 3 with the Plone CMS and extensions. Technically, these are the topics covered in this article series: Manipulation of audio content stored as File content in Plone The different formats used for the binary storage of audio data Storing and accessing MP3 audio metadata with the ID3 tag format Managing metadata, formats, and playlists with p4a.ploneaudio in Plone Including a custom embedded audio player in Plone Using the Flowplayer product to include an audio player standalone in rich text and as a portlet Previewing the audio element of HTML5 Extracting metadata from a FLAC file using mutagen   Uploading audio files with an unmodified Plone installation The out of the box support of Plone for audio content is limited. What is possible to do is to upload an audio file utilizing the File content type of Plone to the ZODB. A File is nothing more and nothing less than a simple binary file. Plone does not make any difference between a MP3 file and a ZIP, an EXE, or an RPM binary file. When adding File content to Plone, we need to upload a file (of course!). We don't necessarily need to specify a title, as the filename is used if the title is omitted. The filename is always taken for the short name (ID) of the object. This limits the number of files with any specific name to one in a container While uploading a file, Plone tries to recognize the MIME type and the size of the file. This is the smallest subset of information shared by all binary files the content type File was intended for. Normally, detecting the MIME type for standard audio is not a problem if the file extension is correctly set. Clicking on the link in the default view either downloads the file or opens it with the favorite player of your operating system. This behavior depends on the settings made on the target browser and corresponds with the method 1 of our audio use cases. It goes without saying that we can add the default metadata to files and organize them in folders. Like Images, File objects do not have a workflow associated in a default Plone setup. They inherit the read and write permissions from the container they are placed into. Still, we can add an existing workflow to this content type or create a new one via the portal_workflow tool if we want. That's pretty much it. Fortunately, we can utilize some extensions to enhance the Plone audio story greatly. What we will see in this article is as follows: First, we will go over some theoretical ground. We will see what formats are available for storing audio content and which is best for which purpose. Later we will investigate the Plone4Artists extension for Plone's File content type—p4a.ploneaudio. We will talk about metadata especially used for audio content and how to manipulate it. As a concrete example, we will use mutagen to extract metadata from a FLAC file to add FLAC support to p4a.ploneaudio. Finally, we will have a word on streaming audio data through the Web and see how to embed a Flash player into our Plone site. We will see how we can do this programmatically and also with the help of a third-party product called collective.flowplayer. At the very end of the article, we have a small technical preview on HTML5 where a dedicated audio element is available. This element allows us to embed audio directly into our HTML page without the detour with Flash. Accessing audio content in Plone Once we upload a file we want to work with to Plone, we will link it with other content and display it in one way or another. There are several ways of accessing audio data in Plone. It can be accessed in the visual editor by editors, in templates by integrators and in Python code by developers. Kupu access Unlike for images, there is no special option in the visual editor to embed file/audio content into a page. The only way to access an audio file with Kupu is to use an internal link. The file displays as a normal link and is executed when clicked. Executed means (as for the standalone file) saved or opened with the music player of your operating system as is done in the standard view of the File content type. Of course, it is possible to reference external audio files as well. Page template access As there is no special access method in Kupu, there is none in page templates. If we need to access a file there, we can use the absolute_url method of the audio content object. This computes a link we can refer to. So the only way to access a file from another context is to refer to its URL. <a tal_attributes="href audiocontext/absolute_url"tal:content="audiocontext/Title">audio</a> Python script access If we need to access the content of an (audio) file in a Python script, we can get the binary data with the Archetype accessor getFile. >>> binary = context.getFile() This method returns the data wrapped into a Zope OFS.File object. To access the raw data as a string, we need to do the following: >>> rawdata = str(binary.data) Accessing the raw data of an audio file might be useful if we want to do format transformations on the fly or other direct manipulation of the data. Field access If we write our own content type and want to save audio data with an object, we need a file field. This field stores the binary data and takes care of communicating with the browser with adequate view and edit widgets. The file field is defined in the Field module of the Archetype product. Additional to the properties, it exclusively defines that it inherits from the ObjectField base class. The following properties are important. Key Default value type 'file' default ' ' primary False widget FileWidget content_class File default_content_type 'application/octet-stream'   The type property provides a unique name for the field. We usually don't need to change this. The default property defines the default value for this field. It is normally empty. If we want to change it, we need to specify an instance of the content_class property. One field of the schema can be marked as primary. This field can be retrieved by the getPrimaryField accessor. When accessing the content object with FTP, the content of the primary field is transmitted to the client. Like every other field, the file field needs a widget. The standard FileWidget is defined in the Widget module of the Archetypes product. The content_class property declares the instance, where the actual binary data is stored. As standard, the File class from Zope's OFS.Image module is used. This class supports chunk-wise transmission of the data with the publisher. Field can be accessed like any other field by its accessor method. This method is either defined as a property of the field or constructed from its name. If the name were "audio", the accessor would be getAudio. The accessor is generated from the "get" prefix with the capitalized name of the field. Audio formats Before we go on with Plone and see how we can enhance the story of audio processing and manipulate audio data, we will glance at audio formats. We will see how raw audio data is compressed to enable effective audio storage and streaming. We need to have some basic audio know-how about some of the terminology to understand how we can effectively process audio for our own purposes. As with images, there are several formats in which audio content can be stored. We want to learn a bit of theoretical background. This eases the decision of choosing the right format for our use case. An analog acoustic signal can be displayed as a wave: If digitalized, the wave gets approximated by small rectangles below the curve. The more rectangles are used the better is the sound (fidelity) of the digital variant. The width of the rectangles is called the sampling rate. Usual sampling rates include: 44.1 kHz (44,100 samples per second): CD quality 32 kHz: Speech 14.5 kHz: FM radio bandwidth 10 kHz: AM radio Each sample is stored with a fixed number of bits. This value is called the audio bit depth or bit resolution. Finally, there is a third value that we already know from the analog side. It is the channel. We have one channel for mono and two channels for stereo. For the digital variant, this means a doubling of data if stereo is used. So let's do a calculation. Let's assume we have an audio podcast with a length of eight minutes, which we want to stream in stereo CD quality. The sampling rate corresponds with the highest frequency of sound that is stored. For accurate reproduction of the original sound, the sample rate has to be at least twice that ofthe highest frequency sound. Most humans cannot hear frequencies higher than 20 kHz. The corresponding sampling rate to 20 kHz is a sampling rate of 44100 samples. We want to use a bit resolution of 16. This is the standard bit depth for audio CDs. Lastly, we have two channels for stereo: 44100 x 16 x 2 x 60 x 8= 677376000 bits = 84672000 bytes ˜ 80.7 MB This is quite a lot of data for eight minutes of CD-quality sound. We do not want to store so much data and more importantly, we do not want to send so much data over the Internet. So what we do is compress the data. Zipping the data would not give us a big effect because of the binary structure of digital audio data. There are different types of compressions for different types of data. ZIPs are good for text, JPEG is good for images, and MP3 is good for music—but why? Each of these algorithms takes the nature of the data into account. ZIP looks for redundant characters, JPEG unifies similar color areas, and MP3 strips the frequencies humans do not hear from the raw data.
Read more
  • 0
  • 0
  • 1201

article-image-audio-enhancements-p4aploneaudio-plone-33
Packt
17 May 2010
14 min read
Save for later

Audio Enhancements with p4a.ploneaudio in Plone 3.3

Packt
17 May 2010
14 min read
(For more resources on Plone, see here.) Audio enhancements with p4a.ploneaudio One of the most advanced products to boost the audio features of Plone is p4a.ploneaudio. Like its image sister p4a.ploneimage it doesn't bring a content type on its own, but expands existing ones. As you might have guessed already, the File content type and the folderish ones (Folder, Large Folder, and Collection) are chosen for the enhancement. To install it, add the following code to the buildout of our instance: [buildout]...[instance]...eggs =${buildout:eggs}Plonep4a.ploneaudiozcml =p4a.ploneaudio After running the buildout and restarting the instance, we need to install the product as an add-on product. We find it with the product name Plone4Artists Audio (p4a.ploneaudio). Enhancing files Installing the p4a.ploneaudio product enables the enhancement of the File content type of ATContentTypes. Unlike with the image enhancement, not all files are automatically enhanced with additional audio features. p4a.ploneaudio comes with a MIME type filter. If we upload a file with one of the meta types such as audio/MPEG or application/Ogg, the file will automatically be audio enhanced. All other files (such as ZIP files, EXE files, and so on) stay untouched. Technically speaking, this works via a named adapter. The first thing we see is the modified default view for audio-enhanced files: On the right side we see some technical information about the audio file itself. We find the size, the format (MP3 or Ogg), the bitrate, the frequency, and the length of the track there. As with any other content type, we have the title and the description at the top of the content area. For the audio-enhanced content, the description has changed from a simple text field to a rich text field. We find four buttons after the usual CMS bar (the belowcontenttitle slot) containing the author and the modification date of the file. Each of these buttons retrieves the audio file in a different way: Button Action Description     Play An embedded audio player written in Flash. Clicking on it starts playback immediately.     Pop up Opens a pop-up window with a Flash player playing the audio track. This is useful if someone wants to play the track while continuing to browse the site.     Stream Clicking on the button returns an M3U playlist with the URL of the file. The browser/operating system needs to take care of the handling of the stream. If you have a Mac, the file will be streamed to iTunes.     Download This is the standard behavior of Plone’s File content-type. The file is returned to the client like any other file object. It can be saved or opened with the favorite media player of the operating system.   We find a long list of additional information on the audio track below the player and streaming buttons. This information is the metadata stored with the audio file and is gathered during the enhancing process. It can be changed and written back to the file. Let's take a closer look on the enhancement process. One important step here is marking the content object with two interfaces: One is p4a.subtyper.interfaces.ISubtyped. This interface marks the content as subtyped. The other interface is p4a.audio.interfaces.IAudioEnhanced. This interface describes the type of enhancement, which is audio content in this case. All other views and components available with the enhanced version bind to the p4a.audio.interfaces.IAudioEnhanced interface. Additionally, p4a.ploneaudio tries to extract as much of the metadata information from the file as possible. The title is retrieved from the metadata and changed. Let's see what happens when a file is added in detail: It is possible to write custom audio enhancers if needed. The enhancers are queried as named adapters by the MIME type on the IAudioDataAccessor interface. Enhancing containers With p4a.ploneaudio, we can turn any Plone folder into an audio-enhanced folder by choosing Audio container from the Subtype menu. Two marker interfaces are attached to the container: p4a.subtyper.interfaces.ISubtyped p4a.audio.interfaces.IAudioContainerEnhanced The default view of the container is changed utilizing the IAudioContainerEnhanced interface. The new default view is audio-container.html, which comes with the p4a.ploneaudio product. In the View option we see one box for each track. For each track, the title and the cover artwork is shown. There is also an embedded Flash player to play each track directly. There are some other container views that come with the product as follows: audio-album.html (album view) audiocd-popup.html (pop-up view) cd_playlist.xspf And the default edit view for IAudioContainerEnhaced-marked folders is overridden. The audio-album.html view presents the audio content of the container in a slightly different way. The single tracks are arranged in a table. Two variants of this view are exposed in the Display menu of the container—Album view and Album view with no track numbers. Both these views are more compact than the default audio container view and have the same layout, except that the second one omits the column with the track numbers. As for the other audio container views, there is a player for each track. Moreover, there are two buttons on the top of the page. One is the commonly used RSS icon and the other one is the familiar pop-up player button . By clicking on the RSS icon, we get to the stream (or podcast of the folder). This may not be too interesting for a standard static Folder, but can be for a Collection where the content changes more dynamically. The pop-up player for a folder looks and operates slightly differently as the file standalone variant. It contains all tracks that are part of the audio container as a playlist. Lastly, there is the cd_playlist.xspf view. This view is not exposed via a display or as an action. It provides the audio data as a XSPF stream. The XML Shareable Playlist Format: XSPF The XML Shareable Playlist Format (XSPF) is an XML file format for storing playlists of digital audio. The audio can be located locally or online. Last.fm uses XSPF for providing its playlists. An example playlist looks like this: <?xml version="1.0" encoding="UTF-8"?><playlist version="1" ><trackList><track><location>example.mp3</location><creator>Tom</creator><album>Thriller</album><annotation>A comment</annotation></track><track><location>another.mp3</location><creator>Tom</creator></track></trackList></playlist> There is a list of applications supporting the XSPF format on the XSPF (http://xspf.org/) website. The default XSPF view of p4a.ploneaudio does not include all possible information. It provides the following attributes: location: This is the required location (URL) of the song. image: The album artwork that may be included with each track. annotation: p4a.ploneaudio collects information about the title, artist, album, and year in this field. It is easy to write a custom implementation of an XSPF view. Look at the available fields at the XSPF home page and the XSPF implementation of p4a.audio. We find the template named cd_playlist.xspf.pt in the p4a.audio.browser module. p4a.ploneaudio and the Plone catalog Besides the customized default views and the additional views, p4a.ploneaudio comes with a number of other changes. One very important change is the disclosure of some audio metadata fields to the portal catalog. This allows us to use them in catalog queries in general and smart folders in particular. The following indexes are added: Artist Genre Track Format The Artist attribute is exposed as metadata information in the catalog. Also, the genre and the artist name are added to the full text index SearchableText. The values for the genre field are hardcoded. The ID3 tag genre list is used together with the Winamp extensions. They are stored as a vocabulary. The term titles are resolved for Searchable Text, but not for the index and the Collection field. Accessing audio metadata in Collections To access catalog information in collections, it needs to be exposed to the collections tool. This can either be done by a product or TTW in the Plone configuration panel. p4a.ploneaudio comes with a modification of the fields: Artist (Artist name) Genre (Genre) Format (MIME Types) Let's say we want a collection of all our MP3 files. All we have to do is add a MIME Types criterion to our collection and set audio/mpeg as the value: ATAudio migration If you have an older Plone site (2.5), you probably have ATAudio installed to deal with audio content.ATAudio has features similar to p4a.ploneaudio. This is not surprising as p4a.ploneaudio was derived from ATAudio. The main difference is that ATAudio provides a content type, while p4a.ploneaudio reuses an existing one. If you want to switch from ATAudio to p4a.ploneaudio for one or the other reason, p4a.ploneaudio comes with a migration routine. One reason for switching might be that ATAudio is not actively developed any more and probably doesn't work with recent versions of Plone. For migrating, you need to call migrate-ataudioconfiglet.html and follow the instructions there. The migration view is available only if ATAudio is installed. There is a little bit of a catch-22 situation because p4a.ploneaudio doesn't run on Plone 2.5 and ATAudio doesn't run on Plone 3. This means there is no good starting point for the migration. At least, there is a version of ATAudio that does install in Plone 3 in the collective repository: http://svn.plone.org/svn/collective/ATAudio/tags/0.7- plone3migration/. Extracting metadata with AudioDataAccessors The IAudioDataAccessor interface is used for extracting metadata from binary audio content. If uploading a file, Plone tries to acquire a named adapter for the interface with the MIME type as the key. It has the following layout: class IAudioDataAccessor(interface.Interface):"""Audio implementation accessor (ie MP3, ogg, etc)."""audio_type = schema.TextLine(title=_(u'Audio Type'),required=True,readonly=True)def load(filename):"""Load from filename"""def store(filename):"""Store to filename""" The audio_type field contains a human-readable description of the audio type. In the case of MP3, the Unicode string "MPEG-1 Audio Layer 3" is used. The load and store methods are used for reading/writing the metadata from/to the audio file. The definition for the MP3 adapter looks like this: <adapterfor="p4a.audio.interfaces.IPossibleAudio"factory="._audiodata.MP3AudioDataAccessor"provides="p4a.audio.interfaces.IAudioDataAccessor"name="audio/mpeg"/> The component is registered for the p4a.audio.interfaces.IPossibleAudio interface. All classes marked with this interface are capable of getting converted to an audio-enhanced object. The standard product marks the File content type with this interface. The adapter provides the p4a.audio.interfaces.IAudioDataAccessor interface, which is the marker for the lookup. The name attribute of adapter is the key for the lookup and needs to be set to the MIME type of the audio file that should be processed. Now, the factory does the actual work of loading and storing the metadata from the audio file. p4a.ploneaudio and FLAC For the moment, p4a.ploneaudio only supports MP3 and Ogg Vorbis. This is a reasonable choice. Both formats are streamable and were made for good audio quality with small file sizes. We want to add FLAC support. We use mutagen for metadata extraction. Mutagen is an audio metadata extractor written in Python. It is capable of reading and writing many audio metadata formats including: FLAC M4A Monkey's Audio MP3 Musepack Ogg Vorbis True Audio WavPack OptimFROG Let's remember the flow chart of the audio adding process. We recall that we need a metadata extractor for our FLAC MIME type. First, we need to register a named adapter for this purpose. This is very similar to the MP3 adapter we saw before: <adapterfor="p4a.audio.interfaces.IPossibleAudio"factory=".flac._audiodata.FlacAudioDataAccessor"provides="p4a.audio.interfaces.IAudioDataAccessor"name="application/x-flac"/> The adapter is used for objects implementing the p4a.audio.interfaces.IPossibleAudio interface. The factory does the work of extracting the metadata. The adapter provides the p4a.audio.interfaces.IAudioDataAccessor interface. This is what the adapter is made for and the name is application/x-flac, which is the MIME type of FLAC audio files. Next, we define the metadata accessor: from mutagen.flac import Open as openaudio...from p4a.audio.ogg._audiodata import _safe First, we need some third-party imports. For the metadata extraction, we use the FLAC accessor of the mutagen library. _safe is a helper method. It returns the first element if the given parameter is a list or a tuple, or the element itself. class FlacAudioDataAccessor(object):"""An AudioDataAccessor for FLAC"""implements(IAudioDataAccessor)def __init__(self, context):self._filecontent = context The first lines are the boilerplate part. The adapter class implements the interface the adapter provides. In the constructor, we get the context of the adapter and save it in the _filecontent variable of the instance. @propertydef audio_type(self):return 'FLAC'@propertydef _audio(self):return IAudio(self._filecontent)@propertydef _audio_data(self):annotations = IAnnotations(self._filecontent)return annotations.get(self._audio.ANNO_KEY, None) The audio_type property is just for information purposes and required by the interface. It is displayed in the audio view. The _audio property is a shortcut for accessing the IAudio adapter for the context. The audio_data property is a shortcut for accessing the metadata annotated to the context. def load(self, filename):flacfile = openaudio(filename)self._audio_data['title'] = _safe(flacfile.get('title', ''))self._audio_data['artist'] = _safe(flacfile.get('artist', ''))self._audio_data['album'] = _safe(flacfile.get('album', ''))self._audio_data['year'] = _safe(flacfile.get('date', ''))self._audio_data['idtrack'] = _safe(flacfile.get('tracknumber', ''))self._audio_data['genre'] = _safe(flacfile.get('genre', ''))self._audio_data['comment'] = _safe(flacfile.get('description', ''))self._audio_data['bit_rate'] = long(flacfile.info.bits_per_sample)self._audio_data['length'] = long(flacfile.info.length)self._audio_data['frequency'] = long(flacfile.info.sample_rate) The load method is required by the IAudioDataAccessor interface. It fetches the metadata using the mutagen method from the audio file and stores it as an annotation on the context. def store(self, filename):flacfile = openaudio(filename)flacfile['title'] = self._audio.title or u''flacfile['artist'] = self._audio.artist or u''flacfile['album'] = self._audio.album or u''flacfile['date'] = self._audio.year or u''flacfile['tracknumber'] = self._audio.idtrack or u''flacfile.save() The store method is required by the IAudioDataAccessor interface as well and its purpose is to write the metadata from the context annotation back to the audio file. We have covered the following in this article series: Manipulation of audio content stored as File content in Plone The different formats used for the binary storage of audio data Storing and accessing MP3 audio metadata with the ID3 tag format Managing metadata, formats, and playlists with p4a.ploneaudio in Plone Including a custom embedded audio player in Plone Using the Flowplayer product to include an audio player standalone in rich text and as a portlet >> Continue Reading: Using Flowplayer in Plone 3. Further resources on this subject: Plone 3 Multimedia [book] Using Flowplayer in Plone 3 [article] Audio Enhancements with p4a.ploneaudio in Plone 3.3 [article] Red5: A video-on-demand Flash Server [article]   Plone 3.3 Products Development Cookbook [book] Creating a custom type with paster in plone 3 [article] Improving Plone 3 Product Performance [article]   Plone 3 for Education [book] Calendaring with Plone 3 for Education [article] Showcasing Personnel with Faculty/Staff Directory using Plone 3 [article] Plone 3 Themes [article] Blogs and forums using Plone 3 [article]   Plone 3 Theming [book] Creating, Installing and Tweaking your theme using Plone 3 [article] Skinner's Toolkit for Plone 3 Theming (Part 1) [article] Skinner's Toolkit for Plone 3 Theming (Part 2) [article] Add-on Tools and Theming Tips for Plone 3 [article]   Practical Plone 3: A Beginner's Guide to Building Powerful Websites [book] Find and Install Add-Ons that Expand Plone Functionality [article] Structure the Content on your Plone Site [article] Safely manage different vesions of content with plone [article] Creating New Types of Plone Portlets [article] Show Additional Information to Users and Visitors of Your Plone Site [article]
Read more
  • 0
  • 0
  • 1178
Visually different images

article-image-customizing-your-vim-work-area
Packt
14 May 2010
12 min read
Save for later

Customizing Your Vim for work area

Packt
14 May 2010
12 min read
(Read more interesting articles on Hacking Vim 7.2 here.) Work area personalization In this article, we introduce a list of smaller, good-to-know modifications for the editor area in Vim. The idea with these recipes is that they all give you some sort of help or optimization when you use Vim for editing text or code. Adding a more visual cursor Sometimes, you have a lot of syntax coloring in the file you are editing. This can make the task of tracking the cursor really hard. If you could just mark the line the cursor is currently in, then it would be easier to track it. Many have tried to fix this with Vim scripts, but the results have been near useless (mainly due to slowness, which prevented scrolling longer texts at an acceptable speed). Not until version 7 did Vim have a solution for this. But then it came up with not just one, but two possible solutions for cursor tracking. The first one is the cursorline command , which basically marks the entire line with, for example, another background color without breaking the syntax coloring. To turn it on, use the following command: :set cursorline The color it uses is the one defined in the CursorLine color group. You can change this to any color or styling you like, for example: :highlight CursorLine guibg=lightblue ctermbg=lightgray If you are working with a lot of aligned file content (such as tab-separated data), the next solution for cursor tracking comes in handy: :set cursorcolumn This command marks the current column (here the cursor is placed) by coloring the entire column through the entire file, for example. As with the cursor line, you can change the settings for how the cursor column should be marked. The color group to change is named cursorcolumn. Adding both the cursor line and column marking makes the cursor look like a crosshair, thus making it impossible to miss. Even though the cursorline and cursorcolumn functionalities are implemented natively in Vim, it can still give quite a slowdown when scrolling through the file. Adding line numbers Often when compiling and debugging code, you will get error messages stating that the error is in some line. One could, of course, start counting lines from the top to find the line, but Vim has a solution to go directly to some line number. Just execute :XXX where XXX is the line number, and you will be taken to the XXX line. Alternatively, you can go into normal mode (press the Esc key) and then simply use XXXgg or XXXG (again XXX is the line number). Sometimes, however, it is nice to have an indication of the line number right there in the editor, and that's where the following command comes in handy: :set number Now, you get line numbers to the left of each line in the file. By default, the numbers take up four columns of space, three for numbers, and one for spacing. This meansthat the width of the numbers will be the same until you have more than 999 lines. If you get above this number of lines, an extra column will be added and the content will be moved to the right. Of course, you can change the default number of columns used for the line numbers. This can be achieved by changing the following property: :set numberwidth=XXX Replace XXX with the number of columns that you want. Even though it would be nice to make the number of columns higher in order to get more spacing between code and line numbers, this is not achievable with the numberwidth property. This is because the line numbers will be right-aligned within the columns. In the following figure, you can see how line numbers are shown as right-aligne when a higher number of columns are set in numberwidth: You can change the styling of the line numbers and the columns they are in by making changes to the LineNr color group. Spell checking your language We all know it! Even if we are really good spellers, it still happens from time to time that we misspell a word or hit the wrong keys. In the past, you had to run your texts (that you had written in Vim) through some sort of spell checker such as Aspell or Ispell . This was a tiresome process that could only be performed as a final task, unless you wanted to do it over and over again. With version 7 of Vim, this troublesome way of spell checking is over. Now, Vim has got a built-in spell checker with support for more than 50 languages from around the world. The new spell checker marks the wrongly written words as you type them in, so you know right away that there is an error. The command to execute to turn on this helpful spell checker feature is: :set spell This turns on the spell checker with the default language (English). If you don't use English much and would prefer to use another language in the spell checker, then there is no problem changing this. Just add the code of the language you would like to use to the spelllang property . For example: :set spelllang=de Here, the language is set to German (Deutsch) as the spell checker language of choice. The language name can be written in several different formats. American English, for example, can be written as: en_us us American Names can even be an industry-related name such as medical. If Vim does not recognize the language name, Vim will highlight it when you execute the property-setting command. If you change the spelllang setting to a language not already installed, then Vim will ask you if it should try to automatically retrieve it from the Vim homepage. Personally, I tend to work in several different languages in Vim, and I really don't want to tell Vim all the time which language I am using right now. Vim has a solution for this. By appending more language codes to the spelllang property (separated by commas), you can tell Vim to check the spelling in more than one language. :set spelllang=en,da,de,it Vim will then take the languages from the start to the end, and check if the words match any word in one of these languages. If they do, then they are not marked as a spelling error. Of course, this means that you can have a word spelled wrong in the language you are using but spelled correctly in another language, thereby introducing a hidden spelling error. You can find language packages for a lot of languages at the Vim FTP site: ftp://ftp.vim.org/pub/vim/runtime/spell. Spelling errors are marked differently in Vim and Gvim. In regular Vim, the misspelled word is marked with the SpellBad color group (normally, white on red). In Gvim, the misspelled word is marked with a red curvy line underneath the word. This can, of course, be changed by changing the settings of the color group. Whenever you encounter a misspelled word, you can ask Vim to suggest better ways to spell the word. This is simply done by placing the cursor over the word, going into the normal mode (press Esc), and then pressing Z + =. If possible, Vim will give you a list of good guesses for the word you were actually trying to write. In front of each suggestion is a number. Press the number you find in front of the right spelling (of the word you wanted) or press Enter if the word is not there. Often Vim gives you a long list of alternatives for your misspelled word, but unless you have spelled the word completely wrong, chances are that the correct word is within the top five of the alternatives. If this is the case, and you don't want to look through the entire list of alternatives, then you can limit the output with the following command: :set spellsuggest=X Set X to the number of alternative ways of spelling you want Vim to suggest. Adding helpful tool tips In the Modifying tabs recipe, we learned about how to use tool tips to store more information using less space in the tabs in Gvim. To build on top of that same idea with this recipe, we move on and use tool tips in other places in the editor. The editing area is the largest part of Vim. So, why not try to add some extra information to the contents of this area by using tool tips? In Vim, tool tips for the editing area are called balloons and they are only shown when the cursor is hovering over one of the characters. The commands you will need to know in order to use the balloons are: The first command is the one you will use to actually turn on this functionality in Vim. :set ballooneval The second command tells Vim how long it should wait before showing the tool tip/balloon (the delay is in milliseconds and as a default is set to 600). :set balloondelay=400 The last command is the one that actually sets the string that Vim will show in the balloon. :set ballonexpr="textstring" This can either be a static text string or the return of some function. In order to have access to information about the place where you are hovering over a character in the editor, Vim provides access to a list of variables holding such information: abc<space>and abc<enter> Both expand 123abc<space> Will not expand as the abbreviation is part of a word abcd<space> Will not expand because there are letters after the abbreviation abc Will not expand until another special letter is pressed So with these variables in hand, let's look at some examples. Example 1: The first example is based on one from the Vim help system. It shows how to make a simple function that will show the information from all the available variables. function! SimpleBalloon() return 'Cursor is at line/column: ' . v:beval_lnum . '/' . v:beval_col . ' in file ' . bufname(v:beval_bufnr) . '. Word under cursor is: "' . v:beval_text . '"' endfunction set balloonexpr=SimpleBalloon() set balloonevalcode 59 The result will look similar to the following screenshot: Example 2: Let's look at a more advanced example that explores the use of balloons for specific areas in editing. In this example, we will put together a function that gives us great information balloons for two areas at the same time: Misspelled words: The balloon gives ideas for alternative words Folded text: The balloon gives a preview of what's in the fold So, let's take a look at what the function should look for, to detect if the cursor is hovering over either a misspelled word or a fold line (a single line representing multiple lines folded behind it). In order to detect if a word is misspelled, the spell check would need to be turned on: :set spell If it is on, then calling the built-in spell checker function—spellsuggest()—would return alternative words if the hovered word was misspelled. So, to see if a word is misspelled, just check if the spellsuggest() returns anything. There is, however, a small catch. spellsuggest() also returns alternative, similar words if the word is not misspelled. To get around this, another function has to be used on the input word before putting it into the spellsuggest() function . This extra function is the spellbadword(). This basically moves the cursor to the first misspelled word in the sentence that it gets as input, and then returns the word. We just input a single word and if it is not misspelled, then the function cannot return any words. Putting no word into spellsuggest() results in getting nothing back, so we can now check if a word is misspelled or not. It is even simpler to check if a word is in a line, in a fold. You simply have to call the foldclosed()function on the line number of the line over which the cursor is hovering (remember v:beval_lnum ?), and it will return the number of the first line in the current fold; if not in a fold, then it returns -1. In other words, if foldclosed(v:beval_lnum) returns anything but -1 and 0, we are in a fold. Putting all of this detection together and adding functionality to construct the balloon text ends up as the following function: function! FoldSpellBalloon() let foldStart = foldclosed(v:beval_lnum ) let foldEnd = foldclosedend(v:beval_lnum) let lines = [] " Detect if we are in a fold if foldStart < 0 " Detect if we are on a misspelled word let lines = spellsuggest( spellbadword(v:beval_text)[ 0 ], 5, 0 ) else " we are in a fold let numLines = foldEnd - foldStart + 1 " if we have too many lines in fold, show only the first 14 " and the last 14 lines if ( numLines > 31 ) let lines = getline( foldStart, foldStart + 14 ) let lines += [ '-- Snipped ' . ( numLines - 30 ) . ' lines --' ] let lines += getline( foldEnd - 14, foldEnd ) else "less than 30 lines, lets show all of them let lines = getline( foldStart, foldEnd ) endif endif " return result return join( lines, has( "balloon_multiline" ) ? "n" : " " ) endfunction set balloonexpr=FoldSpellBalloon() set ballooneval The result is some really helpful balloons in the editing area of Vim that can improve your work cycle tremendously. The following screenshot shows how the information balloon could look when it is used to preview a folded range of lines from a file: Instead, if the balloon is used on a misspelled word, it will look like the following screenshot: In Production Boosters, you can learn more about how to use folding of lines to boost productivity in Vim.
Read more
  • 0
  • 0
  • 3016

article-image-personalizing-vim
Packt
14 May 2010
12 min read
Save for later

Personalizing Vim

Packt
14 May 2010
12 min read
(Read more interesting articles on Hacking Vim 7.2 here.) Some of these tasks contain more than one recipe because there are different aspects for personalizing Vim for that particular task. It is you, the reader, who decides which recipes (or parts of it) you would like to read and use. Before we start working with Vim, there are some things that you need to know about your Vim installation, such as where to find the configuration files. Where are the configuration files? When working with Vim, you need to know a range of different configuration files. The location of these files is dependent on where you have installed Vim and the operating system that you are using. In general, there are three configuration files that you must know where to find: vimrc gvimrc exrc The vimrc file is the main configuration file for Vim. It exists in two versions—global and personal. The global vimrc file is placed in the folder where all of your Vim system files are installed. You can find out the location of this folder by opening Vim and executing the following command in normal mode: :echo $VIM The examples could be: Linux: /usr/share/vim/vimrc Windows: c:program filesvimvimrc The personal vimrc file is placed in your home directory. The location of the home directory is dependent on your operating system. Vim was originally meant for Unixes, so the personal vimrc file is set to be hidden by adding a dot as the first character in the filename. This normally hides files on Unix, but not on Microsoft Windows. Instead, the vimrc file is prepended with an underscore on these systems. So, examples would be: Linux: /home/kim/.vimrc Windows: c:documents and settingskim_vimrc Whatever you change in the personal vimrc file will overrule any previous setting made in the global vimrc file. This way you can modify the entire configuration without having to ever have access to the global vimrc file. You can find out what Vim considers as the home directory on your system by executing the following command in normal mode: :echo $HOME Another way of finding out exactly which vimrc file you use as your personal file is by executing the following command in the normal mode: :echo $MYVIMRC The vimrc file contains ex (vi predecessor) commands, one on each line, and is the default place to add modifications to the Vim setup. In the rest of the article, this file is just called vimrc. Your vimrc can use other files as an external source for configurations. In the vimrc file, you use the source command like this: source /path/to/external/file Use this to keep the vimrc file clean, and your settings more structured. (Learn more about how to keep your vimrc clean in Appendix B, Vim Configuration Alternatives). The gvimrc file is a configuration file specifically for Gvim. It resembles the vimrc file previously described, and is placed in the same location as a personal version as well as a global version. For example: Linux: /home/kim/.gvimrc and /usr/share/vim/gvimrc Windows: c:documents and settingskim_gvimrc and c:program filesvimgvimrc This file is used for GUI-specific settings that only Gvim will be able to use. In the rest of the article, this file is called gvimrc. The gvimrc file does not replace the vimrc file, but is simply used for configurationsthat only apply to the GUI version of Vim. In other words, there is no need to haveyour configurations duplicated in both the vimrc file and the gvimrc file. The exrc file is a configuration file that is only used for backwards compatibility with the old vi / ex editor. It is placed at the same location (both global and local) as vimrc, and is used the same way. However, it is hardly used anymore except if you want to use Vim in a vi-compatible mode. Changing the fonts In regular Vim, there is not much to do when it comes to changing the font because the font follows one of the terminals. In Gvim, however, you are given the ability to change the font as much as you like. The main command for changing the font in Linux is: :set guifont=Courier 14 Here, Courier can be exchanged with the name of any font that you have, and 14 with any font size you like (size in points—pt). For changing the font in Windows, use the following command: :set guifont=Courier:14 If you are not sure about whether a particular font is available on the computer or not, you can add another font at the end of the command by adding a comma between the two fonts. For example: :set guifont=Courier New 12, Arial 10 If the font name contains a whitespace or a comma, you will need to escape it with a backslash. For example: :set guifont=Courier New 12 This command sets the font to Courier New size 12, but only for this session. If you want to have this font every time you edit a file, the same command has to be added to your gvimrc file (without the : in front of set). In Gvim on Windows, Linux (using GTK+), Mac OS, or Photon, you can get a font selection window shown if you use this command: :set guifont=*. If you tend to use a lot of different fonts depending on what you are currently working with (code, text, logfiles, and so on.), you can set up Vim to use the correct font according to the file type. For example, if you want to set the font to Arial size 12 every time a normal text file (.txt) is opened, this can be achieved by adding the following line to your vimrc file: autocmd BufEnter *.txt set guifont=Arial 12 The window of Gvim will resize itself every time the font is changed. This means, if you use a smaller font, you will also (as a default) have a smaller window. You will notice this right away if you add several different file type commands like the one previously mentioned, and then open some files of different types. Whenever you switch to a buffer with another file type, the font will change, and hence the window size too. You can find more information about changing fonts in the Vim help system under Help | guifont. Changing color scheme Often, when working in a console environment, you only have a black background and white text in the foreground. This is, however, both dull and dark to look at. Some colors would be desirable. As a default, you have the same colors in the console Vim as in the console you opened it from. However, Vim has given its users the opportunity to change the colors it uses. This is mostly done with a color scheme file. These files are usually placed in a directory called colors wherever you have installed Vim. You can easily change the installed color schemes with the command: :colorscheme mycolors Here, mycolors is the name of one of the installed color schemes. If you don't know the names of the installed color schemes, you can place the cursor after writing: :colorscheme Now, you can browse through the names by pressing the Tab key. When you find the color scheme you want, you can press the Enter key to apply it. The color scheme not only applies to the foreground and background color, but also to the way code is highlighted, how errors are marked, and other visual markings in the text. You will find that some color schemes are very alike and only minor things have changed. The reason for this is that the color schemes are user supplied. If some user did not like one of the color settings in a scheme, he or she could just change that single setting and re-release the color scheme under a different name. Play around with the different color schemes and find the one you like. Now, test it in the situations where you would normally use it and see if you still like all the color settings. While learning Basic Vim Scripting, we will get back to how you can change a color scheme to fit your needs perfectly. Personal highlighting In Vim, the feature of highlighting things is called matching. With matching, you can make Vim mark almost any combination of letters, words, numbers, sentences, and lines. You can even select how it should be marked (errors in red, important words in green, and so on). Matching is done with the following command: :match Group /pattern/ The command has two arguments. The first one is the name of the color group that you will use in the highlight. Compared to a color scheme, which affects the entire color setup, a color group is a rather small combination of background (or foreground) colors that you can use for things such as matches. When Vim is started, a wide range of color groups are set to default colors, depending on the color scheme you have selected. To see a complete list of color groups, use the command: :so $VIMRUNTIME/syntax/hitest.vim. The second argument is the actual pattern you want to match. This pattern is a regular expression and can vary from being very simple to extremely complex, depending on what you want to match. A simple example of the match command in use would be: :match ErrorMsg /^Error/ This command looks for the word Error (marked with a ^) at the beginning of all lines. If a match is found, it will be marked with the colors in the ErrorMsg color group (typically white text on red background). If you don't like any of the available color groups, you can always define your own. The command to do this is as follows: :highlight MyGroup ctermbg=red guibg=red gctermfg=yellowguifg=yellow term=bold This command creates a color group called MyGroup with a red background and yellow text, in both the console (Vim) and the GUI (Gvim). You can change the following options according to your preferences: ctermb Background color in console guibg Background color in Gvim ctermf Text color in console guifg Text color in Gvim gui Font formatting in Gvim term Font formatting in console (for example, bold) If you use the name of an existing color group, you will alter that group for the rest of the session. When using the match command, the given pattern will be matched until you perform a new match or execute the following command: :match NONE The match command can only match one pattern at a time, so Vim has provided you with two extra commands to match up to three patterns at a time. The commands are easy to remember because their names resemble those of the match command: :2match:3match You might wonder what all this matching is good for, as it can often seem quite useless. Here are a few examples to show the strength of matching. Example 1: Mark color characters after a certain column In mails, it is a common rule that you do not write lines more than 74 characters (a rule that also applies to some older programming languages such as, Fortran-77). In a case like this, it would be nice if Vim could warn you when you reached this specific number of characters. This can simply be done with the following command: :match ErrorMsg /%>73v.+/ Here, every character after the 73rd character will be marked as an error. This match is a regular expression that when broken down consists of: %> Match after column with the number right after this 73 The column number V Tells that it should work on virtual columns only .+ Match one or more of any character Example 2: Mark tabs not used for indentation in code When coding, it is generally a good rule of thumb to use tabs only to indent code, and not anywhere else. However, for some it can be hard to obey this rule. Now, with the help of a simple match command, this can easily be prevented. The following command will mark any tabs that are not at the beginning of the line (indentation) as an error: :match errorMsg /[^t]zst+/ Now, you can check if you have forgotten the rule and used the Tab key inside the code. Broken down, the match consists of the following parts: [^ Begin a group of characters that should not be matched t The tab character ] End of the character group zs A zero-width match that places the 'matching' at the beginning of the line ignoring any whitespaces t+ One or more tabs in a row This command says: Don't match all the tab characters; match only the ones that are not used at the beginning of the line (ignoring any whitespaces around it). If instead of using tabs you want to use the space character for indentation, you can change the command to: :match errorMsg /[t]/ This command just says: Match all the tab characters. Example 3: Preventing errors caused by IP addresses If you write a lot of IP addresses in your text, sometimes you tend to enter a wrong value in one (such as 123.123.123.256). To prevent this kind of an error, you can add the following match to your vimrc file: match errorMsg /(2[5][6-9]|2[6-9][0-9]|[3-9][0-9][0-9])[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}|[0-9]{1,3}[.](2[5][6-9]|2[6-9][0-9]| [3-9][0-9][0-9])[.][0-9]{1,3}[.][0-9]{1,3}|[0-9]{1,3}[.][0-9]{1,3}[.](2[5] [6-9]|2[6-9][0-9]|[3-9][0-9][0-9])[.][0-9]{1,3}|[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.](2[5][6-9]|2[6-9][0-9]|[3-9][0-9][0-9])/ Even though this seems a bit too complex for solving a small possible error, you have to remember that even if it helps you just once, it is worth adding. If you want to match valid IP addresses, you can use this, which is a much simpler command: match todo /((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).) {3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/
Read more
  • 0
  • 0
  • 5425

article-image-manage-your-money-simple-invoices
Packt
13 May 2010
6 min read
Save for later

Manage Your Money with Simple Invoices

Packt
13 May 2010
6 min read
As a freelancer I have one primitive motive. I want to do work and get paid. Getting paid means I need to generate invoices and keep track of them. I've tried to manage my invoices via spreadsheets and documents, but keeping track of my payments in a series of disconnected files is a fragile and inefficient process. Simple Invoices provides a solution to this. Simple Invoices is a relatively young project, and working with it requires that you're willing to do some manual configurations and tolerate the occasional problem. To work with and install the application, you need to be familiar with running a web server on OS X, Windows, or Linux. The next section, Web Server Required provides some out of the box server packages that allow you to run a server environment on your personal computer. It's point and click easy and perfect for an individual user. Not up for running a web server, but still need to find a reliable invoicing application? No problem. Visit www.simpleinvoices.com for a list of hosted solutions. Let's get started. Web Server Required Simple Invoices is a web application that requires Apache, PHP, and MySQL to function. Even if you're not a system administrator, you can still run a web server on your computer, regardless of your operating system. Windows users can get the required software by installing WAMP from www.wampserver.com. OS X users can install MAMP from www.mamp.info. Linux users can install Apache, MySql, and PHP5 using their distribution's software repositories. The database administrative tool, phpMyAdmin makes managing the MySQL database intuitive. Both the WAMP and MAMP installers contain phpMyAdmin, and we'll use it to setup our databases. Take a moment to setup your web server before continuing with the Simple Invoices installation. Install Simple Invoices Our first step will be to prepare the MySQL database. Open a web browser and navigate to http://localhost/phpmyadmin. Replace localhost with the actual server address. A login screen will display and will prompt you for a user name and password. Enter the the root login information for your MySQL install. MAMP users might try root for both the user name and password. WAMP users might try root with no password. If you plan on keeping your WAMP or MAMP servers installed, setting new root passwords for your MySQL database is a good idea, even if you do not allow external connections to your server. After you log in to phpMyAdmin, you will see a list of databases on the left sidebar; the main content window displays a set of tabs, including Databases, SQL, and Status. Let's create the database. Click on the Privileges tab to display a list of all users and associated access permissions. Find the Add a New User link and click on it. The Add New User page displays. Complete the following fields: User Name: enter simpleinvoices Host: select Local Password: specify a password for the user; then retype it in the field provided Database for User: select the Create database with same name and grant all privileges option Scroll to the bottom of the page and click the Go button. This procedure creates the database user and the database at the same time. If you wanted to use a database name that was different than the user name, then could have selected None for the Database for user configuration and added the database manually via the Databases tab in phpMyAdmin. If you prefer to work with MySQL directly, the SQL code for the steps we just ran is (the *** in the first line is the password): CREATE USER 'simpleinvoices'@'localhost' IDENTIFIED BY '***'; GRANT USAGE ON *.* TO 'simpleinvoices'@'localhost' IDENTIFIED BY '***' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0;CREATE DATABASE IF NOT EXISTS `simpleinvoices`; GRANT ALL PRIVILEGES ON `simpleinvoices`.* TO 'simpleinvoices'@'localhost'; Now that the database is setup, let's download the stable version of Simple Invoices by visiting www.simpleinvoices.org and following the Download link. The versions are identified by the year and version. At the time of this writing, the stable version is 2010.1. Unzip the Simple Invoices download file into a subdirectory on your web server. Because I like to install a lot of software, I like to keep the application name in my directory structure, so my example installation installs to a directory named simpleinvoices. That makes my installation available at http://localhost/simpleinvoices. Pick a directory path that makes sense for you. Not sure where the root of your web server resides on your server? Here are some of the default locations for the various server environments: WAMP – C:wampwww MAMP – /Applications/MAMP/htdocs Linux – /var/www Linux users will need to set the ownership of the tmp directory to the web user and make the tmp directory writable. For an Ubuntu system, the appropriate commands are: chown -R www-data tmpchmod -R 775 tmp The command syntax assumes we're working from the Simple Invoices installation directory on the web server. The web user on Ubuntu and other Debian-based systems is www-data. The -R option in both commands applies the permissions to all sub-directories and files. With the chmod command, you are granting write access to the web user. If you have problems or feel like being less secure, you can reduce this step down to one command: chmod -R 777 tmp. We're almost ready to open the Simple Invoices installer, but before we go to the web browser, we need to define the database connections in the config/config.ini file. At a minimum, we need to specify the database.params.username and database.params.password with the values we used to setup the database. If you skip this step and try to open Simple Invoices in your web browser, you will receive an error message indicating that your config.ini settings are incorrect. The following screenshot shows the relevant settings in confi.ini. Now, we're ready to start Simple Invoices and step through the graphical installer. Open a web browser and navigate to your installation (for example: http://localhost/simpleinvoices). Step 1: Install Database will display in the browser. Review the database connection information and click the Install Database button. Step 2: Import essential data displays. Click the Install Essential Data button to advance the installation. Step 3: Import sample data displays. We can choose to import sample data or start using the application. The sample data contains a few example billers, customers, and invoices. We're going to set all that up from scratch, so I recommend you click the Start using Simple Invoices button. At this point the Simple Invoices dashboard displays with a yellow note that instructs us to configure a biller, a customer, and a product before we create our first invoice. See the following screenshot. You might notice that the default access to Simple Invoices is not protected by a username and password. We can force authentication by adding a user and password via the People > Users screen. Then set the authentication.enabled field in config.ini equal to true.
Read more
  • 0
  • 0
  • 2522
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €14.99/month. Cancel anytime
article-image-data-binding-expression-blend-4-silverlight-4
Packt
13 May 2010
7 min read
Save for later

Data binding from Expression Blend 4 in Silverlight 4

Packt
13 May 2010
7 min read
Using the different modes of data binding to allow persisting data Until now, the data has flowed from the source to the target (the UI controls). However, it can also flow in the opposite direction, that is, from the target towards the source. This way, not only can data binding help us in displaying data, but also in persisting data. The direction of the flow of data in a data binding scenario is controlled by the Mode property of the Binding. In this recipe, we'll look at an example that uses all the Mode options and in one go, we'll push the data that we enter ourselves to the source. Getting ready This recipe builds on the code that was created in the previous recipes, so if you're following along, you can keep using that codebase. You can also follow this recipe from the provided start solution. It can be found in the Chapter02/SilverlightBanking_Binding_ Modes_Starter folder in the code bundle that is available on the Packt website. The Chapter02/SilverlightBanking_Binding_Modes_Completed folder contains the finished application of this recipe. How to do it... In this recipe, we'll build the "edit details" window of the Owner class. On this window, part of the data is editable, while some isn't. The editable data will be bound using a TwoWay binding, whereas the non-editable data is bound using a OneTime binding. The Current balance of the account is also shown—which uses the automatic synchronization—based on the INotifyPropertyChanged interface implementation. This is achieved using OneWay binding. The following is a screenshot of the details screen: Let's go through the required steps to work with the different binding modes: Add a new Silverlight child window called OwnerDetailsEdit.xaml to the Silverlight project. In the code-behind of this window, change the default constructor—so that it accepts an instance of the Owner class—as shown in the following code: private Owner owner; public OwnerDetailsEdit(Owner owner) { InitializeComponent(); this.owner = owner; } In MainPage.xaml, add a Click event on the OwnerDetailsEditButton: <Button x_Name="OwnerDetailsEditButton" Click="OwnerDetailsEditButton_Click" > In the event handler, add the following code, which will create a new instance of the OwnerDetailsEdit window, passing in the created Owner instance: private void OwnerDetailsEditButton_Click(object sender, RoutedEventArgs e) { OwnerDetailsEdit ownerDetailsEdit = new OwnerDetailsEdit(owner); ownerDetailsEdit.Show(); } The XAML of the OwnerDetailsEdit is pretty simple. Take a look at the completed solution (Chapter02/SilverlightBanking_Binding_Modes_Completed)for a complete listing. Don't forget to set the passed Owner instance as the DataContext for the OwnerDetailsGrid. This is shown in the following code: OwnerDetailsGrid.DataContext = owner; For the OneWay and TwoWay bindings to work, the object to which we are binding should be an instance of a class that implements the INotifyPropertyChanged interface. In our case, we are binding an Owner instance. This instance implements the interface correctly. The following code illustrates this: public class Owner : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; ... } Some of the data may not be updated on this screen and it will never change. For this type of binding, the Mode can be set to OneTime. This is the case for the OwnerId field. The users should neither be able to change their ID nor should the value of this field change in the background, thereby requiring an update in the UI. The following is the XAML code for this binding: <TextBlock x_Name="OwnerIdValueTextBlock" Text="{Binding OwnerId, Mode=OneTime}" > </TextBlock> The CurrentBalance TextBlock at the bottom does not need to be editable by the user (allowing a user to change his or her account balance might not be benefi cial for the bank), but it does need to change when the source changes. This is the automatic synchronization working for us and it is achieved by setting the Binding to Mode=OneWay. This is shown in the following code: <TextBlock x_Name="CurrentBalanceValueTextBlock" Text="{Binding CurrentBalance, Mode=OneWay}" > </TextBlock> The final option for the Mode property is TwoWay. TwoWay bindings allow us to persist data by pushing data from the UI control to the source object. In this case, all other fields can be updated by the user. When we enter a new value, the bound Owner instance is changed. TwoWay bindings are illustrated using the following code: <TextBox x_Name="FirstNameValueTextBlock" Text="{Binding FirstName, Mode=TwoWay}" > </TextBox> We've applied all the different binding modes at this point. Notice that when you change the values in the pop-up window, the details on the left of the screen are also updated. This is because all controls are in the background bound to the same source object as shown in the following screenshot: How it works... When we looked at the basics of data binding, we saw that a binding always occurs between a source and a target. The first one is normally an in-memory object, but it can also be a UI control. The second one will always be a UI control. Normally, data flows from source to target. However, using the Mode property, we have the option to control this. A OneTime binding should be the default for data that does not change when displayed to the user. When using this mode, the data flows from source to target. The target receives the value initially during loading and the data displayed in the target will never change. Quite logically, even if a OneTime binding is used for a TextBox, changes done to the data by the user will not flow back to the source. IDs are a good example of using OneTime bindings. Also, when building a catalogue application, OneTime bindings can be used, as we won't change the price of the items that are displayed to the user (or should we...?). We should use a OneWay binding for binding scenarios in which we want an up-to-date display of data. Data will flow from source to target here also, but every change in the values of the source properties will propagate to a change of the displayed values. Think of a stock market application where updates are happening every second. We need to push the updates to the UI of the application. The TwoWay bindings can help in persisting data. The data can now flow from source to target, and vice versa. Initially, the values of the source properties will be loaded in the properties of the controls. When we interact with these values (type in a textbox, drag a slider, and so on), these updates are pushed back to the source object. If needed, conversions can be done in both directions. There is one important requirement for the OneWay and TwoWay bindings. If we want to display up-to-date values, then the INotifyPropertyChanged interface should be implemented. The OneTime and OneWay bindings would have the same effect, even if this interface is not implemented on the source. The TwoWay bindings would still send the updated values if the interface was not implemented; however, they wouldn't notify about the changed values. It can be considered as a good practice to implement the interface, unless there is no chance that the updates of the data would be displayed somewhere in the application. The overhead created by the implementation is minimal. There's more... Another option in the binding is the UpdateSourceTrigger. It allows us to specify when a TwoWay binding will push the data to the source. By default, this is determined by the control. For a TextBox, this is done on the LostFocus event; and for most other controls, it's done on the PropertyChanged event. The value can also be set to Explicit. This means that we can manually trigger the update of the source. BindingExpression expression = this.FirstNameValueTextBlock. GetBindingExpression(TextBox.TextProperty); expression.UpdateSource(); See also Changing the values that flow between source and target can be done using converters. Data binding from Expression Blend 4 While creating data bindings is probably a task mainly reserved for the developer(s) in the team, Blend 4—the design tool for Silverlight applications—also has strong support for creating and using bindings. In this recipe, we'll build a small data-driven application that uses data binding. We won't manually create the data binding expressions; we'll use Blend 4 for this task.
Read more
  • 0
  • 0
  • 1534

article-image-creating-customizing-and-assigning-portlets-automatically-plone-33
Packt
12 May 2010
5 min read
Save for later

Creating, Customizing, and Assigning Portlets Automatically for Plone 3.3

Packt
12 May 2010
5 min read
(For more resources on Plone, see here.) Introduction One of the major changes from Plone 2.5 to Plone 3.0 was the complete refactoring of its portlets engine. In Plone 2.5, left and right side portlets were managed from Zope Management Interface (ZMI) by setting two special properties: left_slots and right_slots. This was not so hard but was cumbersome. Any TALES path expression—ZPT macros typically—could be manually inserted in the above two properties and would be displayed as a bit of HTML to the final user. The major drawback for site managers with the old-style approach was not just the uncomfortable way of setting which portlets to display, but the lack of any configuration options for them. For example, if we wanted to present the latest published news items, we wouldn't have any means of telling how many of them to show, unless the portlet itself were intelligent enough to get that value from some other contextual property. But again, we were still stuck in the ZMI. Fortunately, this has changed enormously in Plone 3.x: Portlets can now be configured and their settings are mantained in ZODB. Portlets are now managed via a user-friendly, Plone-like interface. Just click on the Manage portlets link below each of the portlets columns (see the following screenshot). In the above screen, if we click on the News portlet link, we are presented with a special configuration form to choose the Number of items to display and the Workflow state(s) we want to consider when showing news items. If you have read previous chapters, you might be correctly guessing that Zope 3 components (zope.formlib mainly) are behind the portlets configuration forms. In the next sections, we'll look again at the customer's requirements: Advertisement banners will be located in several areas of every page Advertisement banners may vary according to the section of the website Creating a portlet package Once again, paster comes to the rescue. As in Creating a product package structure and Creating an Archetypes product with paster, we will use the paster command here to create all the necessary boilerplate (and even more) to get a fully working portlet. Getting ready As we are still at the development stage, we should run the following commands in our buildout's src folder: cd ./src How to do it... Run the paster command: We are going to create a new egg called pox.portlet.banner. The pox prefix is from PloneOpenX (the website we are working on) and it will be the namespace of our product. Portlets eggs usually have a nested portlet namespace as in plone.portlet.collection or plone.portlet.static. We have chosen the pox main namespace as in the previous eggs we have created, and the banner suffix corresponds to the portlet name. For more information about eggs and packages names read http://www.martinaspeli.net/articles/the-naming-ofthings-package-names-and-namespaces.If you want to add portlets to an existing package instead of creating a new one, the steps covered in this chapter should tell you all you need to know (the use of paster addcontent portlet local command will be of great help). In your src folder, run the following command: paster create -t plone3_portlet This paster command creates a product using the plone3_portlet template. When run, it will output some informative text, and then a short wizard will be started to select options for the package: Option Value Enter project name pox.portlet.banner Expert Mode? easy Version 1.0 Description Portlet to show banners Portlet Name Banner portlet Portlet Type BannerPortlet After selecting the last option, you'll get an output like this (a little longer actually): Creating directory ./pox.portlet.banner ... Recursing into +namespace_package+ Recursing into +namespace_package2+ Recursing into +package+ Recursing into profiles Creating ./pox.portlet.banner/pox/portlet/banner/profiles/ Recursing into default Creating ./pox.portlet.banner/pox/portlet/banner/profiles/default/ Copying metadata.xml_tmpl to ./pox.portlet.banner/pox/portlet/banner/profiles/default/metadata.xml Copying portlets.xml_tmpl to ./pox.portlet.banner/pox/portlet/banner/profiles/default/portlets.xml This tells us that even the GenericSetup extension profile has also been created by paster. This means that we can install the new Banner portlet product (as entered in the portlet_name option above). Install the product: To tell our Zope instance about the new product, we must update the buildout.cfg file as follows: [buildout]...eggs =... pox.portlet.banner...develop = src/pox.portlet.banner We can automatically install the product during buildout. Add a pox.portlet.banner line inside the products parameter of the [plonesite] part: [plonesite]recipe = collective.recipe.plonesite...products =... pox.portlet.banner Build your instance and, if you want to, launch it to see the new empty Banner portlet: ./bin/buildout./bin/instance fg Check the new portlet: After implementing the changes above, if you click on the Manage portlets link in the site's home page (or anywhere in the Plone site), you will see a new Banner portlet option in the drop-down menu. A new box in the portlet column will then be shown. The Header/Body text/Footer box shown above matches the template definition in the bannerportlet.pt file the way paster created it.
Read more
  • 0
  • 0
  • 1691

article-image-creating-your-first-complete-moodle-theme
Packt
11 May 2010
11 min read
Save for later

Creating your First Complete Moodle Theme

Packt
11 May 2010
11 min read
So let's crack on... Creating a new theme Finding a base theme to create your Moodle theme on is the first thing that you need to do.There are, however, various ways to do this; you can make a copy of the standard themeand rename it as you did in part of this article, or you can use a parent theme that isalso based on the standard theme. The important point here is that the standard theme that comes with Moodle is the cornerstone of the Moodle theming process. Every other Moodle theme should be based upon this theme, and would normally describe the differences from the standard theme. Although this method does work and is a simple way to get started with Moodle theming, it does cause problems as new features could get added to Moodle that might cause your theme to display or function incorrectly. The standard theme will always be updated before a new release of Moodle is launched. So if you do choose to make a copy of the standard theme and change its styles, it would be best to make sure that you use a parent theme as well. In this way, the parent theme will be your base theme along with the changes that you make to your copy of the standard theme. However, there is another way of creating your first theme, and that is to create a copy of a theme that is very close to the standard theme, such as standardwhite, and use this as your theme. Moodle will then use the standard theme as its base theme and apply any changes that you make to the standardwhite theme on the top (parent). All we are doing is describing the differences between the standard and the standardwhite themes. This is better because Moodle developers will sometimes make changes to the standard theme to be up-to-date with new Moodle features. This means that on each Moodle update, your standard theme, folder will be updated automatically, thus avoiding any nasty display problems being caused by Moodle updates. The way by which you configure Moodle themes is completely up to you. If you see a theme that is nearly what you want and there aren't really many changes needed, then using a parent theme makes sense, as most of the styles that you require have already been written. However, if you want to create a theme that is completely different from any other theme or wish to really get into Moodle theming, then using a copy of one of the standard sheets would be best. So let's get on and see what the differences are when using different theme setups, and see what effect these different methods have on the theming process. Time for action – copying the standard theme Browse to your theme folder in C:Program FilesApache Software FoundationApache 2.2htdocstheme. Copy the standard theme by right-clicking on the theme's folder and choosing Copy. Paste the copied theme into the theme directory (the same directory that you arecurrently in). Rename the copy of standard folder to blackandblue or any other name that you wish to choose (remember not to use capitals or spaces). Open your Moodle site and navigate to Site Administration Appearance | Themes | Theme Selector|, and choose the blackandblue theme that you have just created. Y ou might have noticed that the theme shown in the preceding screenshot has a header that says Black and Blue theme. This is because I have added this to the Full site name in the Front Page settings page. Time for action – setting a parent theme Open your web browser and navigate to your Moodle site and log in as the administrator. Go to Site Administration | Appearance | Themes | Theme Selector and choose your blackandblue theme if it is not already selected. Browse to the root of your blackandblue folder, right-click on the config.php file, and choose Open with | WordPad. You need to make four changes to this file so that you can use this theme and a parent theme while ensuring that you still use the default standard theme as your base. Here are the changes: $THEME->sheets = array('user_styles');$THEME->standardsheets = true;$THEME->parent = 'autumn';$THEME->parentsheets = array('styles'); Let's look at each of these statements, in turn. $THEME->sheets = array('user_styles'); This contains the names of all of the stylesheet files that you want to include in this for your blackandblue theme, namely user_styles. $THEME->standardsheets = true; This parameter is used to include the standard theme's stylesheets. If it is set to True, it will use all of the stylesheets in the standard theme. Alternatively, it can be set as an array in order to load individual stylesheets in whatever order is required. We have set this to True, so we will use all of the stylesheets of the standard theme. $THEME->parent = 'autumn'; This variable can be set to use a theme as the parent theme, which is included before the current theme. This will make it easier to make changes to another theme without having to change the actual files. $THEME->parentsheets = array('styles'); This variable can be used to choose either all of the parent theme's stylesheets or individual files. It has been set to include the styles.css file from the parent theme, namely autumn. Because there is only one stylesheet in the Autumn theme, you can set this variable to True. Either way, you will have the same outcome. Save themeblackandblueconfig.php, and refresh your web browser window. You should see something similar to the following screenshot. Note that your blocks may be different to the ones below, but you can ignore this. What just happened? Okay, so now you have a copy of the standard theme that uses the Autumn theme (by Patrick Malley) as its parent. You might have noticed that the header isn't correct and that the proper Autumn theme header isn't showing. Well, this is because you are essentially using the copy of the standard theme and that the header from this theme is the one that you see above. It's only the CSS files that are included in this hierarchy, so any HTML changes will not be seen until you edit your standard theme's header.html file. Have a go hero – choose another parent theme Go back and have a look through some of the themes on Moodle.org and download one that you like. Add this theme as a parent theme to your blackandblue theme's config.php file, but this time choose which stylesheets you want to use from that theme. The Back to School theme is a good one for this exercise, as its stylesheets are clearly labeled. So you Copying the header and footer files To show that you are using the Autumn theme's CSS files and the standard theme's HTML files, you can just go and copy the header.html and footer.html files from Patrick Malley's Autumn theme and paste them into your blackandblue theme's folder. Don't worry about overwriting your header and footer files, as you can always just copy them again from the ac tual standard theme folder. Time for action – copying the header.html and footer.html files Browse to the Autumn theme's folder and highlight both the header.html and footer.html files by holding down the Ctrl key and clicking on them both. Right-click on the selected files and choose Copy. Browse to your blackandblue theme's folder and right-click and choose Paste. Go back to your browser window and press the F5 button to refresh the page. You will now see the full Autumn theme. What just happened? You have copied the autumn theme's header.html and footer.html files into your blackandblue theme, so you can see the full autumn theme working. You probably will not actually use the header.html and footer.html files that you just copied, as this was just an example of how the Moodle theming process works. So you now have an unmodified copy of the standard theme called blackandblue, which is using the autumn theme as its parent theme. All you need to do now to make changes to this theme is to edit your CSS file in the blackandblue theme folder. Theme folder housework However, there are a couple of things that you need to do first, as you have an exact copy of the standard theme apart from the header.html and footer.html files. This copied folder has files that you do not need, as the only file that you set for your theme to use was the user_styles.css file in the config.php file earlier. This was the first change that you made: $THEME->sheets = array('user_styles'); The user_style.css file does not exist in your blackandblue theme's folder, so you will need to create it. You will also need to delete any other CSS files that are present, as your new blackandblue theme will use only one stylesheet, namely the user_styles.css file that you will be creating in the following sections. Time for action – creating our stylesheet Right-click anywhere in your blackandblue folder and choose New Text Document|. Rename this text document to user_styles.css by right-clicking again and choosing Rename. Time for action – deleting CSS files that we don't need Delete the following CSS files by selecting them and then right-clicking on the selected files and choosing Delete. styles_color.css styles_ie6.css styles_ie6.css styles_ie7.css styles_layout.css styles_moz.css {background: #000000;} What just happened? In the last two tasks, you created an empty CSS file called user_style.css in your blackandblue theme's folder. You then deleted all of the CSS files in your blackandblue theme's folder, as you will no longer need them. Remember, these are just copies of the CSS files in the standard theme folder and you have set your theme to use the standard theme as its base in the blackandblue theme's config.php file. Let's make some changes Now you have set up your theme the way that you want it, that is, you are using your own blackandblue theme by using the standard theme as a base and the Autumn theme as the parent. Move on and make a few changes to your user_style.css file so that you can see what effect this has on your theme, and check that all of your config.php file's settings are correct. Remember that all of the current styles are being inherited from the Autumn theme. Time for action – checking our setup Open up your Moodle site with the current theme (which should be blackandblue but looks like the Autumn theme). Navigate to your blackandblue theme's folder, right-click on the user_style.css file, and choose Open. This file should be completely blank. Type in the following line of CSS for the body element, and then save the fi le: body {background: #000000;} Now refresh your browser window. You will see that the background is now black. Note: When using Firebug to identify styles that are being used, it might not always be obvious where they are or which style is controlling that element of the page. An example of this is the body {background: #000000;}code that we just pasted in our user_style.css file. If we had used Firebug to indentify that style, we would not have found it. Instead, I just took a look at the CSS file from the autumn theme. What I am trying to say here is that there will always be an element of poking around and trial and error. What just happened? All seems fine there, doesn't it? You have added one style declaration to your empty user_style.css file to change the background color, and have checked the changes in your browser. You now know how the parent themes work and know that you only need to copy the styles from Firebug into your user_style.css file and edit the style declarations that need to be changed.
Read more
  • 0
  • 1
  • 3871

article-image-working-dataform-microsoft-silverlight-4
Packt
10 May 2010
9 min read
Save for later

Working with DataForm in Microsoft Silverlight 4

Packt
10 May 2010
9 min read
Displaying and editing an object using the DataForm Letting a user work with groups of related data is a requirement of almost every application. It includes displaying a group of people, editing product details, and so on. These groups of data are generally contained in forms and the Silverlight DataForm (from the Silverlight Toolkit) is just that—a form. In the next few recipes, you'll learn how to work with this DataForm. As of now, let's start off with the basics, that is, displaying and editing the data. Getting ready For this recipe, we're starting with a blank solution, but you do need to install the Silverlight Toolkit as the assemblies containing the DataForm are offered through this. You can download and install it from http://www.codeplex.com/Silverlight/. You can find the completed solution in the Chapter05/Dataform_DisplayAndEdit_Completed folder in the code bundle that is available on the Packt website. How to do it... We're going to create a Person object, which will be displayed through a DataForm. To achieve this, we'll carry out the following steps: Start a new Silverlight solution, name it DataFormExample, and add a reference to System.Windows.Controls.Data.DataForm.Toolkit (from the Silverlight Toolkit). Alternatively, you can drag the DataForm from the Toolbox to the design surface. Open MainPage.xaml and add a namespace import statement at the top of this fi le (in the tag) as shown in the following code. This will allow us to use the DataForm, which resides in the assembly that we've just referenced. Add a DataForm to MainPage.xaml and name it as myDataForm. In the DataForm, set AutoEdit to False and CommandButtonsVisibility to All as shown in the following code: <Grid x_Name="LayoutRoot"> <Grid.RowDefinitions> <RowDefinition Height="40" ></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <TextBlock Text="Working with the DataForm" Margin="10" FontSize="14" > </TextBlock> <df:DataForm x_Name="myDataForm" AutoEdit="False" CommandButtonsVisibility="All" Grid.Row="1" Width="400" Height="300" Margin="10" HorizontalAlignment="Left" VerticalAlignment="Top" > </df:DataForm> </Grid> Add a new class named Person to the Silverlight project having ID, FirstName, LastName, and DateOfBirth as its properties. This class is shown in the following code. We will visualize an instance of the Person class using the DataForm. public class Person { public int ID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public DateTime DateOfBirth { get; set; } } Open MainPage.xaml.cs and add a person property of the Person type to it. Also, create a method named InitializePerson in which we'll initialize this property as shown in the following code: public Person person { get; set; } private void InitializePerson() { person = new Person() { ID = 1, FirstName = "Kevin", LastName = "Dockx", DateOfBirth = new DateTime(1981, 5, 5) }; } Add a call to InitializePerson in the constructor of MainPage.xaml.cs and set the CurrentItem property of the DataForm to a person as shown in the following code: InitializePerson(); myDataForm.CurrentItem = person; You can now build and run your solution. When you do this, you'll see a DataForm that has automatically generated the necessary fields in order to display a person. This can be seen in the following screenshot: How it works... To start off, we needed something to display in our DataForm: a Person entity. This is why we've created the Person class: it will be bound to the DataForm by setting the CurrentItem property to an object of type Person. Doing this will make sure that the DataForm automatically generates the necessary fi elds. It looks at all the public properties of our Person object and generates the correct control depending on the type. A string will be displayed as a TextBox, a Boolean value will be displayed as a CheckBox, and so on. As we have set the CommandButtonsVisibility property on the DataForm to All, we get an Edit icon in the command bar at the top of the DataForm. (Setting AutoEdit to False makes sure that we start in the display mode, rather than the edit mode). When you click on the Edit icon, the DataForm shows the person in the editable mode (using the EditItemTemplate) and an OK button appears. Clicking on the OK button will revert the form to the regular displaying mode. Do keep in mind that the changes you make to the person are persisted immediately in memory (in the case of a TextBox, when it loses focus). If necessary, you can write extra code to persist the Person object from the memory to an underlying datastore by handling the ItemEditEnded event on the DataForm. There's more... At this moment, we've got a DataForm displaying a single item that you can either view or edit. But what if you want to cancel your edit? As of now, the Cancel button appears to be disabled. As the changes you make in the DataForm are immediately persisted to the underlying object in the memory, cancelling the edit would require some extra business logic. Luckily, it's not hard to do. First of all, you'll want to implement the IEditableObject interface on the Person class, which will make sure that cancelling is possible. As a result, the Cancel button will no longer be disabled. The following code is used to implement this: public class Person : IEditableObject { public int ID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public DateTime DateOfBirth { get; set; } public void BeginEdit() {} public void CancelEdit() {} public void EndEdit() {} } This interface exposes three methods: BeginEdit, CancelEdit, and EndEdit. If needed, you can write extra business logic in these methods, which is exactly what we need to do. For most applications, you might want to implement only CancelEdit, which would then refetch the person from the underlying data store. In our example, we're going to solve this problem by using a different approach. (You can use this approach if you haven't got an underlying database from which your data can be refetched, or if you don't want to access the database again.) In the BeginEdit method, we save the current property values of the person. When the edit has been cancelled, we put them back to the way they were before. This is shown in the following code: public void BeginEdit() { // save current values tmpPerson = new Person() { ID = this.ID, FirstName = this.FirstName, LastName = this.LastName, DateOfBirth = this.DateOfBirth }; } public void CancelEdit() { // reset values ID = tmpPerson.ID; FirstName = tmpPerson.FirstName; LastName = tmpPerson.LastName; DateOfBirth = tmpPerson.DateOfBirth; } Now, cancelling an edit is possible and it actually reverts to the previous property values. More on DataForm behavior The DataForm exposes various events such as BeginningEdit (when you begin to edit an item), EditEnding (occurs just before an item is saved), and EditEnded (occurs after an item has been saved). It also exposes properties that you can use to defi ne how the DataForm behaves. Validating a DataForm or a DataGrid As you might have noticed, the DataForm includes validation on your fields automatically. For example, try inputting a string value into the ID field. You'll see that an error message appears. This is beyond the scope of this recipe, but more on this will be discussed in the Validating the DataForm recipe. Managing the editing of an object on different levels There are different levels of managing the editing of an object. You can manage this on the control level itself by handling events such as BeginningEdit or ItemEditEnded in the DataForm. Besides that, you can also handle editing on a business level by implementing the IEditableObject interface and providing custom code for the BeginEdit, CancelEdit, or EndEdit methods in the class itself. Depending on the requirements of your application, you can use either of the levels or even both together. See also In this recipe, we've seen how the DataForm is created automatically. For most applications, you require more control over how your fi elds, for example, are displayed. The DataForm is highly customizable, both on a template level (through template customization) and on how the data is generated (through data annotations). If you want to learn about using the DataForm to display or edit a list of items rather than just one, have a look at the next recipe, Displaying and editing a collection using the DataForm. Displaying and editing a collection using the DataForm In the previous recipe, you learned how to work with the basic features of the DataForm. You can now visualize and edit an entity. But in most applications, this isn't enough. Often, you'll want to have an application that shows you a list of items with the ability to add a new item or delete an item from the list. You'll want the application to allow you to edit every item and provide an easy way of navigating between them. A good example of this would be an application that allows you to manage a list of employees. The DataForm can do all of this and most of it is built-in. In this recipe, you'll learn how to achieve this. Getting ready For this recipe, we're starting with the basic setup that we completed in the previous recipe. If you didn't complete that recipe, you can find a starter solution in the Chapter05/ Dataform_Collection_Starter folder in the code bundle that is available on the Packt website. The finished solution for this recipe can be found in the Chapter05/Dataform_ Collection_Completed folder. In any case, you'll need to install the Silverlight Toolkit as the assemblies containing the DataForm are offered through it. You can download and install it from http://www.codeplex.com/Silverlight/.
Read more
  • 0
  • 0
  • 2397
article-image-introduction-data-binding
Packt
10 May 2010
10 min read
Save for later

Introduction to Data Binding

Packt
10 May 2010
10 min read
Introduction Data binding allows us to build data-driven applications in Silverlight in a much easier and much faster way compared to old-school methods of displaying and editing data. This article and the following one take a look at how data binding works. We'll start by looking at the general concepts of data binding in Silverlight 4 in this article. Analyzing the term data binding immediately reveals its intentions. It is a technique that allows us to bind properties of controls to objects or collections thereof. The concept is, in fact, not new. Technologies such as ASP.NET, Windows Forms, and even older technologies such as MFC (Microsoft Foundation Classes) include data binding features. However, WPF's data binding platform has changed the way we perform data binding; it allows loosely coupled bindings. The BindingsSource control in Windows Forms has to know of the type we are binding to, at design time. WPF's built-in data binding mechanism does not. We simply defi ne to which property of the source the target should bind. And at runtime, the actual data—the object to which we are binding—is linked. Luckily for us, Silverlight inherits almost all data binding features from WPF and thus has a rich way of displaying data. A binding is defined by four items: The source or source object: This is the data we are binding to. The data that is used in data binding scenarios is in-memory data, that is, objects. Data binding itself has nothing to do with the actual data access. It works with the objects that are a result of reading from a database or communicating with a service. A typical example is a Customer object. A property on the source object: This can, for example, be the Name property of the Customer object. The target control: This is normally a visual control such as a TextBox or a ListBox control. In general, the target can be a DependencyObject. In Silverlight 2 and Silverlight 3, the target had to derive from FrameworkElement; this left out some important types such as transformations. A property on the target control: This will, in some way—directly or after a conversion—display the data from the property on the source. The data binding process can be summarized in the following image: In the previous image, we can see that the data binding engine is also capable of synchronization. This means that data binding is capable of updating the display of data automatically. If the value of the source changes, Silverlight will change the value of the target as well without us having to write a single line of code. Data binding isn't a complete black box either. There are hooks in the process, so we can perform custom actions on the data fl owing from source to target, and vice versa. These hooks are the converters. Our applications can still be created without data binding. However, the manual process—that is getting data and setting all values manually on controls from code-behind—is error prone and tedious to write. Using the data-binding features in Silverlight, we will be able to write more maintainable code faster. In this article, we'll explore how data binding works. We'll start by building a small data-driven application, which contains the most important data binding features, to get a grasp of the general concepts. We'll also see that data binding isn't tied to just binding single objects to an interface; binding an entire collection of objects is supported as well. We'll also be looking at the binding modes. They allow us to specify how the data will flow (from source to target, target to source, or both). We'll finish this article series by looking at the support that Blend 4 provides to build applications that use data binding features. In the recipes of this article and the following one, we'll assume that we are building a simple banking application using Silverlight. Each of the recipes in this article will highlight a part of this application where the specific feature comes into play. The following screenshot shows the resulting Silverlight banking application: Displaying data in Silverlight applications When building Silverlight applications, we often need to display data to the end user. Applications such as an online store with a catalogue and a shopping cart, an online banking application and so on, need to display data of some sort. Silverlight contains a rich data binding platform that will help us to write data-driven applications faster and using less code. In this recipe, we'll build a form that displays the data of the owner of a bank account using data binding. Getting ready To follow along with this recipe, you can use the starter solution located in the Chapter02/ SilverlightBanking_Displaying_Data_Starter folder in the code bundle available on the Packt website. The finished application for this recipe can be found in the Chapter02/SilverlightBanking_Displaying_Data_Completed folder. How to do it... Let's assume that we are building a form, part of an online banking application, in which we can view the details of the owner of the account. Instead of wiring up the fields of the owner manually, we'll use data binding. To get data binding up and running, carry out the following steps: Open the starter solution, as outlined in the Getting Ready section. The form we are building will bind to data. Data in data binding is in-memory data, not the data that lives in a database (it can originate from a database though). The data to which we are binding is an instance of the Owner class. The following is the code for the class. Add this code in a new class fi le called Owner in the Silverlight project. public class Owner{public int OwnerId { get; set; }public string FirstName { get; set; }public string LastName { get; set; }public string Address { get; set; }public string ZipCode { get; set; }public string City { get; set; }public string State { get; set; }public string Country { get; set; }public DateTime BirthDate { get; set; }public DateTime CustomerSince { get; set; }public string ImageName { get; set; }public DateTime LastActivityDate { get; set; }public double CurrentBalance { get; set; }public double LastActivityAmount { get; set; }} Now that we've created the class, we are able to create an instance of it in the MainPage.xaml.cs file, the code-behind class of MainPage.xaml. In the constructor, we call the InitializeOwner method, which creates an instance of the Owner class and populates its properties. private Owner owner;public MainPage(){InitializeComponent();//initialize owner dataInitializeOwner();}private void InitializeOwner(){owner = new Owner();owner.OwnerId = 1234567;owner.FirstName = "John";owner.LastName = "Smith";owner.Address = "Oxford Street 24";owner.ZipCode = "W1A";owner.City = "London";owner.Country = "United Kingdom";owner.State = "NA";owner.ImageName = "man.jpg";owner.LastActivityAmount = 100;owner.LastActivityDate = DateTime.Today;owner.CurrentBalance = 1234.56;owner.BirthDate = new DateTime(1953, 6, 9);owner.CustomerSince = new DateTime(1999, 12, 20);} Let's now focus on the form itself and build its UI. For this sample, we're not making the data editable. So for every field of the Owner class, we'll use a TextBlock. To arrange the controls on the screen, we'll use a Grid called OwnerDetailsGrid. This Grid can be placed inside the LayoutRoot Grid.We will want the Text property of each TextBlock to be bound to a specifi c property of the Owner instance. This can be done by specifying this binding using the Binding "markup extension" on this property. <Grid x_Name="OwnerDetailsGrid"VerticalAlignment="Stretch"HorizontalAlignment="Left"Background="LightGray"Margin="3 5 0 0"Width="300" ><Grid.RowDefinitions><RowDefinition Height="100"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="30"></RowDefinition><RowDefinition Height="*"></RowDefinition></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition></ColumnDefinition><ColumnDefinition></ColumnDefinition></Grid.ColumnDefinitions><Image x_Name="OwnerImage"Grid.Row="0"Width="100"Height="100"Stretch="Uniform"HorizontalAlignment="Left"Margin="3"Source="/CustomerImages/man.jpg"Grid.ColumnSpan="2"></Image><TextBlock x_Name="OwnerIdTextBlock"Grid.Row="1"FontWeight="Bold"Margin="2"Text="Owner ID:"></TextBlock><TextBlock x_Name="FirstNameTextBlock"Grid.Row="2"FontWeight="Bold"Margin="2"Text="First name:"></TextBlock><TextBlock x_Name="LastNameTextBlock"Grid.Row="3"FontWeight="Bold"Margin="2"Text="Last name:"></TextBlock><TextBlock x_Name="AddressTextBlock"Grid.Row="4"FontWeight="Bold"Margin="2"Text="Adress:"></TextBlock><TextBlock x_Name="ZipCodeTextBlock"Grid.Row="5"FontWeight="Bold"Margin="2"Text="Zip code:"></TextBlock><TextBlock x_Name="CityTextBlock"Grid.Row="6"FontWeight="Bold"Margin="2"Text="City:"></TextBlock><TextBlock x_Name="StateTextBlock"Grid.Row="7"FontWeight="Bold"Margin="2"Text="State:"></TextBlock><TextBlock x_Name="CountryTextBlock"Grid.Row="8"FontWeight="Bold"Margin="2"Text="Country:"></TextBlock><TextBlock x_Name="BirthDateTextBlock"Grid.Row="9"FontWeight="Bold"Margin="2"Text="Birthdate:"></TextBlock><TextBlock x_Name="CustomerSinceTextBlock"Grid.Row="10"FontWeight="Bold"Margin="2"Text="Customer since:"></TextBlock><TextBlock x_Name="OwnerIdValueTextBlock"Grid.Row="1"Grid.Column="1"Margin="2"Text="{Binding OwnerId}"></TextBlock><TextBlock x_Name="FirstNameValueTextBlock"Grid.Row="2"Grid.Column="1"Margin="2"Text="{Binding FirstName}"></TextBlock><TextBlock x_Name="LastNameValueTextBlock"Grid.Row="3"Grid.Column="1"Margin="2"Text="{Binding LastName}"></TextBlock><TextBlock x_Name="AddressValueTextBlock"Grid.Row="4"Grid.Column="1"Margin="2"Text="{Binding Address}"></TextBlock><TextBlock x_Name="ZipCodeValueTextBlock"Grid.Row="5"Grid.Column="1"Margin="2"Text="{Binding ZipCode}"></TextBlock><TextBlock x_Name="CityValueTextBlock"Grid.Row="6"Grid.Column="1"Margin="2"Text="{Binding City}"></TextBlock><TextBlock x_Name="StateValueTextBlock"Grid.Row="7"Grid.Column="1"Margin="2"Text="{Binding State}"></TextBlock><TextBlock x_Name="CountryValueTextBlock"Grid.Row="8"Grid.Column="1"Margin="2"Text="{Binding Country}"></TextBlock><TextBlock x_Name="BirthDateValueTextBlock"Grid.Row="9"Grid.Column="1"Margin="2"Text="{Binding BirthDate}"></TextBlock><TextBlock x_Name="CustomerSinceValueTextBlock"Grid.Row="10"Grid.Column="1"Margin="2"Text="{Binding CustomerSince}"></TextBlock><Button x_Name="OwnerDetailsEditButton"Grid.Row="11"Grid.ColumnSpan="2"Margin="3"Content="Edit details..."HorizontalAlignment="Right"VerticalAlignment="Top"></Button><TextBlock x_Name="CurrentBalanceValueTextBlock"Grid.Row="12"Grid.Column="1"Margin="2"Text="{Binding CurrentBalance}" ></TextBlock><TextBlock x_Name="LastActivityDateValueTextBlock"Grid.Row="13"Grid.Column="1"Margin="2"Text="{Binding LastActivityDate}" ></TextBlock><TextBlock x_Name="LastActivityAmountValueTextBlock"Grid.Row="14"Grid.Column="1"Margin="2"Text="{Binding LastActivityAmount}" ></TextBlock></Grid> At this point, all the controls know what property they need to bind to. However, we haven't specifi ed the actual link. The controls don't know about the Owner instance we want them to bind to. Therefore, we can use DataContext. We specify the DataContext of the OwnerDetailsGrid to be the Owner instance. Each control within that container can then access the object and bind to its properties . Setting the DataContext in done using the following code: public MainPage(){InitializeComponent();//initialize owner dataInitializeOwner();OwnerDetailsGrid.DataContext = owner;} The result can be seen in the following screenshot:
Read more
  • 0
  • 0
  • 4226

article-image-working-binding-data-and-ui-elements-silverlight-4
Packt
10 May 2010
6 min read
Save for later

Working with Binding data and UI elements in Silverlight 4

Packt
10 May 2010
6 min read
Binding data to another UI element Sometimes, the value of the property of an element is directly dependent on the value of the property of another element. In this case, you can create a binding in XAML called an element binding or element-to-element binding . This binding links both values. If needed, the data can flow bidirectionally. In the banking application, we can add a loan calculator that allows the user to select an amount and the number of years in which they intend to pay the loan back to the bank, including (of course) a lot of interest. Getting ready To follow this recipe, you can either continue with your solution from the previous recipe or use the provided solution that can be found in the Chapter02/SilverlightBanking_ Element_Binding_Starter folder in the code bundle that is available on the Packt website. The finished application for this recipe can be found in the Chapter02/SilverlightBanking_Element_Binding_Completed folder. How to do it... To build the loan calculator, we'll use Slider controls. Each Slider is bound to a TextBlock using an element-to-element binding to display the actual value. Let's take a look at the steps we need to follow to create this binding: We will build the loan calculator as a separate screen in the application. Add a new child window called LoanCalculation.xaml. To do so, right-click on the Silverlight project in the Solution Explorer, select Add | New Item..., and choose Silverlight Child Window under Visual C#. Within MainPage.xaml, add a Click event on the LoanCalculationButton as shown in the following code: <Button x_Name="LoanCalculationButton" Click="LoanCalculationButton_Click" /> In the code-behind's event handler for this Click event, we can trigger the display of this new screen with the following code: private void LoanCalculationButton_Click(object sender, RoutedEventArgs e) { LoanCalculation loanCalculation = new LoanCalculation(); loanCalculation.Show(); } The UI of the LoanCalculation.xaml is quite simple—it contains two Slider controls. Each Slider control has set values for its Minimum and Maximum values (not all UI code is included here; the complete listing can be found in the finished sample code) as shown in the following code: <Slider x_Name="AmountSlider" Minimum="10000" Maximum="1000000" SmallChange="10000" LargeChange="10000" Width="300" > </Slider> <Slider x_Name="YearSlider" Minimum="5" Maximum="30" SmallChange="1" LargeChange="1" Width="300" UseLayoutRounding="True"> </Slider> As dragging a Slider does not give us proper knowledge of where we are exactly between the two values, we add two TextBlock controls. We want the TextBlock controls to show the current value of the Slider control, even while dragging. This can be done by specifying an element-to-element binding as shown in the following code: <TextBlock x_Name="AmountTextBlock" Text="{Binding ElementName=AmountSlider, Path=Value}"> </TextBlock> <TextBlock x_Name="MonthTextBlock" Text="{Binding ElementName=YearSlider, Path=Value}"> </TextBlock> Add a Button that will perform the actual calculation called CalculateButton and a TextBlock called PaybackTextBlock to show the results. This can be done using the following code: <Button x_Name="CalculateButton" Content="Calculate" Click="CalculateButton_Click"> </Button> <TextBlock x_Name="PaybackTextBlock"></TextBlock> The code for the actual calculation that is executed when the Calculate button is clicked uses the actual value for either the Slider or the TextBlock. This is shown in the following code: private double percentage = 0.0345; private void CalculateButton_Click(object sender, RoutedEventArgs e) { double requestedAmount = AmountSlider.Value; int requestedYears = (int)YearSlider.Value; for (int i = 0; i < requestedYears; i++) { requestedAmount += requestedAmount * percentage; } double monthlyPayback = requestedAmount / (requestedYears * 12); PaybackTextBlock.Text = "€" + Math.Round(monthlyPayback, 2); } Having carried out the previous steps, we now have successfully linked the value of the Slider controls and the text of the TextBlock controls. The following screenshot shows the LoanCalculation.xaml screen as it is included in the finished sample code containing some extra markup: How it works... An element binding links two properties of two controls directly from XAML. It allows creating a Binding where the source object is another control. For this to work, we need to create a Binding and specify the source control using the ElementName property. This is shown in the following code: <TextBlock Text="{Binding ElementName=YearSlider, Path=Value}" > </TextBlock> Element bindings were added in Silverlight 3. Silverlight 2 did not support this type of binding. There's more... An element binding can also work in both directions, that is, from source to target and vice versa. This can be achieved by specifying the Mode property on the Binding and setting it to TwoWay. The following is the code for this. In this code, we replaced the TextBlock by a TextBox. When entering a value in the latter, the Slider will adjust its position: <TextBox x_Name="AmountTextBlock" Text="{Binding ElementName=AmountSlider, Path=Value, Mode=TwoWay}" > </TextBox> Element bindings without bindings Achieving the same effect in Silverlight 2—which does not support this feature—is also possible, but only through the use of an event handler as shown in the following code. Element bindings eliminate this need: private void AmountSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { AmountSlider.Value = Math.Round(e.NewValue); AmountTextBlock.Text = AmountSlider.Value.ToString(); } See also Element-to-element bindings can be easily extended to use converters. For more information on TwoWay bindings, take a look at the Using the different modes of data binding to allow persisting data recipe in this article. Binding collections to UI elements Often, you'll want to display lists of data in your application such as a list of shopping items, a list of users, a list of bank accounts, and so on. Such a list typically contains a bunch of items of a certain type that have the same properties and need to be displayed in the same fashion. We can use data binding to easily bind a collection to a Silverlight control (such as a ListBox or DataGrid) and use the same data binding possibilities to defi ne how every item in the collection should be bound. This recipe will show you how to achieve this. Getting ready For this recipe, you can fi nd the starter solution in the Chapter02/SilverlightBanking_ Binding_Collections_Starter folder and the completed solution in the Chapter02/SilverlightBanking_Binding_Collections_Completed folder in the code bundle that is available on the Packt website.
Read more
  • 0
  • 0
  • 1579

article-image-creating-and-modifying-filters-moodle-19
Packt
06 May 2010
6 min read
Save for later

Creating and Modifying Filters in Moodle 1.9

Packt
06 May 2010
6 min read
Moodle filters modify content from the database as it is output to the screen, thus adding function to the display. An example of this is the multimedia filter, which can detect references to video and audio files, and can replace them with a "mini-player" embedded in the content. How a filter works Before trying to build a filter, it would help to understand how it works. To begin with, any text written to the screen in Moodle should be processed through the format_text function. The purpose of this function is to process the text, such that it is always safe to be displayed. This means making sure there are no security issues and that any HTML used contains only allowed tags. Additionally, the output is run through the filter_text function, and this is the function we are interested in. This function takes the text destined for the screen, and applies all enabled filters to it. The resulting text will be the result of all of these filters. filter_text applies each enabled filter to the text in the order defined in the filter configuration screen (shown in the following screenshot). The order is important; each filter will be fed the output of the previous filter's text. So it is always possible that one filter may change the text in a way that impacts the next filter. Building a filter Now it's time to build our own filter. To begin with, let's come up with a requirement. Let's assume that our organization, called "Learning is Fun", has a main website at http://2fun2learn.org. Now, we need any instance of the phrase learning is fun to be hyperlinked to the website URL every time it appears on the screen, as in the forum post shown in the following screenshots: We can do this by implementing a policy with our content creators that forces them to create hyperlink tags around the phrase every time they write it. However, this will be difficult to enforce and will be fraught with errors. Instead, wouldn't it be easier if the system itself could recognize the phrase and create the hyperlink for us? That's what our filter will do. Getting started We need a name for our filter. It is the name that will be used for the directory the filter will reside in. We want a name that will describe what our filter does and will be unlikely to conflict with any other filter name. Let's call it "learningisfunlink". To start with, create a new subdirectory in the /filter directory and call it learningisfunlink. Next, create a new file called filter.php. This is the only file required for a filter. Open the new filter.php file in your development environment. The filter only requires one function, which is named after the filter name and suffixed with _filter. Add the PHP open and close tags (<?php and ?>), and an empty function called learningisfunlink_filter that takes two arguments: a course ID and the text to filter. When completed, you should have a file that looks like this: <?phpfunction learningisfunlink_filter($courseid, $text) {return $text;}?> We now have the bare minimum required for the filter to be recognized by the system. It doesn't do what we want yet, but it will be present. Creating the language file Log in to the site (that makes use of your new filter) as an administrator. On the main page of your site, look for the Modules Filters| folder in the Site Administration block. Click on the Manage filters link. If you have the default filter setup, you will see your new filter near the bottom of the list, called Learningisfunlink, as shown in the following screenshot: Now, even though the name is reasonably descriptive, it will be better if it were a phrase similar to the others in the list; something like Main website link. To do this, we need to create a new directory in our /filter/learningisfunlink directory called lang/en_utf8/ (the en_utf8 is the language specific part—English in this case). In this directory, we create a new file called filter_learningisfunlink.php. This name is the concatenation of the phrase filter_ and the name of our filter. In this file, we need to add the following line: $string['filtername'] = "Main website link"; This language string defines the text that will be displayed as the name of our filter, replacing the phrase Learningisfunlink that we saw earlier with Main website link. This file will contain any other strings that we may output to the screen, specifically for this filter. Once we have created this file, returning to the Manage filters page should now show our filter with the name that we provided for it in our language file. Creating the filter code We now have a filter that is recognized by the system and that displays the name we want it to. However, we haven't made it do anything. Let's create the code to add some functionality. Remember, what we want this filter to do is to search the text and add a hyperlink pointing to our website for all occurrences of the phrase "learning is fun". We could simply perform a search and replace function on the text and return it, and that would be perfectly valid. However, for the sake of learning more about the Moodle API, we'll use some functions that are set up specifically for filters. To that end, we'll look at two code constructs: the filterobject class and the filter_phrases function, both of which are contained in the /lib/filterlib.php file. The filterobject class defines an object that contains all of the information required by the filter_phrases function to change the text to the way the filter wants it to be. It contains the phrase to be filtered, the tag to start the replacement with, the tag to end the replacement with, whether to match case, whether a full match is required, and any replacement text for the match. An array of filterobjects is sent to the filter_phrases function, along with the text to search in. It's intended to be used when you have a number of phrases and replacements to apply at one time, but we'll use it anyway. Let's initialize our filter strings: $searchphrase = "learning is fun";$starttag = "<a href="http://2fun2learn.org">";$endtag = "</a>"; Now, let's create our filterobject: $filterobjects = array();$filterobjects[] = new filterobject($searchphrase, $starttag, $endtag); Lastly, let's pass the structure to the filter_phrases function, along with the text to be filtered: $text = filter_phrases($text, $filterobjects); Our function now has the code to change any occurrence of the phrase "learning is fun" to a hyperlinked phrase. Let's go test it
Read more
  • 0
  • 0
  • 1557
article-image-vim-72-formatting-code
Packt
30 Apr 2010
11 min read
Save for later

Vim 7.2 Formatting Code

Packt
30 Apr 2010
11 min read
Formatting code often depends on many different things. Each programming language has its own syntax, and some languages rely on formatting like indentation more than others. In some cases, the programmer is following style guidelines given by an employer so that code can follow the company-wide style. So, how should Vim know how you want your code to be formatted? The short answer is that it shouldn't! But by being flexible, Vim can let you set up exactly how you want your formatting done. However, the fact is that even though formatting differs, most styles of formatting follow the same basic rules. This means that in reality, you only have to change the things that differ. In most cases, the changes can be handled by changing a range of settings in Vim. Among these, there are a few especially worth mentioning: Formatoptions: This setting holds formatting-specific settings (see :help 'fo') Comments: What are comments and how they should be formatted (see :help 'co') (no)expandtab: Convert tabs to spaces (see :help 'expandtab') Softtabstop: How many spaces a single tab is converted to (see :help 'sts') Tabstop: How many spaces a tab looks like (see :help 'ts') With these options, you can set nearly every aspect of how Vim will indent your code, and whether it should use spaces or tabs for indentation. But this is not enough because you still have to tell Vim if it should actually try to do the indentation for you, or if you want to do it manually. It you want Vim to do the indentation for you, you have the choice between four different ways for Vim to do it. In the following sections, we will look at the options you can set to interact with the way Vim indents code. Autoindent Autoindent is the simplest way of getting Vim to indent your code. It simply stays at the same indentation level as the previous line. So, if the current line is indented with four spaces, then the new line you add by pressing Enter will automatically be indented with four spaces too. It is then up to you as to how and when the indentation level needs to change again. This type of indentation is particularly good for languages where the indentation stays the same for several lines in a row. You get autoindent by using :set, autoindent, or :set ai. Smartindent Smartindent is the next step when you want a smarter indent than autoindent. It still gives you the indentation from the previous line, but you don't have to change the indentation level yourself. Smartindent recognizes the most common structures from the C programming language and uses this as a marker for when to add / remove the indentation levels. As many languages are loosely based on the same syntax as C, this will work for those languages as well. You get smart indent by using any of the following commands: :set smartindent :set si Cindent Cindent is often called clever indent or configurable indent because it is more configurable than the previous two indentation methods. You have access to three different setup options: cinkeys This option contains a comma-separated list of keys that Vim should use to change the indentation level. An example could be: :set cinkeys="0{,0},0#,:", which means that it should reindent whenever it hits a {, a } or a # as the first character on the line, or if you use : as the last character on the line (as used in switch constructs in many languages).The default value for cinkeys is "0{, 0}, 0), :, 0#, !^F, o, O, and e". See :help cinkeys for more information on what else you can set in this option. cinoptions This option contains all the special options you can set specifically for cindent. A large range of options can be set in this comma-separated list. An example could be:set cinoptions=">2,{3,}3", which means that we want Vim to add two extra spaces to the normal indent length, and we want to place { and } three spaces as compared to the previous line. So, if we have a normal indent to be four spaces, then the previous example could result in the code looking like this (dot marks represent a space): if( a == b) ...{ ......print "hello"; ...} The default value for cinoptions is this quite long string: ">s,e0,n0,f0,{0,}0,^0,:s,=s,l0,b0,gs,hs,ps,ts,is,+s,c3,C0,/0,(2s,us,U0,w0,W0,m0,j0,)20,*30" . See :help 'cinoptions' for more information on all the options. cinwords This option contains all the special keywords that will make Vim add indentation on the next line. An example could be: :set cinwords="if,else,do,while,for,switch", which is also the default value for this option. See :help 'cinwords' for more information. Indentexpr Indentexpr is the most flexible indent option to use, but also the most complex. When used, indentexpr evaluates an expression to compute the indent of a line. Hence, you have to write an expression that Vim can evaluate. You can activate this option by simply setting it to a specific expression such as: :set indentexpr=MyIndenter() Here, MyIndenter() is a function that computes the indentation for the lines it is executed on. A very simple example could be a function that emulates the autoindent option: function! MyIndenter() " Find previous line and get its indentation let prev_lineno = s:prevnonblank(v:lnum) let ind = indent( prev_lineno ) return indendfunction Adding just a bit more functionality than this, the complexity increases quite fast. Vim comes with a lot of different indent expressions for many programming languages. These can serve as inspiration if you want to write your own indent expression. You can find them in the indent folder in your VIMHOME. You can read more about how to use indentexpr in :help 'indentexpr' and :help 'indent-expression'. Fast code-block formatting After you have configured your code formatting, you might want to update your code to follow these settings. To do so, you simply have to tell Vim that it should reindent every single line in the file from the first line to the last. This can be done with the following Vim command: 1G=G If we split it up, it simply says: 1G: Go to the first line of the file (alternatively you can use gg) =: Equalize lines; in other words, indent according to formatting configuration G: Go to the last line in the file (tells Vim where to end indenting) You could easily map this command to a key in order to make it easily accessible: :nmap <F11> 1G=G:imap <F11> <ESC>1G=Ga The last a is to get back into the insert mode as this was where we originally were. So, now you can just press the F11key in order to reindent the entire buffer correctly. Note that if you have a programmatic error, for example, missing a semicolon at the end of a line in a C program, the file will not be correctly indented from that point on in the buffer. This can sometimes be useful to identify where a scope is not closed correctly (for example, a { not closed with a } ). Sometimes, you might just want to format smaller blocks of code. In those cases, you typically have two options—use the natural scope blocks in the code, or select a block of code in the visual mode and indent it. The last one is simple. Go into the visual mode with, for example,Shift+v and then press = to reindent the lines. When it comes to using code blocks on the other hand, there are several different ways to do it. In Vim, there are multiple ways to select a block of code. So in order to combine a command that indents a code block, we need to look at the different types and the commands to select them: i{ Inner block, which means everything between { and } excluding the brackets. This can also be selected with i} and iB. a{ A block, which means all the code between { and } including the brackets. This can also be selected with a} and aB. i( Inner parenthesis, meaning everything between ( and ) excluding the parentheses. Can also be selected with i) and ib. a( A parentheses, meaning everything between ( and ) including the parenthesis. Can also be selected with a) and ab. i< Inner < > block, meaning everything between < and > excluding the brackets. Can also be selected with i>. a< A < > block, meaning everything between < and > including the brackets. Can also be selected with a>. i[ Inner [ ] block, meaning everything between [ and ] excluding the square brackets. Can also be selected with i]. a[ A [ ] block, meaning everything between [ and ], including the square brackets. This can also be selected with a]. So, we have defined what Vim sees a block of code as; now, we simply have to tell it what to do with the block. In our case, we want to reindent the code. We already know that = can do this. So, an example of a code block reindentation could look like this: =i{ Let's execute the code block reindentation in the following code (| being the place where the cursor is): if( a == b ) { print |"a equals b"; } This would produce the following code (with default C format settings): if( a == b ) { print |"a equals b"; } If, on the other hand, we choose to use a { as the block we are working on, then the resulting code would look like this: if( a == b ) { print "a equals b"; } As you can see in the last piece of code, the =a{ command corrects the indentation of both the brackets and the print line. In some cases where you work in a code block with multiple levels of code blocks, you might want to reindent the current block and maybe the surrounding one. No worries, Vim has a fast way to do this. If, for instance, you want to reindent the current code block and besides that want to reindent the block that surrounds it, you simply have to execute the following command while the cursor is placed in the innermost block: =2i{ This simply tells Vim that you will equalize / reindent two levels of inner blocks counting from the "active" block and out. You can replace the number 2 with any number of levels of code blocks you want to reindent. Of course, you can also swap the inner block command with any of the other block commands, and that way select exactly what you want to reindent. So, this is really all it takes to get your code to indent according to the setup you have. Auto format pasted code The trend among programmers tells us that we tend to reuse parts of our code, or so-called patterns. This could mean that you have to do a lot of copying and pasting of code. Most users of Vim have experienced what is often referred to as the stair effect when pasting code into a file. This effect occurs when Vim tries to indent the code as it inserts it. This often results in each new line to be indented to another level, and you ending up with a stair: code line 1 code line 2 codeline 3 code line 4 ... The normal workaround for this is to go into the paste-mode in Vim, which is done by using: :set paste After pasting your code, you can now go back to your normal insert mode again: :set nopaste But what if there was another workaround? What if Vim could automatically indent the pasted code such that it is indented according to the rest of the code in the file? Vim can do that for you with a simple paste command. p=`] This command simply combines the normal paste command (p) with a command that indents the previously inserted lines (=`]). It actually relies on the fact that when you paste with p (lowercase), the cursor stays on the first character of the pasted text. This is combined with `], which takes you to the last character of the latest inserted text and gives you a motion across the pasted text from the first line to the last. So, all you have to do now is map this command to a key and then use this key whenever you paste a piece of code into your file. Using external formatting tools Even though experienced Vim users often say that Vim can do everything, this is of course not the truth—but is close. For those things that Vim can't do, it is smart enough to be able to use external tools. In the following sections, we will take a look at some of the most used external tools that can be used for formatting your code, and how to use them.
Read more
  • 0
  • 0
  • 7160

article-image-vim-72-scripting
Packt
30 Apr 2010
9 min read
Save for later

Vim 7.2 Scripting

Packt
30 Apr 2010
9 min read
Scripting tips In this section, we will look at a few extra tips that can be handy when you create scripts for Vim. Some are simple code pieces you can add directly in your script, while others are good-to-know tips. Gvim or Vim? Some scripts have extra features when used in the GUI version of Vim (Gvim). This could be adding menus, toolbars, or other things that only work if you are using Gvim. So what do you do to check if the user runs the script in a console Vim or in Gvim? Vim has already prepared the information for you. You simply have to check if the feature gui_running is enabled. To do so, you use a function called has(), which returns 1 (true) if a given feature is supported / enabled and 0 (false), otherwise. An example could be: if has("gui_running") "execute gui-only commands here.endif This is all you need to do to check if a user has used Gvim or not. Note that it is not enough to check if the feature "gui" exists, because this will return true if your Vim is just compiled with GUI support—even if it is not using it. Look in :help 'feature-list' for a complete list of other features you can check with the has() function. Which operating system? If you have tried to work with multiple operating systems such as Microsoft Windows and Linux, you will surely know that there are many differences. This can be everything from where programs are placed, to which programs you have available and how access to files is restricted. Sometimes, this can also have an influence on how you construct your Vim script as you might have to call external programs, or use other functionality, specific for a certain operating system. Vim lets you check which operation system you are on, such that you can stop executing your script or make decisions about how to configure your script. This is done with the following piece of code: if has("win16") || has("win32") || has("win64")|| has("win95") " do windows things hereelseif has("unix") " do linux/unix things hereendif This example only shows how to check for Windows (all flavors available) and Linux / Unix. As Vim is available on a wide variety of platforms, you can of course also check for these. All of the operating systems can be found in: :help 'feature-list' Which version of Vim? Throughout the last decade or two, Vim has developed and been extended with a large list of functions. Sometimes, you want to use the newest functions in your script, as these are the best / easiest to use. But what about the users who have a version of Vim that is older than the one you use, and hence don't have access to the functions you use? You have three options: Don't care and let it be the user's own problem (not a good option). Check if the user uses an old version of Vim, and then stop executing the script if this is the case. Check if the user has too old a version of Vim, and then use alternative code. The first option is really not one I would recommend anyone to use, so please don't use it. The second option is acceptable, if you can't work around the problem in the old version of Vim. However, if it is possible to make an alternative solution for the older version of Vim, then this will be the most preferable option. So let's look at how you can check the version of Vim. Before we look at how to check the version, we have to take a look at how the version number is built. The number consists of three parts: Major number (for example, 7 for Vim version 7) Minor number (for example, 3 for Vim version 6.3) Patch number (for example, 123 for Vim 7.0.123) The first two numbers are the actual version number, but when minor features / patches are applied to a version of Vim, it is mostly only the patch number that is increased. It takes quite a bit of change to get the minor number to increase, and a major part of Vim should change in order to increase the major version number. Therefore, when you want to check which version of Vim the user is using, you do it for two versions—major and minor versions and patch number. The code for this could look like: if v:version >= 702 || v:version == 701 && has("patch123") " code here is only done for version 7.1 with patch 123 " and version 7.2 and aboveendif The first part of the if condition checks if our version of Vim is version 7.2 (notice that the minor version number is padded with 0 if less than 10) or above. If this is not the case, then it checks to see if we have a version 7.1 with patch 123. If patch version 124 or above is included, then you also have patch 123 automatically. Printing longer lines Vim was originally created for old text terminals where the length of lines was limited to a certain number of characters. Today, this old limitation shows up once in a while. One place where you meet this limitation of line length is when printing longer lines to the screen using the "echo" statement. Even though you use Vim in a window where there are more than the traditional 80 characters per line, Vim will still prompt you to press Enter after echoing lines longer than 80 characters. There is, however, a way to get around this, and make it possible to use the entire window width to echo on. Window width means the total number of columns in the Vim window minus a single character. So if your Vim window is wide enough to have 120 characters on each line, then the window width is 120-1 characters. By adding the following function to your script, you will be able to echo screen-wide long lines in Vim: " WideMsg() prints [long] message up to (&columns-1) lengthfunction! WideMsg(msg) let x=&ruler | let y=&showcmd set noruler noshowcmd redraw echo a:msg let &ruler=x | let &showcmd=yendfunction This function was originally proposed by the Vim script developer Yakov Lerner on the Vim online community site at http://www.vim.org. Now whenever you need to echo a long line of text in your script, instead of using the echo statement you simply use the function Widemsg(). An example could be: :call WideMsg("This should be a very long line of text") The length of a single line message is still limited, but now it is limited to the width of the Vim window instead of the traditional 80-1 characters. Debugging Vim scripts Sometimes things in your scripts do not work exactly as you expect them to. In these cases, it is always good to know how to debug your script. In this section, we will look at some of the methods you can use to find your error. Well-structured code often has fewer bugs and is also easier to debug. In Vim, there is a special mode to perform script debugging. Depending on what you want to debug, there are some different ways to start this mode. So let's look at some different cases. If Vim just throws some errors (by printing them at the bottom of the Vim window), but you are not really sure where it is or why it happens, then you might want to try to start Vim directly in debugging mode. This is done on the command line by invoking Vim with the -Dargument. vim -D somefile.txt The debugging mode is started when Vim starts to read the first vimrc file it loads (in most cases the global vimrc file where Vim is installed). We will look at what to do when you get into debug mode in a moment. Another case where you might want to get into debug mode is when you already know which function the error (most likely) is in, and hence, just want to debug that function. In that case you just open Vim as normal (load the script with the particular function if needed) and then use the following command: :debug call Myfunction() Here everything after the :debug is the functionality you want to debug. In this case, it is a simple call of the function Myfunction(), but it could just as well be any of the following: :debug read somefile.txt:debug nmap ,a :call Myfunction() <CR>:debug help :debug So let's look at what to do when we get into the debugging mode. When reaching the first line that it should debug, Vim breaks the loading and shows something like: Entering Debug mode. Type "cont" to continue.cmd: call MyFunction()> Now you are in the Vim script debugger and have some choices for what to make Vim do. If you are not familiar with debugging techniques, it might be a good idea to read up on this subject before starting to debug your scripts. The following commands are available in the debugger (shortcuts are in parentheses): cont (c): Continue running the scripts / commands as normal (no debugging) until the next breakpoint (more about this later). quit (q): Quit the debugging process without executing the last lines. interrupt (i): Stop the current process like quit, but go back to the debugger. step (s): Execute the next line of code and come back to the debugger when it is finished. If a line calls a function or sources a file, then it will step into the function / file. next (n): Execute the next command and come back to the debugger when it is finished. If used on a line with a function call, it does not go into the function but steps over it. finish (f): Continue executing the script without stopping on breakpoints. Go into debug mode when done.
Read more
  • 0
  • 0
  • 2417