<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://commons.oreilly.com/wiki/skins/common/feed.css?97"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer's_Notebook/Editing_Movies&amp;action=history&amp;feed=atom</id>
		<title>QuickTime for Java: A Developer's Notebook/Editing Movies - Revision history</title>
		<link rel="self" type="application/atom+xml" href="http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer's_Notebook/Editing_Movies&amp;action=history&amp;feed=atom"/>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Editing_Movies&amp;action=history"/>
		<updated>2013-05-18T12:30:38Z</updated>
		<subtitle>Revision history for this page on the wiki</subtitle>
		<generator>MediaWiki 1.11.0</generator>

	<entry>
		<id>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Editing_Movies&amp;diff=7238&amp;oldid=prev</id>
		<title>Docbook2Wiki: Initial conversion from Docbook</title>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Editing_Movies&amp;diff=7238&amp;oldid=prev"/>
				<updated>2008-03-07T13:22:47Z</updated>
		
		<summary type="html">&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 13:22, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</summary>
		<author><name>Docbook2Wiki</name></author>	</entry>

	<entry>
		<id>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Editing_Movies&amp;diff=7159&amp;oldid=prev</id>
		<title>Docbook2Wiki: Initial conversion from Docbook</title>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Editing_Movies&amp;diff=7159&amp;oldid=prev"/>
				<updated>2008-03-07T13:17:34Z</updated>
		
		<summary type="html">&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 13:17, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</summary>
		<author><name>Docbook2Wiki</name></author>	</entry>

	<entry>
		<id>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Editing_Movies&amp;diff=4459&amp;oldid=prev</id>
		<title>Evanlenz: 1 revision(s)</title>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Editing_Movies&amp;diff=4459&amp;oldid=prev"/>
				<updated>2008-03-07T00:25:56Z</updated>
		
		<summary type="html">&lt;p&gt;1 revision(s)&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 00:25, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</summary>
		<author><name>Evanlenz</name></author>	</entry>

	<entry>
		<id>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Editing_Movies&amp;diff=4458&amp;oldid=prev</id>
		<title>Docbook2Wiki: Initial conversion from Docbook</title>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Editing_Movies&amp;diff=4458&amp;oldid=prev"/>
				<updated>2008-03-07T00:17:35Z</updated>
		
		<summary type="html">&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 00:17, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 250:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 250:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 3-1. BasicQTEditor with two movies open'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 3-1. BasicQTEditor with two movies open'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_3_tt39.png|BasicQTEditor with two movies open]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_3_tt39.png|BasicQTEditor with two movies open]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 300:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 300:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 3-2. MovieController scrubber bar with editing enabled'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 3-2. MovieController scrubber bar with editing enabled'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_3_tt40.png|MovieController scrubber bar with editing enabled]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_3_tt40.png|MovieController scrubber bar with editing enabled]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 559:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 559:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 3-3. QuickTime Save As dialog'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 3-3. QuickTime Save As dialog'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_3_tt47.png|QuickTime Save As dialog]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_3_tt47.png|QuickTime Save As dialog]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 609:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 609:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 3-4. Default QuickTime progress dialog'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 3-4. Default QuickTime progress dialog'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_3_tt49.png|Default QuickTime progress dialog]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_3_tt49.png|Default QuickTime progress dialog]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 748:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 748:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 3-5. Unresolvable media reference dialog'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 3-5. Unresolvable media reference dialog'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_3_tt52.png|Unresolvable media reference dialog]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_3_tt52.png|Unresolvable media reference dialog]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 849:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 849:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 3-6. QuickTime Player &amp;quot;Get Info&amp;quot; for movie with multiple audio tracks'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 3-6. QuickTime Player &amp;quot;Get Info&amp;quot; for movie with multiple audio tracks'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_3_tt54.png|QuickTime Player &amp;quot;Get Info&amp;quot; for movie with multiple audio tracks]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_3_tt54.png|QuickTime Player &amp;quot;Get Info&amp;quot; for movie with multiple audio tracks]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;!-- diff cache key wikicontent:diff:version:1.11a:oldid:4307:newid:4458 --&gt;
&lt;/table&gt;</summary>
		<author><name>Docbook2Wiki</name></author>	</entry>

	<entry>
		<id>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Editing_Movies&amp;diff=4307&amp;oldid=prev</id>
		<title>Evanlenz: 1 revision(s)</title>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Editing_Movies&amp;diff=4307&amp;oldid=prev"/>
				<updated>2008-03-07T00:16:19Z</updated>
		
		<summary type="html">&lt;p&gt;1 revision(s)&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 00:16, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</summary>
		<author><name>Evanlenz</name></author>	</entry>

	<entry>
		<id>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Editing_Movies&amp;diff=4306&amp;oldid=prev</id>
		<title>Docbook2Wiki: Initial conversion from Docbook</title>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Editing_Movies&amp;diff=4306&amp;oldid=prev"/>
				<updated>2008-03-07T00:15:32Z</updated>
		
		<summary type="html">&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 00:15, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</summary>
		<author><name>Docbook2Wiki</name></author>	</entry>

	<entry>
		<id>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Editing_Movies&amp;diff=4155&amp;oldid=prev</id>
		<title>Evanlenz: 1 revision(s)</title>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Editing_Movies&amp;diff=4155&amp;oldid=prev"/>
				<updated>2008-03-06T23:57:55Z</updated>
		
		<summary type="html">&lt;p&gt;1 revision(s)&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 23:57, 6 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</summary>
		<author><name>Evanlenz</name></author>	</entry>

	<entry>
		<id>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Editing_Movies&amp;diff=4154&amp;oldid=prev</id>
		<title>Docbook2Wiki: Initial conversion from Docbook</title>
		<link rel="alternate" type="text/html" href="http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Editing_Movies&amp;diff=4154&amp;oldid=prev"/>
				<updated>2008-03-06T23:50:56Z</updated>
		
		<summary type="html">&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{QuickTime for Java: A Developer's Notebook/TOC}}&lt;br /&gt;
Playback is nice, but you have nothing to play if you lack tools to create media, and the most critical of these are editing tools. If you've ever used iMovie with your home movies, you know what I'm talking about: there's a huge difference between watching a cute collection of scenes of your kids playing, set to music, and watching the two hours of unedited raw footage you started with. Sometimes, less ''is'' more.&lt;br /&gt;
&lt;br /&gt;
== Copying and Pasting ==&lt;br /&gt;
&lt;br /&gt;
The most familiar form of editing is copy-and-paste, which many users already are familiar with from the &amp;quot;pro&amp;quot; version of QuickTime Player. The metaphor is identical to how copy-and-paste works in nonmedia applications such as text editors and spreadsheets: select some source material of interest, do a &amp;quot;copy&amp;quot; to put it on the system clipboard, select an insertion point in this or another document, and do a &amp;quot;paste&amp;quot; to put the contents of the clipboard into that target.&lt;br /&gt;
&lt;br /&gt;
In the simplest form of a QuickTime copy-and-paste, the controller bar (from &amp;lt;tt&amp;gt;MovieController&amp;lt;/tt&amp;gt;) is used to indicate where copies and pastes should occur. By shift-clicking, a user can select a time-range from the current time (indicated by the play head) to wherever the user shift-clicks (or, if he is dragging, wherever the mouse is released).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''QuickTime Pro costs money ($29.99 as of this writing), but it allows you to exercise much of the QuickTime API from QuickTime Player, which can be a useful debugging tool''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;BasicQTEditor&amp;lt;/tt&amp;gt;, shown in [[QuickTime for Java: A Developer's Notebook/Editing Movies#quicktimejvaadn-CHP-3-EX-1|Example 3-1]], will be the basis for the examples in this chapter. It offers a single empty movie window (with the ability to open movies from disk in new windows or to create new empty movie windows), and an Edit menu with cut, copy, and paste options.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-3-EX-1&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 3-1. A copy-and-paste movie editor'''&lt;br /&gt;
&lt;br /&gt;
 package com.oreilly.qtjnotebook.ch03;&lt;br /&gt;
  &lt;br /&gt;
 import quicktime.*;&lt;br /&gt;
 import quicktime.qd.QDRect;&lt;br /&gt;
 import quicktime.std.*;&lt;br /&gt;
 import quicktime.std.movies.*;&lt;br /&gt;
 import quicktime.app.view.*;&lt;br /&gt;
 import quicktime.io.*;&lt;br /&gt;
  &lt;br /&gt;
 import java.awt.*;&lt;br /&gt;
 import java.awt.event.*;&lt;br /&gt;
  &lt;br /&gt;
 import com.oreilly.qtjnotebook.ch01.QTSessionCheck;&lt;br /&gt;
  &lt;br /&gt;
 public class BasicQTEditor extends Frame&lt;br /&gt;
   implements ActionListener {&lt;br /&gt;
  &lt;br /&gt;
   Component comp;&lt;br /&gt;
  &lt;br /&gt;
   Movie movie;&lt;br /&gt;
   MovieController controller;&lt;br /&gt;
   Menu fileMenu, editMenu;&lt;br /&gt;
   MenuItem openItem, closeItem, newItem, quitItem;&lt;br /&gt;
   MenuItem copyItem, cutItem, pasteItem;&lt;br /&gt;
   static int newFrameX = -1;&lt;br /&gt;
   static int newFrameY = -1;&lt;br /&gt;
   static int windowCount = 0;&lt;br /&gt;
   &lt;br /&gt;
   /** no-arg constructor for &amp;quot;new&amp;quot; movie&lt;br /&gt;
    */&lt;br /&gt;
   public BasicQTEditor ( ) throws QTException {&lt;br /&gt;
       super (&amp;quot;BasicQTEditor&amp;quot;);&lt;br /&gt;
       setLayout (new BorderLayout( ));&lt;br /&gt;
       QTSessionCheck.check( );&lt;br /&gt;
       movie = new Movie(StdQTConstants.newMovieActive);&lt;br /&gt;
       controller = new MovieController (movie);&lt;br /&gt;
       controller.enableEditing(true);&lt;br /&gt;
       doMyLayout( );&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   /** file-based constructor for opening movies&lt;br /&gt;
    */&lt;br /&gt;
   public BasicQTEditor (QTFile file) throws QTException {&lt;br /&gt;
       super (&amp;quot;BasicQTEditor&amp;quot;);&lt;br /&gt;
       setLayout (new BorderLayout( ));&lt;br /&gt;
       QTSessionCheck.check( );&lt;br /&gt;
       OpenMovieFile omf = OpenMovieFile.asRead (file);&lt;br /&gt;
       movie = Movie.fromFile (omf);&lt;br /&gt;
       controller = new MovieController (movie);&lt;br /&gt;
       controller.enableEditing(true);&lt;br /&gt;
       doMyLayout( );&lt;br /&gt;
   }&lt;br /&gt;
   /** gets component from controller, makes menus&lt;br /&gt;
    */&lt;br /&gt;
   private void doMyLayout( ) throws QTException {&lt;br /&gt;
       // add movie component&lt;br /&gt;
       QTComponent qtc =&lt;br /&gt;
           QTFactory.makeQTComponent (controller);&lt;br /&gt;
       comp = qtc.asComponent( );&lt;br /&gt;
       add (comp, BorderLayout.CENTER);&lt;br /&gt;
       // file menu&lt;br /&gt;
       fileMenu = new Menu (&amp;quot;File&amp;quot;);&lt;br /&gt;
       newItem = new MenuItem (&amp;quot;New Movie&amp;quot;);&lt;br /&gt;
       newItem.addActionListener (this);&lt;br /&gt;
       fileMenu.add (newItem);&lt;br /&gt;
       openItem = new MenuItem (&amp;quot;Open Movie...&amp;quot;);&lt;br /&gt;
       openItem.addActionListener (this);&lt;br /&gt;
       fileMenu.add (openItem);&lt;br /&gt;
       closeItem = new MenuItem (&amp;quot;Close&amp;quot;);&lt;br /&gt;
       closeItem.addActionListener (this);&lt;br /&gt;
       fileMenu.add (closeItem);&lt;br /&gt;
       fileMenu.addSeparator( );&lt;br /&gt;
       quitItem = new MenuItem (&amp;quot;Quit&amp;quot;);&lt;br /&gt;
       quitItem.addActionListener (this);&lt;br /&gt;
       fileMenu.add(quitItem);&lt;br /&gt;
       // edit menu&lt;br /&gt;
       editMenu = new Menu (&amp;quot;Edit&amp;quot;);&lt;br /&gt;
       copyItem = new MenuItem (&amp;quot;Copy&amp;quot;);&lt;br /&gt;
       copyItem.addActionListener(this);&lt;br /&gt;
       editMenu.add(copyItem);&lt;br /&gt;
       cutItem = new MenuItem (&amp;quot;Cut&amp;quot;);&lt;br /&gt;
       cutItem.addActionListener(this);&lt;br /&gt;
       editMenu.add(cutItem);&lt;br /&gt;
       pasteItem = new MenuItem (&amp;quot;Paste&amp;quot;);&lt;br /&gt;
       pasteItem.addActionListener(this);&lt;br /&gt;
       editMenu.add(pasteItem);&lt;br /&gt;
       // make menu bar&lt;br /&gt;
       MenuBar bar = new MenuBar( );&lt;br /&gt;
       bar.add (fileMenu);&lt;br /&gt;
       bar.add (editMenu);&lt;br /&gt;
       setMenuBar (bar);&lt;br /&gt;
       // add close-button handling&lt;br /&gt;
       addWindowListener (new WindowAdapter( ) {&lt;br /&gt;
               public void windowClosing (WindowEvent e) {&lt;br /&gt;
                   doClose( );&lt;br /&gt;
               }&lt;br /&gt;
           });&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   /** handles menu actions&lt;br /&gt;
    */&lt;br /&gt;
   public void actionPerformed (ActionEvent e) {&lt;br /&gt;
       Object source = e.getSource( );&lt;br /&gt;
       try {&lt;br /&gt;
           if (source =  = quitItem) doQuit( );&lt;br /&gt;
           else if (source =  = openItem) doOpen( );&lt;br /&gt;
           else if (source =  = closeItem) doClose( );&lt;br /&gt;
           else if (source =  = newItem) doNew( );&lt;br /&gt;
           else if (source =  = copyItem) doCopy( );&lt;br /&gt;
           else if (source =  = cutItem) doCut( );&lt;br /&gt;
           else if (source =  = pasteItem) doPaste( );&lt;br /&gt;
       } catch (QTException qte) {&lt;br /&gt;
           qte.printStackTrace( );&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public void doQuit( ) {&lt;br /&gt;
       System.exit(0);&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public void doNew( ) throws QTException {&lt;br /&gt;
       makeNewAndShow( );&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public void doOpen( ) throws QTException {&lt;br /&gt;
       QTFile file =&lt;br /&gt;
           QTFile.standardGetFilePreview (QTFile.kStandardQTFileTypes);&lt;br /&gt;
       Frame f = new BasicQTEditor (file);&lt;br /&gt;
       f.pack( );&lt;br /&gt;
       if (newFrameX &amp;gt;= 0)&lt;br /&gt;
           f.setLocation (newFrameX+=16, newFrameY+=16);&lt;br /&gt;
       f.setVisible(true);&lt;br /&gt;
       windowCount++;&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public void doClose( ) {&lt;br /&gt;
       setVisible(false);&lt;br /&gt;
       dispose( );&lt;br /&gt;
       // quit if no windows now showing&lt;br /&gt;
       if (--windowCount =  = 0)&lt;br /&gt;
           doQuit( );&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public void doCopy( ) throws QTException {&lt;br /&gt;
       Movie copied = controller.copy( );&lt;br /&gt;
       copied.putOnScrap(0);&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public void doCut( ) throws QTException {&lt;br /&gt;
       Movie cut = controller.cut( );&lt;br /&gt;
       cut.putOnScrap(0);&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public void doPaste( ) throws QTException {&lt;br /&gt;
       controller.paste( );&lt;br /&gt;
       pack( );&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
 /** Force frame's size to respect movie size&lt;br /&gt;
    */&lt;br /&gt;
   public Dimension getPreferredSize( ) {&lt;br /&gt;
       System.out.println (&amp;quot;getPreferredSize&amp;quot;);&lt;br /&gt;
       if (controller =  = null)&lt;br /&gt;
           return new Dimension (0,0);&lt;br /&gt;
       try {&lt;br /&gt;
           QDRect contRect = controller.getBounds( );&lt;br /&gt;
           Dimension compDim = comp.getPreferredSize( );&lt;br /&gt;
           if (contRect.getHeight( ) &amp;gt; compDim.height) {&lt;br /&gt;
               return new Dimension (contRect.getWidth( ) +&lt;br /&gt;
                                     getInsets( ).left +&lt;br /&gt;
                                     getInsets( ).right,&lt;br /&gt;
                                     contRect.getHeight( ) +&lt;br /&gt;
                                     getInsets( ).top +&lt;br /&gt;
                                     getInsets( ).bottom);&lt;br /&gt;
  &lt;br /&gt;
           } else {&lt;br /&gt;
               return new Dimension (compDim.width +&lt;br /&gt;
                                     getInsets( ).left +&lt;br /&gt;
                                     getInsets( ).right,&lt;br /&gt;
                                     compDim.height +&lt;br /&gt;
                                     getInsets( ).top +&lt;br /&gt;
                                     getInsets( ).bottom);&lt;br /&gt;
  &lt;br /&gt;
           }&lt;br /&gt;
       } catch (QTException qte) {&lt;br /&gt;
           return new Dimension (0,0);&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   /** opens a single new movie window&lt;br /&gt;
    */&lt;br /&gt;
   public static void main (String[  ] args) {&lt;br /&gt;
       try {&lt;br /&gt;
           Frame f = makeNewAndShow( );&lt;br /&gt;
           // note its x, y for future calls&lt;br /&gt;
           newFrameX = f.getLocation( ).x;&lt;br /&gt;
           newFrameY = f.getLocation( ).y;&lt;br /&gt;
       } catch (Exception e) {&lt;br /&gt;
           e.printStackTrace( );&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   /** creates &amp;quot;new&amp;quot; movie frame, packs and shows.&lt;br /&gt;
       used by main( ) and &amp;quot;new&amp;quot;&lt;br /&gt;
    */&lt;br /&gt;
   private static Frame makeNewAndShow( )&lt;br /&gt;
       throws QTException {&lt;br /&gt;
       Frame f = new BasicQTEditor( );&lt;br /&gt;
       f.pack( );&lt;br /&gt;
       if (newFrameX &amp;gt;= 0)&lt;br /&gt;
           f.setLocation (newFrameX+=16, newFrameY+=16);&lt;br /&gt;
       f.setVisible(true);&lt;br /&gt;
       windowCount++;&lt;br /&gt;
       return f;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''With the downloaded book code, compile and run this with ant run-ch03-basicqteditor''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[QuickTime for Java: A Developer's Notebook/Editing Movies#quicktimejvaadn-CHP-3-FIG-1|Figure 3-1]] shows the &amp;lt;tt&amp;gt;BasicQTEditor&amp;lt;/tt&amp;gt; class in action, with two windows open. The window on the left is the original empty movie window, with the user about to paste in some contents. The window on the right is a movie that was opened from a file. Note the small stretch of darker gray in the timeline, under the play head, which indicates the selected segment that was copied from the movie to the system clipboard.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-3-FIG-1&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 3-1. BasicQTEditor with two movies open'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_3_tt39.png|BasicQTEditor with two movies open]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also note that when running in Windows, as pictured here, the menus are inside the windows. On Mac OS X, the usage of AWT means the File and Edit menus will be at the top of the screen in the Mac's &amp;quot;One True Menu Bar.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
One usability note: for simplicity, I haven't tried to make this particularly smart about what the user &amp;quot;really wants,&amp;quot; and that can be bad on the paste . The paste will replace whatever is selected in the target movie, and if there is no selection, it will paste to the beginning of the movie. It's probably more typical to add clips either to the end of the movie, or to the current time as indicated by the play head (i.e., to behave as if a lack of a selection should be interpreted as a zero-length selection beginning and ending at the movie's current time). It's simple enough to add this kind of intelligence to &amp;lt;tt&amp;gt;doPaste()&amp;lt;/tt&amp;gt; and find a behavior that feels better.&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
This is a big example, so here's an overview.&lt;br /&gt;
&lt;br /&gt;
The no-arg constructor, &amp;lt;tt&amp;gt;BasicQTEditor( )&amp;lt;/tt&amp;gt;, initializes QuickTime with [[QuickTime for Java: A Developer's Notebook/Getting Up and Running with QuickTime for Java|Chapter 1]]s &amp;lt;tt&amp;gt;QTSessionCheck&amp;lt;/tt&amp;gt;, then creates a new empty &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;, gets a &amp;lt;tt&amp;gt;MovieController&amp;lt;/tt&amp;gt; for it, and calls &amp;lt;tt&amp;gt;doMyLayout&amp;lt;/tt&amp;gt;. A second constructor, &amp;lt;tt&amp;gt;BasicQTEditor (QTFile)&amp;lt;/tt&amp;gt;, is essentially identical, except that instead of creating an empty movie, it gets a movie from the provided &amp;lt;tt&amp;gt;QTFile&amp;lt;/tt&amp;gt;. The &amp;lt;tt&amp;gt;movie&amp;lt;/tt&amp;gt; and the &amp;lt;tt&amp;gt;controller&amp;lt;/tt&amp;gt; instance variables are used by many methods throughout the application.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;doMyLayout( )&amp;lt;/tt&amp;gt; method sets up the menus and their &amp;lt;tt&amp;gt;ActionListeners&amp;lt;/tt&amp;gt; and reminds us that building GUIs in code is a pain.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;actionPerformed (ActionEvent)&amp;lt;/tt&amp;gt; is used to farm out method calls from clicks on the various menu items.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;doQuit( )&amp;lt;/tt&amp;gt; is a trivial call to &amp;lt;tt&amp;gt;System.exit(0)&amp;lt;/tt&amp;gt;. Remember that the &amp;lt;tt&amp;gt;QTSessionCheck&amp;lt;/tt&amp;gt; call has set up a shutdown handler to close QuickTime when Java goes away.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;doNew( )&amp;lt;/tt&amp;gt; trivially calls &amp;lt;tt&amp;gt;makeNewAndShow()&amp;lt;/tt&amp;gt;, which is a convenience method to call the no-arg constructor (which creates an empty &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;), pack the frame, and move it down and to the right 16 pixels from the last place a new window was created.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tip&amp;quot;&amp;gt;&lt;br /&gt;
'''Tip'''&lt;br /&gt;
&lt;br /&gt;
Note that there's nothing here to keep new windows from going off-screen if the user creates enough of them. In a more polished application, you'd check the proposed x and y against the screen size reported by the AWT's &amp;lt;tt&amp;gt;Toolkit.getScreenSize()&amp;lt;/tt&amp;gt; .&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;doOpen( )&amp;lt;/tt&amp;gt; brings up a file-open dialog and calls the file-aware constructor. It then &amp;lt;tt&amp;gt;pack( )&amp;lt;/tt&amp;gt; s the window and positions it in the same way &amp;lt;tt&amp;gt;makeNewAndShow()&amp;lt;/tt&amp;gt; does.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;doClose( )&amp;lt;/tt&amp;gt; closes the frame and, if it is the last open window, quits the application via &amp;lt;tt&amp;gt;doQuit( )&amp;lt;/tt&amp;gt; (yes, this is Windows-like behavior, as opposed to the typical Mac application which can hang around with no open windows).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;doCopy( )&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;doCut( )&amp;lt;/tt&amp;gt; are practically identical, and each needs only two lines to do its thing. They make a call to the &amp;lt;tt&amp;gt;MovieController&amp;lt;/tt&amp;gt; to cut or copy the current selection and return the result as a new &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;. Then they put this movie on the system clipboard with the movie's &amp;lt;tt&amp;gt;putOnScrap( )&amp;lt;/tt&amp;gt; call.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;doPaste( )&amp;lt;/tt&amp;gt; is even simpler: it just calls the controller's &amp;lt;tt&amp;gt;paste( )&amp;lt;/tt&amp;gt; method and then re-&amp;lt;tt&amp;gt;pack( )&amp;lt;/tt&amp;gt;s the window.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;getPreferredSize()&amp;lt;/tt&amp;gt; method overrides the default by indicating that the window needs to be large enough to contain the movie, its control bar, and any insets that might be set. This is why you should &amp;lt;tt&amp;gt;pack( )&amp;lt;/tt&amp;gt; after each paste: the original empty movie has no size other than its control bar, so when you paste into it, the size of the movie (and thus its controller) changes to accommodate the pasted contents, and you need the frame to adjust to that.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;warning&amp;quot;&amp;gt;&lt;br /&gt;
'''Warning'''&lt;br /&gt;
&lt;br /&gt;
This really should be taken care of automatically in Java, because the use of a &amp;lt;tt&amp;gt;BorderLayout&amp;lt;/tt&amp;gt; should allow the contents to achieve their preferred size on a &amp;lt;tt&amp;gt;pack( )&amp;lt;/tt&amp;gt;. Unfortunately, on Mac OS X, the &amp;lt;tt&amp;gt;QTComponent&amp;lt;/tt&amp;gt; exhibits a bizarre behavior where its preferred size is set ''once'', when it's packed, and never again. So, a component built from an empty movie always thinks it's supposed to be zero pixels high by 160 pixels wide, even if you paste in contents much larger than that. Fixing this reveals the opposite problem on Windows: sometimes there's a good preferred size and a zero-height controller bound. The version here prefers whichever set of bounds has a greater height.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...that weird play head? That is odd, isn't it? The call to &amp;lt;tt&amp;gt;enableEditing(true)&amp;lt;/tt&amp;gt; has changed the play head ball to an hourglass shape. [[QuickTime for Java: A Developer's Notebook/Editing Movies#quicktimejvaadn-CHP-3-FIG-2|Figure 3-2]] shows it at an enlarged size.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-3-FIG-2&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 3-2. MovieController scrubber bar with editing enabled'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_3_tt40.png|MovieController scrubber bar with editing enabled]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
My guess is that the shape is supposed to help you select the exact point for making a selection, instead of burying it under the center of the ball. That said, there's a reason you don't see this elsewhere: this default widget isn't terribly well-suited to editing. The QuickTime Player application that comes with QuickTime has a custom controller widget with two little triangles under the timeline to mark in and out points. But that control, like this one, shares the flaw that the accuracy of your edit is limited by the on-screen size of your movie. More serious editing applications, like Premiere and Final Cut Pro, have custom GUI components for editing, usually based on a timeline that can be &amp;quot;zoomed&amp;quot; to an arbitrary accuracy. Of course, one could do the same with AWT or Swing, tracking &amp;lt;tt&amp;gt;MouseEvent&amp;lt;/tt&amp;gt;s, &amp;lt;tt&amp;gt;paint()&amp;lt;/tt&amp;gt;ing as necessary, and making programmatic calls to QTJ to perform actions.&lt;br /&gt;
&lt;br /&gt;
== Performing &amp;quot;Low-Level&amp;quot; Edits ==&lt;br /&gt;
&lt;br /&gt;
Low-level edits are a separate set of editing calls that don't involve the clipboard or selection metaphors. They're called &amp;quot;low level&amp;quot; because instead of operating at the conceptual level of &amp;quot;paste the contents of the clipboard into the user's current selection,&amp;quot; they work at the level of &amp;quot;insert a segment from movie M1, ranging from time A to time B, into movie M2 at time C.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''By way of comparison, although QuickTime has two sets of editing functions, Sun's Java Media Framework has no editing API at all''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
This version reimplements &amp;lt;tt&amp;gt;doCopy( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;doCut( )&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;doPaste( )&amp;lt;/tt&amp;gt; to use low-level editing calls on the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; instead of cut/copy/paste-type calls on the &amp;lt;tt&amp;gt;MovieController&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
First, &amp;lt;tt&amp;gt;LowLevelQTEditor&amp;lt;/tt&amp;gt; needs a static &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;, called &amp;lt;tt&amp;gt;copiedMovie&amp;lt;/tt&amp;gt;, to keep track of what's on its virtual &amp;quot;clipboard&amp;quot; so that it can be shared across the new &amp;lt;tt&amp;gt;doCopy( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;doCut()&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;doPaste( )&amp;lt;/tt&amp;gt; methods:&lt;br /&gt;
&lt;br /&gt;
 public void doCopy( ) throws QTException {&lt;br /&gt;
       copiedMovie = new Movie( );&lt;br /&gt;
       TimeInfo selection = movie.getSelection( );&lt;br /&gt;
       movie.insertSegment (copiedMovie,&lt;br /&gt;
                            selection.time,&lt;br /&gt;
                            selection.duration,&lt;br /&gt;
                            0);&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
 public void doCut( ) throws QTException {&lt;br /&gt;
       copiedMovie = new Movie( );&lt;br /&gt;
       TimeInfo selection = movie.getSelection( );&lt;br /&gt;
       movie.insertSegment (copiedMovie,&lt;br /&gt;
                            selection.time,&lt;br /&gt;
                            selection.duration,&lt;br /&gt;
                            0);&lt;br /&gt;
       movie.deleteSegment (selection.time,&lt;br /&gt;
                            selection.duration);&lt;br /&gt;
       controller.movieChanged( );&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
 public void doPaste( ) throws QTException {&lt;br /&gt;
       if (copiedMovie =  = null)&lt;br /&gt;
           return;&lt;br /&gt;
       copiedMovie.insertSegment (movie,&lt;br /&gt;
                                  0,&lt;br /&gt;
                                  copiedMovie.getDuration( ),&lt;br /&gt;
                                  movie.getSelection( ).time);&lt;br /&gt;
       controller.movieChanged( );&lt;br /&gt;
       pack( );&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''You can make ant compile and run this example with ant run-ch03-lowlevelqteditor''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The only thing the user might see as being different or odd in this example is that the cut or copied clip does not get put on the system clipboard because low-level edits don't touch the clipboard.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tip&amp;quot;&amp;gt;&lt;br /&gt;
'''Tip'''&lt;br /&gt;
&lt;br /&gt;
For what it's worth, this example was intended originally to be a drag-and-drop demo, for which these low-level, segment-oriented calls are particularly well-suited. Unfortunately, the QTComponent won't generate an AWT &amp;quot;drag gesture.&amp;quot; I suppose it would be a little unnatural to drag the current image as a metaphor for copying a segment of a movie. Anyway, if you decide to do your own controller GUI, you can use this low-level stuff for your drag-and-drop.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;doCut( )&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;doCopy( )&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;doPaste( )&amp;lt;/tt&amp;gt; methods all call &amp;lt;tt&amp;gt;Movie.insertSegment()&amp;lt;/tt&amp;gt; ; either to put some part of a source movie into the clipboard-like &amp;lt;tt&amp;gt;copiedMovie&amp;lt;/tt&amp;gt; or to put the &amp;lt;tt&amp;gt;copiedMovie&amp;lt;/tt&amp;gt; into the target movie. This method takes four arguments:&lt;br /&gt;
&lt;br /&gt;
* The &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; to insert into&lt;br /&gt;
* The start time of the segment, in the movie's time scale&lt;br /&gt;
* The end time of the segment, in the movie's time scale&lt;br /&gt;
* The time in the target movie when the segment should be inserted&lt;br /&gt;
&lt;br /&gt;
In the case of a cut, the &amp;lt;tt&amp;gt;deleteSegment()&amp;lt;/tt&amp;gt; call removes the segment that was just copied out. This method simply takes the beginning and end times of the segment to delete.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Time scales are covered in [[QuickTime for Java: A Developer's Notebook/Playing Movies|Chapter 2]], in the section [[QuickTime for Java: A Developer's Notebook/Playing Movies#Showing a Movie's Current Time|Section 2.5]].''&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;tt&amp;gt;doPaste( )&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;doCut( )&amp;lt;/tt&amp;gt; methods, a call to &amp;lt;tt&amp;gt;MovieController.movieChanged( )&amp;lt;/tt&amp;gt; lets the controller know that the movie was changed in a way that didn't involve a method call on the controller, and that the controller now needs to update itself to adjust to the changed duration, current time, etc.&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...any other low-level calls? There is an interesting method in the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; class, called &amp;lt;tt&amp;gt;scaleSegment()&amp;lt;/tt&amp;gt; , which changes the duration of a segment, meaning it either slows it down or speeds it up to suit the specified duration. This could be handy for creating a &amp;quot; slow-motion&amp;quot; or &amp;quot;fast-motion&amp;quot; effect from a normal-speed source, or stretching it out to fit a piece of audio.&lt;br /&gt;
&lt;br /&gt;
== Undoing an Edit ==&lt;br /&gt;
&lt;br /&gt;
Critical to any kind of editing is the ability to back out of a change that had unintended or undesirable effects. Fortunately, controller-based cuts and pastes can be undone with some fairly simple calls.&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;UndoableQTEditor&amp;lt;/tt&amp;gt; builds on the original &amp;lt;tt&amp;gt;BasicQTEditor&amp;lt;/tt&amp;gt; by adding an &amp;quot;undo&amp;quot; menu item. The &amp;lt;tt&amp;gt;doUndo( )&amp;lt;/tt&amp;gt; method it calls has an utterly trivial implementation:&lt;br /&gt;
&lt;br /&gt;
 public void doUndo( ) throws QTException {&lt;br /&gt;
   controller.undo( );&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Compile and run this example with ant run-ch03-undoableqteditor''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
With a simple call to &amp;lt;tt&amp;gt;MovieController.undo()&amp;lt;/tt&amp;gt; , the program gained the ability to undo a cut or paste, or any other destructive change made through the controller.&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...multiple undoes? Or redoes? Ah, there's the rub. Hit undo again and the cut or paste is redone, in effect undoing the undo.&lt;br /&gt;
&lt;br /&gt;
Sadly, this is your dad's &amp;quot;undo&amp;quot;...the undo from back in 1990, when a single level of undo was a pretty cool thing. Today, when users expect to perform multiple destructive actions with impunity, it's not too impressive.&lt;br /&gt;
&lt;br /&gt;
== Undoing and Redoing Multiple Edits ==&lt;br /&gt;
&lt;br /&gt;
Fortunately, QTJ offers a unique opportunity to combine Swing's thoughtfully designed undo API, &amp;lt;tt&amp;gt;javax.swing.undo&amp;lt;/tt&amp;gt;, with QuickTime's support for reverting a movie to a previous state. Combined, these features provide the ability to support a long trail of undoes and redoes.&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;RedoableQTEditor&amp;lt;/tt&amp;gt; again builds on &amp;lt;tt&amp;gt;BasicQTEditor&amp;lt;/tt&amp;gt;, adding a Swing &amp;lt;tt&amp;gt;UndoManager&amp;lt;/tt&amp;gt; that is used by both the &amp;lt;tt&amp;gt;doUndo( )&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;doRedo( )&amp;lt;/tt&amp;gt; methods:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Compile and run this example with ant run-ch03-redoableqteditor''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 public void doUndo( ) throws QTException {&lt;br /&gt;
   if (! undoanager.canUndo( )) {&lt;br /&gt;
       System.out.println (&amp;quot;can't undo&amp;quot;);&lt;br /&gt;
       return;&lt;br /&gt;
   }&lt;br /&gt;
   undoManager.undo( );&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 public void doRedo( ) throws QTException {&lt;br /&gt;
   if (! undoManager.canRedo( )) {&lt;br /&gt;
       System.out.println (&amp;quot;can't redo&amp;quot;);&lt;br /&gt;
       return;&lt;br /&gt;
   }&lt;br /&gt;
   undoManager.redo( );&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The information about a destructive edit is encapsulated by an inner class called &amp;lt;tt&amp;gt;QTEdit&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 class QTEdit extends AbstractUndoableEdit {&lt;br /&gt;
   MovieEditState previousState;&lt;br /&gt;
   MovieEditState newState;&lt;br /&gt;
   String name;&lt;br /&gt;
   public QTEdit (MovieEditState pState,&lt;br /&gt;
                  MovieEditState nState,&lt;br /&gt;
                  String n) {&lt;br /&gt;
       previousState = pState;&lt;br /&gt;
       newState = nState;&lt;br /&gt;
       this.name = n;&lt;br /&gt;
   }&lt;br /&gt;
   public String getPresentationName( ) {&lt;br /&gt;
       return name;&lt;br /&gt;
   }&lt;br /&gt;
   public void redo( ) throws CannotRedoException {&lt;br /&gt;
       super.redo( );&lt;br /&gt;
       try {&lt;br /&gt;
           movie.useEditState (newState);&lt;br /&gt;
           controller.movieChanged( );&lt;br /&gt;
       } catch (QTException qte) {&lt;br /&gt;
           qte.printStackTrace( );&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
   public void undo ( ) throws CannotUndoException {&lt;br /&gt;
       super.undo( );&lt;br /&gt;
       try {&lt;br /&gt;
           movie.useEditState (previousState);&lt;br /&gt;
           controller.movieChanged( );&lt;br /&gt;
       } catch (QTException qte) {&lt;br /&gt;
           qte.printStackTrace( );&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
   public void die( ) {&lt;br /&gt;
       previousState = null;&lt;br /&gt;
       newState = null;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Finally, &amp;lt;tt&amp;gt;doCut( )&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;doPaste()&amp;lt;/tt&amp;gt; are amended to create suitable &amp;lt;tt&amp;gt;QTEdit&amp;lt;/tt&amp;gt;s and hand them to the &amp;lt;tt&amp;gt;UndoManager&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 public void doCut( ) throws QTException {&lt;br /&gt;
   MovieEditState oldState = movie.newEditState( );&lt;br /&gt;
   Movie cut = movie.cutSelection( );&lt;br /&gt;
   MovieEditState newState = movie.newEditState( );&lt;br /&gt;
   QTEdit edit = new QTEdit (oldState, newState, &amp;quot;Cut&amp;quot;);&lt;br /&gt;
   undoManager.addEdit (edit);&lt;br /&gt;
   cut.putOnScrap(0);&lt;br /&gt;
   controller.movieChanged( );&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 public void doPaste( ) throws QTException {&lt;br /&gt;
   MovieEditState oldState = movie.newEditState( );&lt;br /&gt;
   Movie pasted = Movie.fromScrap(0);&lt;br /&gt;
   movie.pasteSelection (pasted);&lt;br /&gt;
   MovieEditState newState = movie.newEditState( );&lt;br /&gt;
   QTEdit edit = new QTEdit (oldState, newState, &amp;quot;Paste&amp;quot;);&lt;br /&gt;
   undoManager.addEdit (edit);&lt;br /&gt;
   controller.movieChanged( );&lt;br /&gt;
   pack( );&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
When clicked, the Undo menu item now undoes a cut or paste. Redo redoes the edit, while a second &amp;quot;undo&amp;quot; will undo the previous edit, etc.&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
Obviously, the fun parts involve the destructive actions and how they save enough information to be undoable and redoable. In each case, they call &amp;lt;tt&amp;gt;Movie.newEditState()&amp;lt;/tt&amp;gt; to create a &amp;lt;tt&amp;gt;MovieEditState&amp;lt;/tt&amp;gt; , a QuickTime object that contains the information needed to revert the movie to the current state at some point in the future. Then they do the destructive action and create another &amp;lt;tt&amp;gt;MovieEditState&amp;lt;/tt&amp;gt; to represent the post-edit state. These objects are passed to the &amp;lt;tt&amp;gt;QTEdit&amp;lt;/tt&amp;gt;, which is then sent to the &amp;lt;tt&amp;gt;UndoManager&amp;lt;/tt&amp;gt; to join its stack of edits.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When the &amp;lt;tt&amp;gt;UndoManager.undo()&amp;lt;/tt&amp;gt; method is called, it takes the first undoable edit, if there is one, and calls its &amp;lt;tt&amp;gt;undo( )&amp;lt;/tt&amp;gt; method. In this case, that means the manager is calling the &amp;lt;tt&amp;gt;QTEdit.undo( )&amp;lt;/tt&amp;gt; method, which takes the pre-edit &amp;lt;tt&amp;gt;MovieEditState&amp;lt;/tt&amp;gt; and passes it to &amp;lt;tt&amp;gt;Movie.useEditState( )&amp;lt;/tt&amp;gt; to return the movie to that state. Similarly, a post-undo call to &amp;lt;tt&amp;gt;QTEdit.redo( )&amp;lt;/tt&amp;gt; also uses &amp;lt;tt&amp;gt;useEditState( )&amp;lt;/tt&amp;gt; to get to the post-edit state.&lt;br /&gt;
&lt;br /&gt;
== Saving a Movie to a File ==&lt;br /&gt;
&lt;br /&gt;
Once a user has performed a number of edits and has a finished project, she presumably needs to save the movie to disk. In QuickTime, many different actions can be thought of as &amp;quot;saving&amp;quot; a movie. Perhaps the simplest and most flexible option is to let the user decide.&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;SaveableQTEditor&amp;lt;/tt&amp;gt; uses a &amp;lt;tt&amp;gt;QTFile&amp;lt;/tt&amp;gt; to keep track of where a movie was loaded from (&amp;lt;tt&amp;gt;null&amp;lt;/tt&amp;gt; in the case of a new movie). This is used by the &amp;lt;tt&amp;gt;doSave( )&amp;lt;/tt&amp;gt; method to indicate where the saved file goes:&lt;br /&gt;
&lt;br /&gt;
 public void doSave( ) throws QTException {&lt;br /&gt;
   // if no existing file, then prompt for one&lt;br /&gt;
   if (file =  = null) {&lt;br /&gt;
       file = new QTFile (new File (&amp;quot;simplemovie.mov&amp;quot;));&lt;br /&gt;
   }&lt;br /&gt;
   int flags = StdQTConstants.createMovieFileDeleteCurFile |&lt;br /&gt;
       StdQTConstants.createMovieFileDontCreateResFile |&lt;br /&gt;
       StdQTConstants.showUserSettingsDialog;&lt;br /&gt;
   movie.convertToFile (file, // file&lt;br /&gt;
                        StdQTConstants.kQTFileTypeMovie, // filetype,&lt;br /&gt;
                        StdQTConstants.kMoviePlayer, // creator&lt;br /&gt;
                        IOConstants.smSystemScript, // scriptTag&lt;br /&gt;
                        flags);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Compile and run this example with ant run-ch03-saveableqteditor''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When the user hits the Save menu item, she'll see the QuickTime Save As dialog as shown in [[QuickTime for Java: A Developer's Notebook/Editing Movies#quicktimejvaadn-CHP-3-FIG-3|Figure 3-3]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-3-FIG-3&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 3-3. QuickTime Save As dialog'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_3_tt47.png|QuickTime Save As dialog]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This dialog's Export selector gives the user four choices:&lt;br /&gt;
&lt;br /&gt;
;Movie&lt;br /&gt;
: Saves a QuickTime ''reference movie'' , a tiny (typically 4 or 8 KB) file that contains just references (pointers) to the media in their original locations&lt;br /&gt;
;Movie, self-contained&lt;br /&gt;
: Copies all the media, in their original encodings, into a new QuickTime movie file&lt;br /&gt;
;Movie to Hinted Movie&lt;br /&gt;
: Creates a self-contained movie but lets the user adjust the hinting settings for use in a streaming server&lt;br /&gt;
;Movie to QuickTime Movie&lt;br /&gt;
: Creates a self-contained movie, but lets the user choose different compressors and settings to re-encode the audio and video&lt;br /&gt;
&lt;br /&gt;
Some of these options give the user additional choices. Saving a &amp;quot;self-contained&amp;quot; movie presents an Options... button that lets the user specify the audio and video codecs to be used in the saved movie, their quality and bitrate settings, etc. A &amp;quot;Use&amp;quot; pop up contains canned settings with appropriate choices for distributing the movie on CD-ROM, over dial-up, etc.&lt;br /&gt;
&lt;br /&gt;
Once the user clicks Save, the program saves the movie to disk. This is a very fast operation for the reference movie option and a potentially slow operation for the other options because the media might be re-encoded into a new format as part of the save.&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
The key is the &amp;lt;tt&amp;gt;Movie.convertToFile()&amp;lt;/tt&amp;gt; method. The version shown here takes five parameters:&lt;br /&gt;
&lt;br /&gt;
* The &amp;lt;tt&amp;gt;QTFile&amp;lt;/tt&amp;gt; to save to.&lt;br /&gt;
* An &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; to represent the old Mac OS file &amp;quot;type.&amp;quot; Use the constant &amp;lt;tt&amp;gt;kQTFileTypeMovie&amp;lt;/tt&amp;gt; , which gives it the QuickTime movie type &amp;lt;tt&amp;gt;moov&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* An &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; to represent the old Mac OS file &amp;quot;creator.&amp;quot; The boilerplate option is &amp;lt;tt&amp;gt;kMoviePlayer&amp;lt;/tt&amp;gt; , which associates it with the default QuickTime Player application.&lt;br /&gt;
* An &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; to represent the old Mac OS &amp;quot;scriptTag,&amp;quot; which indicates what kind of &amp;quot;script system&amp;quot; (character encoding, writing direction, etc.) is to be used. Common practice is to use the constant &amp;lt;tt&amp;gt;smSystemScript&amp;lt;/tt&amp;gt; to use whatever the operating system's current script is.&lt;br /&gt;
* Behavior flags to affect the save operation, logically &amp;lt;tt&amp;gt;OR&amp;lt;/tt&amp;gt;ed together. The most important flag for this example is the &amp;lt;tt&amp;gt;showUserSettingsDialog&amp;lt;/tt&amp;gt; ; without it, the program would silently save the file with Apple's ancient &amp;quot;Video&amp;quot; codec and uncompressed sound. This example also uses the flag &amp;lt;tt&amp;gt;createMovieFileDeleteCurFile&amp;lt;/tt&amp;gt; to delete any file already at the target location and &amp;lt;tt&amp;gt;createMovieFileDontCreateResFile&amp;lt;/tt&amp;gt; to force the file to exist in a single data &amp;quot;fork,&amp;quot; instead of using the old Mac OS' &amp;quot;resource&amp;quot; fork. This is required for making QuickTime movies that run on multiple platforms.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Most of the time, it's appropriate to use boilerplate code for things like type, creator, and system script, and not to have to read some ''Inside Macintosh'' book from 10 years ago''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...other interesting behavior flags? The docs for the native &amp;lt;tt&amp;gt;ConvertMovieToFile&amp;lt;/tt&amp;gt; function offer two that aren't shown here because they seem to indicate behavior that is already the default:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;movieFileSpecValid&amp;lt;/tt&amp;gt; indicates that the file passed in actually exists and should be shown as the default save location.&lt;br /&gt;
* &amp;lt;tt&amp;gt;movieToFileOnlyExport&amp;lt;/tt&amp;gt; restricts the dialog to showing only the data export components that are actually present.&lt;br /&gt;
&lt;br /&gt;
Can anything be done about the interminable wait when saving &amp;quot;Movie to QuickTime Movie&amp;quot;? One thing that helps is to provide a &amp;quot;progress function,&amp;quot; which provides a visual representation of the progress being made on the long save operation. You can set up the default progress function with a one-line call right before &amp;lt;tt&amp;gt;convertToFile()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 movie.setProgressProc( )&lt;br /&gt;
&lt;br /&gt;
This will bring up a progress dialog like the one shown in [[QuickTime for Java: A Developer's Notebook/Editing Movies#quicktimejvaadn-CHP-3-FIG-4|Figure 3-4]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-3-FIG-4&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 3-4. Default QuickTime progress dialog'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_3_tt49.png|Default QuickTime progress dialog]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; class also has a &amp;lt;tt&amp;gt;setProgressProc( )&amp;lt;/tt&amp;gt; method that takes a &amp;lt;tt&amp;gt;MovieProgress&amp;lt;/tt&amp;gt; object as a parameter. The idea here is that of a typical callback arrangement—during a long save, &amp;lt;tt&amp;gt;MovieProgress.execute()&amp;lt;/tt&amp;gt; is called repeatedly with four parameters: the movie being monitored, a &amp;quot;message&amp;quot; &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, a &amp;quot;what operation&amp;quot; &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;, and a &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt; that represents the percentage done on a scale from 0.0 to 1.0. Unfortunately, this interface has a couple of problems. First, the constants for the &amp;quot;message&amp;quot; aren't defined in QTJ (a few &amp;lt;tt&amp;gt;println&amp;lt;/tt&amp;gt;s here and there show that the values are &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; for start, &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; for update, and &amp;lt;tt&amp;gt;2&amp;lt;/tt&amp;gt; for done). More importantly, using this callback seems extremely unstable in QTJ 6.1—I find I often get an exception with an &amp;quot;Unknown Error Code,&amp;quot; and the movie doesn't save. So, maybe the default behavior is the safe choice for now.&lt;br /&gt;
&lt;br /&gt;
== Flattening a Movie ==&lt;br /&gt;
&lt;br /&gt;
Saving a movie can mean different things in QuickTime: saving a reference movie, saving a self-contained movie, or exporting to a different format. Typically, though, the idea of creating a self-contained movie is what users think of as &amp;quot;saving&amp;quot;—they want a single file that doesn't depend on any others, so they can put it on a server, email it to mom, etc. This process is called &amp;quot;flattening.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
&amp;quot;''Flattening&amp;quot; is also an old Mac OS term for turning a file with both a resource fork and a data fork into a single-fork file, suitable for use on non-Mac disk formats. In this book, we use &amp;quot;flatten&amp;quot; only in its QuickTime sense''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;FlattenableQTEditor&amp;lt;/tt&amp;gt; is similar to the &amp;lt;tt&amp;gt;SaveableQTEditor&amp;lt;/tt&amp;gt;, adding the menu item and its typical GUI and action-handling support. The flattening is done in a &amp;lt;tt&amp;gt;doFlatten( )&amp;lt;/tt&amp;gt; method:&lt;br /&gt;
&lt;br /&gt;
 public void doFlatten( ) throws QTException {&lt;br /&gt;
   // always attempts to save to a new location,&lt;br /&gt;
   // so prompt for filename&lt;br /&gt;
   FileDialog fd = new FileDialog (this,&lt;br /&gt;
                                   &amp;quot;Flatten...&amp;quot;,&lt;br /&gt;
                                   FileDialog.SAVE);&lt;br /&gt;
   fd.setVisible(true); // blocks&lt;br /&gt;
   if ((fd.getDirectory( ) =  = null) ||&lt;br /&gt;
       (fd.getFile( ) =  = null))&lt;br /&gt;
       return;&lt;br /&gt;
   QTFile flatFile =&lt;br /&gt;
       new QTFile (new File (fd.getDirectory( ),&lt;br /&gt;
                                    fd.getFile( )));&lt;br /&gt;
   if (flatFile.exists( )) {&lt;br /&gt;
       // JOptionPane is a bit of cheat-for-clarity here,&lt;br /&gt;
       // building a working AWT dialog would be punitive&lt;br /&gt;
       int choice = &lt;br /&gt;
           JOptionPane.showConfirmDialog (this,&lt;br /&gt;
                                            &amp;quot;Overwrite &amp;quot; + &lt;br /&gt;
                                         flatFile.getName( ) + &amp;quot;?&amp;quot;,&lt;br /&gt;
                                         &amp;quot;Flatten&amp;quot;,&lt;br /&gt;
                                         JOptionPane.OK_CANCEL_OPTION);&lt;br /&gt;
       if (choice != JOptionPane.OK_OPTION)&lt;br /&gt;
           return;&lt;br /&gt;
   }&lt;br /&gt;
   movie.flatten(StdQTConstants.flattenAddMovieToDataFork |&lt;br /&gt;
                 StdQTConstants.flattenForceMovieResourceBeforeMovieData, &lt;br /&gt;
                 flatFile, // fileOut&lt;br /&gt;
                 StdQTConstants.kMoviePlayer, // creator&lt;br /&gt;
                 IOConstants.smSystemScript, // scriptTag&lt;br /&gt;
                 StdQTConstants.createMovieFileDeleteCurFile, &lt;br /&gt;
                 StdQTConstants.movieInDataForkResID, // resID&lt;br /&gt;
                 null); // resName&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Compile and run this example with ant run-ch03-flattenableqt-editor''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When run, this creates a self-contained QuickTime movie file at the specified location, using whatever video and audio encoding was used in the original sources. This can result in some playback jitters if the user has mixed in different kinds of codecs—for example, pasting in some MPEG-4 video with some Sorenson 3 video. Flattening doesn't change encoding; it just resolves references and puts all the media into one file.&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;Movie.flatten( )&amp;lt;/tt&amp;gt; call creates the self-contained movie file, taking seven parameters to control its behavior:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Many of these are the same parameters used by Movie.convertToFile( ), covered in the previous lab''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Behavior flags for the flatten operation, logically &amp;lt;tt&amp;gt;OR&amp;lt;/tt&amp;gt;ed together. This example uses &amp;lt;tt&amp;gt;flattenAddMovieToDataFork&amp;lt;/tt&amp;gt; to create a single-fork movie that is more suitable for non-Mac operating systems. Using &amp;lt;tt&amp;gt;flattenForceMovieResourceBeforeMovieData&amp;lt;/tt&amp;gt; creates a &amp;quot;quick start&amp;quot; movie, so named because all its metadata comes before its media samples, which allows QuickTime to start playing the movie from a stream, even an http://-style URL, before all the data is loaded, because all the information QuickTime needs (what tracks are present, what size the video is, how loud the audio is, etc.) is loaded first.&lt;br /&gt;
* The file to flatten to.&lt;br /&gt;
* The Mac OS &amp;quot;creator,&amp;quot; typically &amp;lt;tt&amp;gt;kMoviePlayer&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* The Mac OS script tag, typically &amp;lt;tt&amp;gt;smSystemScript&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* The behavior flags that are used for the create file operation. &amp;lt;tt&amp;gt;createMovieFileDeleteCurFile&amp;lt;/tt&amp;gt; is used here to delete any file already at the target file location.&lt;br /&gt;
* Resource ID. For cross-platform reasons, it's usually best to use &amp;lt;tt&amp;gt;movieInDataForkResID&amp;lt;/tt&amp;gt; instead of old Mac OS-style resources.&lt;br /&gt;
* Resource name. Irrelevant here, so &amp;lt;tt&amp;gt;null&amp;lt;/tt&amp;gt; will do.&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...behavior flags for the flatten operation? The native docs for &amp;lt;tt&amp;gt;FlattenMovie&amp;lt;/tt&amp;gt; define a bunch, but the ones not used here are largely esoteric.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;flattenDontInterleaveFlatten&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Turns off &amp;quot;interleaving,&amp;quot; an optimization that mixes audio and video samples together so that they're easier to read at playback time (if a movie had a couple of megabytes' worth of video samples, followed by a couple of megabytes' worth of audio samples, the hard drive would have a difficult time zipping back and forth between the two; interleaving puts the samples for the same time period in the same place so that they can be read together). The default behavior is ''a good thing'', so this constant isn't used often.&lt;br /&gt;
;&amp;lt;tt&amp;gt;flattenActiveTracksOnly&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Doesn't include disabled tracks from the movie in the flattened file.&lt;br /&gt;
;&amp;lt;tt&amp;gt;flattenCompressMovieResource&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Compresses the movie's resource, and its organizational and metadata structure, if stored in the data fork. Like you care.&lt;br /&gt;
;&amp;lt;tt&amp;gt;flattenFSSpecPtrIsDataRefRecordPtr&amp;lt;/tt&amp;gt;&lt;br /&gt;
: This is meaningless in QTJ.&lt;br /&gt;
&lt;br /&gt;
== Saving a Movie with Dependencies ==&lt;br /&gt;
&lt;br /&gt;
The opposite of flattening is saving a movie with dependencies. In this type of a save, the resulting file just contains pointers to the sources of the media in each track. The file typically is tiny, usually just 8 KB or less.&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;RefSaveableQTEditor&amp;lt;/tt&amp;gt; example extends the &amp;lt;tt&amp;gt;FlattenableQTEditor&amp;lt;/tt&amp;gt; with a &amp;quot;Save w/Refs&amp;quot; menu item that calls &amp;lt;tt&amp;gt;doRefSave()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 public void doRefSave( ) throws QTException {&lt;br /&gt;
   // if no home file, then prompt for one&lt;br /&gt;
   if (file =  = null) {&lt;br /&gt;
       FileDialog fd = new FileDialog (this,&lt;br /&gt;
                                       &amp;quot;Save...&amp;quot;,&lt;br /&gt;
                                       FileDialog.SAVE);&lt;br /&gt;
       fd.setVisible(true); // blocks&lt;br /&gt;
       if ((fd.getDirectory( ) =  = null) ||&lt;br /&gt;
           (fd.getFile( ) =  = null))&lt;br /&gt;
           return;&lt;br /&gt;
       file = new QTFile (new File (fd.getDirectory( ),&lt;br /&gt;
                                    fd.getFile( )));&lt;br /&gt;
   }&lt;br /&gt;
   // save ref movie to file&lt;br /&gt;
   if (! file.exists( )) {&lt;br /&gt;
       file.createMovieFile(StdQTConstants.kMoviePlayer,&lt;br /&gt;
                            StdQTConstants.createMovieFileDontCreateResFile);&lt;br /&gt;
   }&lt;br /&gt;
   OpenMovieFile outFile =&lt;br /&gt;
       OpenMovieFile.asWrite(file);&lt;br /&gt;
   movie.updateResource (outFile,&lt;br /&gt;
                         StdQTConstants.movieInDataForkResID,&lt;br /&gt;
                         null);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Compile and run this example with ant run-ch03-refsaveableqt-editor''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When run, this creates a movie file that, despite its tiny size, behaves exactly like any other movie file. Double-click it and it will open in QuickTime Player, just like a self-contained movie. QuickTime completely isolates the user from the fact that the file contains nothing more than metadata and pointers to the source media files.&lt;br /&gt;
&lt;br /&gt;
Of course, there are limits to what QuickTime can do if those pointers cease to be valid. A user can move the source files and the movie still will play, but if the source movies are deleted, or if the reference movie is transferred to another system, QuickTime won't be able to resolve the references. This typically will result in a &amp;quot;searching...&amp;quot; dialog, followed by a dialog asking the user to locate the missing media, as shown in [[QuickTime for Java: A Developer's Notebook/Editing Movies#quicktimejvaadn-CHP-3-FIG-5|Figure 3-5]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-3-FIG-5&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 3-5. Unresolvable media reference dialog'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_3_tt52.png|Unresolvable media reference dialog]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
First, a call to &amp;lt;tt&amp;gt;QTFile.createMovieFile()&amp;lt;/tt&amp;gt; creates the file on disk, if it doesn't exist already. This method takes two parameters:&lt;br /&gt;
&lt;br /&gt;
* A Mac OS &amp;quot;creator,&amp;quot; for which &amp;lt;tt&amp;gt;StdQTConstants.kMoviePlayer&amp;lt;/tt&amp;gt; is the typical boilerplate value.&lt;br /&gt;
* Behavior flags. The constant &amp;lt;tt&amp;gt;createMovieFileDontCreateResFile&amp;lt;/tt&amp;gt; commonly is used to create cross-platform, single-fork files.&lt;br /&gt;
&lt;br /&gt;
With the file created, the reference movie data can be put into the file with the &amp;lt;tt&amp;gt;updateResource()&amp;lt;/tt&amp;gt; method. This method takes three parameters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''The name updateResource( ) seems to be another Classic Mac OS legacy that doesn't make much sense today''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* An &amp;lt;tt&amp;gt;OpenMovieFile&amp;lt;/tt&amp;gt;, opened for writing.&lt;br /&gt;
* A resource ID, for which the appropriately cross-platform, no-resource-fork value is &amp;lt;tt&amp;gt;movieInDataForkResId&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* An updated name for the resource; &amp;lt;tt&amp;gt;null&amp;lt;/tt&amp;gt; is appropriate here.&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...the fragility of reference movies? Because a reference movie is fragile, why would anyone ever create one? This technique is very handy for the saving state in editing applications because it allows the user to quickly save his edited movie without the I/O grinding of flattening. Editing, after all, can be seen as a process of arranging pointers to source materials; in the professional realm, a document called an ''Edit Decision List'' (EDL) is a simple list of &amp;quot;in&amp;quot; and &amp;quot;out&amp;quot; points from source media that you can use to produce the edited media. The reference movie is equivalent to the EDL: it's just a collection of pointers, with the nice advantage that it continues to behave as a normal QuickTime movie. So, the reference movie can be used to save the progress of the user's editing work, and when finished, a final self-contained movie can be generated via flattening or exporting (see [[QuickTime for Java: A Developer's Notebook/Working with Components|Chapter 4]]).&lt;br /&gt;
&lt;br /&gt;
== Editing Tracks ==&lt;br /&gt;
&lt;br /&gt;
Often, it makes sense to perform edits on all tracks of a movie. But for serious editing applications, sometimes you need to work at the track level, to add and remove tracks, or to work on just one track in isolation from the others. This task will provide a taste of that by adding a second audio track to a movie.&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;AddAudioTrackQTEditor&amp;lt;/tt&amp;gt; builds on &amp;lt;tt&amp;gt;FlattenableQTEditor&amp;lt;/tt&amp;gt; by adding another Add Audio Track... menu item, calling the &amp;lt;tt&amp;gt;doAddAudioTrack( )&amp;lt;/tt&amp;gt; method:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;public void doAddAudioTrack( ) throws QTException {&lt;br /&gt;
  // ask for an audio file&lt;br /&gt;
  QTFile audioFile =&lt;br /&gt;
      QTFile.standardGetFilePreview (QTFile.kStandardQTFileTypes);&lt;br /&gt;
  OpenMovieFile omf = OpenMovieFile.asRead (audioFile);&lt;br /&gt;
  Movie audioMovie = Movie.fromFile (omf);&lt;br /&gt;
  // find the audio track, if any&lt;br /&gt;
  Track audioTrack =&lt;br /&gt;
          audioMovie.getIndTrackType (1,&lt;br /&gt;
                                 StdQTConstants.audioMediaCharacteristic,&lt;br /&gt;
                                 StdQTConstants.movieTrackCharacteristic);&lt;br /&gt;
  if (audioTrack =  = null) {&lt;br /&gt;
      JOptionPane.showMessageDialog (this,&lt;br /&gt;
                                     &amp;quot;Didn't find audio track&amp;quot;,&lt;br /&gt;
                                     &amp;quot;Error&amp;quot;,&lt;br /&gt;
                                     JOptionPane.ERROR_MESSAGE);&lt;br /&gt;
      return;&lt;br /&gt;
  }&lt;br /&gt;
  // now make new audio track and insert segment&lt;br /&gt;
  // from the loaded track&lt;br /&gt;
  Track newTrack =&lt;br /&gt;
      movie.newTrack (0.0f, // width&lt;br /&gt;
                      0.0f, // height&lt;br /&gt;
                      audioTrack.getVolume( ));&lt;br /&gt;
  // ick, need a dataref for our &amp;quot;new&amp;quot; media&lt;br /&gt;
  // http://developer.apple.com/qa/qtmtb/qtmtb58.html&lt;br /&gt;
  SoundMedia newMedia =&lt;br /&gt;
      new SoundMedia (newTrack,&lt;br /&gt;
                      audioTrack.getMedia( ).getTimeScale( ),&lt;br /&gt;
                      new DataRef (new QTHandle( )));&lt;br /&gt;
  newTrack.getMedia( ).beginEdits( );&lt;br /&gt;
  audioTrack.insertSegment (newTrack,&lt;br /&gt;
                            0,&lt;br /&gt;
                            audioTrack.getDuration( ),&lt;br /&gt;
                            0);&lt;br /&gt;
  controller.movieChanged( );&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Compile and run this example with ant run-ch03-addaudiotrackqteditor''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method is admittedly contrived—it prompts the user to open another file, and if an audio track can be found in the file, the program adds that track to the movie, starting at time 0. If the user has done only a few short pastes and then adds an audio track from a typical iTunes MP3 or AAC, the result probably will be a movie in which the new soundtrack is much longer than the pasted contents.&lt;br /&gt;
&lt;br /&gt;
Also, QuickTime will eat more CPU cycles playing this movie, because it has to decode two compressed soundtracks at once. Like I said, it's a contrived example, but it covers some interesting ground.&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
The program tries to find an audio track with &amp;lt;tt&amp;gt;Movie.getIndTrackType( )&amp;lt;/tt&amp;gt; , passing &amp;lt;tt&amp;gt;audioMediaCharacteristic&amp;lt;/tt&amp;gt; as the search criterion. Assuming an audio track is found in this movie, the program needs to create a new track in the movie being edited. &amp;lt;tt&amp;gt;Movie.newTrack( )&amp;lt;/tt&amp;gt; creates the new track, taking as parameters the width, height, and volume of the new track.&lt;br /&gt;
&lt;br /&gt;
This new track is useless without a &amp;lt;tt&amp;gt;Media&amp;lt;/tt&amp;gt; object to hold the actual sound data, so the next step is to construct a new &amp;lt;tt&amp;gt;SoundMedia&amp;lt;/tt&amp;gt; object. The constructor takes the track that the media is to be associated with, a time scale, and a &amp;lt;tt&amp;gt;DataRef&amp;lt;/tt&amp;gt; to indicate where media samples can be stored.&lt;br /&gt;
&lt;br /&gt;
Interestingly, although the edit methods this program uses are in the &amp;lt;tt&amp;gt;Track&amp;lt;/tt&amp;gt; class, first I have to call &amp;lt;tt&amp;gt;Media.beginEdits( )&amp;lt;/tt&amp;gt; to inform the track's underlying media that it's about to get edited. Having done this, the program then can call &amp;lt;tt&amp;gt;Track.insertSegment()&amp;lt;/tt&amp;gt; , which is identical to its low-level-editing &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; equivalent, taking a target track, source in and out times, and a destination-in time. Following this, the program calls &amp;lt;tt&amp;gt;movieChanged( )&amp;lt;/tt&amp;gt; on the movie controller to let it know that a change was made to the movie behind the controller's back.&lt;br /&gt;
&lt;br /&gt;
The result is an additional audio track in the movie. If the user then flattens the movie and opens it up with QuickTime Player, a &amp;quot;Get Info&amp;quot; shows the extra audio track, as seen in [[QuickTime for Java: A Developer's Notebook/Editing Movies#quicktimejvaadn-CHP-3-FIG-6|Figure 3-6]]. In this case, I imported clips from an MPEG-4 file and added an MP3 soundtrack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''No, I'm not swearing in this filename. I combined a video of my son in an inflatable boat with an MP3 of a song called &amp;quot;Dam Dariram&amp;quot; from the video game &amp;quot;Dance Dance Revolution&amp;quot;; thus, &amp;quot;dam-boat.mov&amp;quot;''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-3-FIG-6&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 3-6. QuickTime Player &amp;quot;Get Info&amp;quot; for movie with multiple audio tracks'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_3_tt54.png|QuickTime Player &amp;quot;Get Info&amp;quot; for movie with multiple audio tracks]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...that crazy-looking &amp;lt;tt&amp;gt;new DataRef (new QTHandle( ))&amp;lt;/tt&amp;gt; parameter in the &amp;lt;tt&amp;gt;SoundMedia&amp;lt;/tt&amp;gt; constructor? OK, scary edge case—here's the story. Zoom out for a second: movies have tracks, tracks have media, media have samples. Those samples need to live ''somewhere''. It's not a problem when you open a movie from disk, but when you create new media in a new movie, QuickTime has no idea where it's supposed to put any samples that you add, whether by way of inserting segments from other tracks or by adding individual samples one by one (which will be covered in Chapters [[QuickTime for Java: A Developer's Notebook/Audio Media|Chapter 7]], [[QuickTime for Java: A Developer's Notebook/Video Media|Chapter 8]], and [[QuickTime for Java: A Developer's Notebook/Miscellaneous Media|Chapter 9]]). So, this example uses the &amp;lt;tt&amp;gt;SoundMedia&amp;lt;/tt&amp;gt; constructor that takes a &amp;lt;tt&amp;gt;DataRef&amp;lt;/tt&amp;gt;, which represents a location to store the samples. This &amp;lt;tt&amp;gt;DataRef&amp;lt;/tt&amp;gt; can be practically anything, even a zero-length buffer in memory, which is pretty much what this example passes in by constructing a new &amp;lt;tt&amp;gt;DataRef&amp;lt;/tt&amp;gt; out of a new, empty &amp;lt;tt&amp;gt;QTHandle&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tip&amp;quot;&amp;gt;&lt;br /&gt;
'''Tip'''&lt;br /&gt;
&lt;br /&gt;
For more on this icky little gotcha, and if you don't mind a C-oriented technote, see &amp;quot;BeginMediaEdits -2050 badDataRefIndex error after calling NewMovie&amp;quot; at ''http://developer.apple.com/qa/qtmtb/qtmtb58.html''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also, what about the control bar? It tells the user nothing about the tracks in the movie. You're absolutely right. Being playback-oriented, the provided GUI is weak for editing movies, and utterly useless for editing tracks. It gives the user no idea how many tracks a movie has, where there's video without sound or vice versa, etc. Moreover, there's no default widget in QTJ to replace it. If you want to provide track-oriented editing, you'll need to develop your own GUI components to display tracks and their contents. I haven't provided one here, because the appearance and behavior of such a component would vary wildly with the kind of application it was needed for (a home movie editor, an MP3 playlist builder, etc.) and because it easily could contain more than 1,000 lines of AWT code with maybe a dozen lines of QuickTime...not exactly ideal for the format of this book.&lt;br /&gt;
&lt;br /&gt;
What about other track-editing methods? Fortunately, many of the concepts from the low-level &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; editing lab from earlier in the chapter apply to tracks. Along with &amp;lt;tt&amp;gt;Track.insertSegment()&amp;lt;/tt&amp;gt; are a &amp;lt;tt&amp;gt;deleteSegment()&amp;lt;/tt&amp;gt; and a &amp;lt;tt&amp;gt;scaleSegment()&amp;lt;/tt&amp;gt; that work like their &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; equivalents. The &amp;lt;tt&amp;gt;insertEmptySegment()&amp;lt;/tt&amp;gt; does what its name implies, and could be useful for building a track in nonconsecutive segments. There's also a &amp;lt;tt&amp;gt;Track.insertMedia()&amp;lt;/tt&amp;gt; that will be used in later chapters to build up a &amp;lt;tt&amp;gt;Media&amp;lt;/tt&amp;gt; object from raw samples.&lt;br /&gt;
&lt;br /&gt;
As for how the tracks relate to their parent movies, this example uses &amp;lt;tt&amp;gt;Movie.newTrack( )&amp;lt;/tt&amp;gt; , though it also is possible to use &amp;lt;tt&amp;gt;addEmptyTrack()&amp;lt;/tt&amp;gt; , which takes a prototype track and a &amp;lt;tt&amp;gt;DataRef&amp;lt;/tt&amp;gt;. Tracks can be removed with &amp;lt;tt&amp;gt;Movie.removeTrack( )&amp;lt;/tt&amp;gt; and temporarily turned on and off with &amp;lt;tt&amp;gt;Track.setEnabled()&amp;lt;/tt&amp;gt; .&lt;/div&gt;</summary>
		<author><name>Docbook2Wiki</name></author>	</entry>

	</feed>