├── lib ├── license ├── jna-3.5.2.jar ├── vlcj-2.4.1.jar ├── platform-3.5.2.jar └── swing-layout-1.0.3.jar ├── bin ├── views │ ├── x.png │ ├── logo.png │ ├── min.png │ ├── x_on.png │ ├── min_on.png │ ├── HRPane.class │ ├── XWindow.class │ ├── HRPane$1.class │ ├── HRPane$2.class │ ├── HRPane$3.class │ ├── HRPane$4.class │ ├── HRPane$5.class │ ├── HRPane$6.class │ ├── XWindow$1.class │ ├── XWindow$2.class │ ├── XWindow$3.class │ ├── XWindow$4.class │ ├── XWindow$5.class │ ├── XWindow$6.class │ ├── XWindow$7.class │ ├── XWindow$8.class │ ├── XWindow$9.class │ ├── TimelinePane.class │ ├── TimelinePane$1.class │ ├── TimelinePane$2.class │ ├── TimelinePane$3.class │ ├── TimelinePane$4.class │ ├── EmbeddedMediaPlayerComponentX.class │ └── XWindow.form ├── controls │ ├── Play.class │ ├── DispTime.class │ ├── TimelineX.class │ └── Play$PlayTask.class └── modles │ └── Timeline.class ├── src ├── views │ ├── x.png │ ├── logo.png │ ├── min.png │ ├── x_on.png │ ├── min_on.png │ ├── TimelinePane.java │ ├── EmbeddedMediaPlayerComponentX.java │ ├── XWindow.java │ └── HRPane.java ├── controls │ ├── DispTime.java │ ├── Play.java │ └── TimelineX.java └── modles │ └── Timeline.java ├── TimelineX PRO.jar ├── .settings ├── org.eclipse.core.resources.prefs └── org.eclipse.jdt.core.prefs ├── README.md └── gpl-2.0.txt /lib/license: -------------------------------------------------------------------------------- 1 | 请遵循开源库的各自协议 2 | -------------------------------------------------------------------------------- /bin/views/x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/x.png -------------------------------------------------------------------------------- /src/views/x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/src/views/x.png -------------------------------------------------------------------------------- /TimelineX PRO.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/TimelineX PRO.jar -------------------------------------------------------------------------------- /bin/views/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/logo.png -------------------------------------------------------------------------------- /bin/views/min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/min.png -------------------------------------------------------------------------------- /bin/views/x_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/x_on.png -------------------------------------------------------------------------------- /lib/jna-3.5.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/lib/jna-3.5.2.jar -------------------------------------------------------------------------------- /lib/vlcj-2.4.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/lib/vlcj-2.4.1.jar -------------------------------------------------------------------------------- /src/views/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/src/views/logo.png -------------------------------------------------------------------------------- /src/views/min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/src/views/min.png -------------------------------------------------------------------------------- /src/views/x_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/src/views/x_on.png -------------------------------------------------------------------------------- /bin/views/min_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/min_on.png -------------------------------------------------------------------------------- /src/views/min_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/src/views/min_on.png -------------------------------------------------------------------------------- /bin/controls/Play.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/controls/Play.class -------------------------------------------------------------------------------- /bin/views/HRPane.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/HRPane.class -------------------------------------------------------------------------------- /bin/views/XWindow.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/XWindow.class -------------------------------------------------------------------------------- /lib/platform-3.5.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/lib/platform-3.5.2.jar -------------------------------------------------------------------------------- /bin/modles/Timeline.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/modles/Timeline.class -------------------------------------------------------------------------------- /bin/views/HRPane$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/HRPane$1.class -------------------------------------------------------------------------------- /bin/views/HRPane$2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/HRPane$2.class -------------------------------------------------------------------------------- /bin/views/HRPane$3.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/HRPane$3.class -------------------------------------------------------------------------------- /bin/views/HRPane$4.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/HRPane$4.class -------------------------------------------------------------------------------- /bin/views/HRPane$5.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/HRPane$5.class -------------------------------------------------------------------------------- /bin/views/HRPane$6.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/HRPane$6.class -------------------------------------------------------------------------------- /bin/views/XWindow$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/XWindow$1.class -------------------------------------------------------------------------------- /bin/views/XWindow$2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/XWindow$2.class -------------------------------------------------------------------------------- /bin/views/XWindow$3.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/XWindow$3.class -------------------------------------------------------------------------------- /bin/views/XWindow$4.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/XWindow$4.class -------------------------------------------------------------------------------- /bin/views/XWindow$5.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/XWindow$5.class -------------------------------------------------------------------------------- /bin/views/XWindow$6.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/XWindow$6.class -------------------------------------------------------------------------------- /bin/views/XWindow$7.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/XWindow$7.class -------------------------------------------------------------------------------- /bin/views/XWindow$8.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/XWindow$8.class -------------------------------------------------------------------------------- /bin/views/XWindow$9.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/XWindow$9.class -------------------------------------------------------------------------------- /lib/swing-layout-1.0.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/lib/swing-layout-1.0.3.jar -------------------------------------------------------------------------------- /bin/controls/DispTime.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/controls/DispTime.class -------------------------------------------------------------------------------- /bin/controls/TimelineX.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/controls/TimelineX.class -------------------------------------------------------------------------------- /bin/views/TimelinePane.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/TimelinePane.class -------------------------------------------------------------------------------- /bin/views/TimelinePane$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/TimelinePane$1.class -------------------------------------------------------------------------------- /bin/views/TimelinePane$2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/TimelinePane$2.class -------------------------------------------------------------------------------- /bin/views/TimelinePane$3.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/TimelinePane$3.class -------------------------------------------------------------------------------- /bin/views/TimelinePane$4.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/TimelinePane$4.class -------------------------------------------------------------------------------- /bin/controls/Play$PlayTask.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/controls/Play$PlayTask.class -------------------------------------------------------------------------------- /bin/views/EmbeddedMediaPlayerComponentX.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acely/TimelineX/HEAD/bin/views/EmbeddedMediaPlayerComponentX.class -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | #Sat Sep 28 14:39:46 CST 2013 2 | eclipse.preferences.version=1 3 | encoding//src/modles/Timeline.java=UTF-8 4 | encoding/=UTF-8 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TimelineX 2 | TimelineX是一个用Java编写的字幕制作桌面程序,是Arctime软件的前身,也是基础框架。 3 | 4 | 此基础框架包括:基于vlcj的视频播放器、程序窗体界面、时间轴、导出SRT文件、视频压制等。 5 | 6 | 开源代码仅供参考交流。不提供任何技术支持和质量保证。 7 | 8 | 9 | 采用GPLv2协议。 10 | -------------------------------------------------------------------------------- /src/controls/DispTime.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @author acely 3 | * 本程序由ACELY创作,开源代码仅供参考交流。不提供任何技术支持和质量保证。 4 | * 禁止修改、传播、再次分发以及任何商业用途。不得将部分或全部代码应用于其他任何软件。 5 | */ 6 | package controls; 7 | 8 | import javax.swing.JLabel; 9 | 10 | import modles.Timeline; 11 | 12 | public class DispTime extends Thread { 13 | 14 | JLabel time; 15 | public DispTime(JLabel t){ 16 | time = t; 17 | } 18 | 19 | @Override 20 | public void run() { 21 | try { 22 | while (true) { 23 | time.setText(formatTime(Timeline.getTimeline().getCurrTime())); 24 | sleep(50); 25 | } 26 | 27 | } catch (InterruptedException e) { 28 | // TODO Auto-generated catch block 29 | e.printStackTrace(); 30 | } 31 | } 32 | 33 | public static String formatTime(long t) { 34 | StringBuilder time = new StringBuilder(); 35 | time.append("00:"); 36 | //获得分钟 37 | if (t/60000 > 9) { 38 | time.append(t/60000).append(":"); 39 | }else { 40 | time.append("0").append(t/60000).append(":"); 41 | } 42 | //获得秒 43 | if (t%60000/1000 > 9) { 44 | time.append(t%60000/1000).append(","); 45 | }else { 46 | time.append("0").append(t%60000/1000).append(","); 47 | } 48 | //获得毫秒 49 | if (t%1000 > 99) { 50 | time.append(t%1000); 51 | }else if (t%1000 > 9) { 52 | time.append("0").append(t%1000); 53 | }else { 54 | time.append("00").append(t%1000); 55 | } 56 | return time.toString(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/controls/Play.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @author acely 3 | * 本程序由ACELY创作,开源代码仅供参考交流。不提供任何技术支持和质量保证。 4 | * 禁止修改、传播、再次分发以及任何商业用途。不得将部分或全部代码应用于其他任何软件。 5 | */ 6 | package controls; 7 | 8 | 9 | import java.util.Timer; 10 | import java.util.TimerTask; 11 | 12 | import views.TimelinePane; 13 | import modles.Timeline; 14 | 15 | public class Play extends Timer { 16 | 17 | 18 | public Play(){ 19 | //如果是新加入的视频(还没有播放过),则从头开始播放 20 | if (TimelineX.getTimelineX().videoJustOpened) { 21 | Timeline.getTimeline().setCurrTime(0); 22 | TimelinePane.getTLPane().setPlayhead(1); 23 | TimelineX.getTimelineX().videoJustOpened = false; 24 | } 25 | } 26 | 27 | 28 | class PlayTask extends TimerTask{ 29 | 30 | @Override 31 | public void run() { 32 | //如果检测到modle停止,则马上退出播放 33 | if (!Timeline.getTimeline().getPlaying()){ 34 | TimelineX.tlx.getPlayPane().getMediaPlayer().pause(); 35 | System.out.println("Paused"); 36 | cancel(); 37 | } 38 | //刷新modle中的时间,刷新界面 39 | Timeline.getTimeline().setCurrTime(Timeline.getTimeline().getCurrTime() + 50); 40 | TimelinePane.getTLPane().setPlayhead((int)((Timeline.getTimeline().getCurrTime())*(float)Timeline.getTimeline().getTimeUnitWidth()/Timeline.getTimeline().time_unit)+1); 41 | TimelinePane.getTLPane().repaint(); 42 | //如果选择了块,则循环播放对应时间段 43 | if (Timeline.getTimeline().repeat_end != -1) { 44 | if (Timeline.getTimeline().getCurrTime() >= Timeline.getTimeline().repeat_end) { 45 | Timeline.getTimeline().setCurrTime(Timeline.getTimeline().repeat_start); 46 | TimelinePane.getTLPane().setPlayhead((int)((Timeline.getTimeline().repeat_start)*(float)Timeline.getTimeline().getTimeUnitWidth()/Timeline.getTimeline().time_unit)+1); 47 | TimelineX.tlx.getPlayPane().getMediaPlayer().setTime(Timeline.getTimeline().repeat_start); 48 | } 49 | } 50 | //如果播放头到达时间轴末尾,则停止播放,将播放头返回到头部 51 | if(TimelinePane.getTLPane().getPlayhead() >= TimelinePane.getTLPane().getWidth()) { 52 | Timeline.getTimeline().setPlaying(false); 53 | TimelineX.tlx.getPlayPane().getMediaPlayer().pause(); 54 | TimelinePane.getTLPane().setPlayhead(1); 55 | Timeline.getTimeline().setCurrTime(0); 56 | System.out.println("Paused"); 57 | cancel(); 58 | } 59 | } 60 | 61 | } 62 | 63 | @Override 64 | public void scheduleAtFixedRate(TimerTask task, long delay, long period) { 65 | // TODO Auto-generated method stub 66 | super.scheduleAtFixedRate(new PlayTask(), 0, 50); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | #Sat Sep 28 14:40:25 CST 2013 2 | eclipse.preferences.version=1 3 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.compliance=1.6 7 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 8 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 9 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 10 | org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning 11 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 12 | org.eclipse.jdt.core.compiler.problem.autoboxing=ignore 13 | org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning 14 | org.eclipse.jdt.core.compiler.problem.deadCode=warning 15 | org.eclipse.jdt.core.compiler.problem.deprecation=warning 16 | org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled 17 | org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled 18 | org.eclipse.jdt.core.compiler.problem.discouragedReference=warning 19 | org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore 20 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 21 | org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore 22 | org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled 23 | org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore 24 | org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning 25 | org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning 26 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=ignore 27 | org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning 28 | org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled 29 | org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning 30 | org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore 31 | org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore 32 | org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore 33 | org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning 34 | org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore 35 | org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore 36 | org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore 37 | org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled 38 | org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning 39 | org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore 40 | org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning 41 | org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning 42 | org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore 43 | org.eclipse.jdt.core.compiler.problem.nullReference=warning 44 | org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning 45 | org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore 46 | org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore 47 | org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore 48 | org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning 49 | org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore 50 | org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore 51 | org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore 52 | org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore 53 | org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled 54 | org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning 55 | org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled 56 | org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled 57 | org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore 58 | org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning 59 | org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled 60 | org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning 61 | org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore 62 | org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning 63 | org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore 64 | org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore 65 | org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore 66 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore 67 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled 68 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled 69 | org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled 70 | org.eclipse.jdt.core.compiler.problem.unusedImport=warning 71 | org.eclipse.jdt.core.compiler.problem.unusedLabel=warning 72 | org.eclipse.jdt.core.compiler.problem.unusedLocal=warning 73 | org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore 74 | org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore 75 | org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled 76 | org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled 77 | org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled 78 | org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning 79 | org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning 80 | org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning 81 | org.eclipse.jdt.core.compiler.source=1.6 82 | -------------------------------------------------------------------------------- /src/controls/TimelineX.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @author acely 3 | * 本程序由ACELY创作,开源代码仅供参考交流。不提供任何技术支持和质量保证。 4 | * 禁止修改、传播、再次分发以及任何商业用途。不得将部分或全部代码应用于其他任何软件。 5 | */ 6 | package controls; 7 | 8 | import java.awt.datatransfer.DataFlavor; 9 | import java.awt.datatransfer.UnsupportedFlavorException; 10 | import java.awt.dnd.DnDConstants; 11 | import java.awt.dnd.DropTargetDropEvent; 12 | import java.io.File; 13 | import java.io.FileInputStream; 14 | import java.io.FileOutputStream; 15 | import java.io.IOException; 16 | import java.io.InputStreamReader; 17 | import java.io.OutputStreamWriter; 18 | import java.util.Iterator; 19 | import java.util.List; 20 | 21 | import modles.Timeline; 22 | import uk.co.caprica.vlcj.binding.LibVlc; 23 | import uk.co.caprica.vlcj.runtime.RuntimeUtil; 24 | import uk.co.caprica.vlcj.runtime.windows.WindowsRuntimeUtil; 25 | import views.TimelinePane; 26 | import views.XWindow; 27 | 28 | import com.sun.jna.Native; 29 | import com.sun.jna.NativeLibrary; 30 | 31 | /** 32 | * added to github 33 | * @author ACELY 34 | * 35 | */ 36 | public class TimelineX { 37 | 38 | private static TimelineX topcontrol = new TimelineX(); 39 | public static TimelineX getTimelineX() { 40 | return topcontrol; 41 | } 42 | private TimelineX(){ 43 | //---------------------------- 44 | if (RuntimeUtil.isWindows()) { 45 | System.out.println("isWindows"); 46 | NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), fixFilename("C:/Program Files/VideoLAN/VLC")); 47 | NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), fixFilename("D:/Program Files/VideoLAN/VLC")); 48 | NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), WindowsRuntimeUtil.getVlcInstallDir()); 49 | }else if (RuntimeUtil.isMac()) { 50 | NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), fixFilename("/Applications/VLC.app/Contents/MacOS/lib")); 51 | } 52 | Native.loadLibrary(RuntimeUtil.getLibVlcLibraryName(),LibVlc.class); 53 | tlx = new XWindow(); 54 | tlx.setTitle("TimelineX - ACELY STUDIO 2013"); 55 | tlx.setVisible(true); 56 | TimelinePane.getTLPane().requestFocus(); 57 | //---------------------------------- 58 | //Timeline.getTimeline().add_block(new HRPane("开始创建时间轴"),1); 59 | //Timeline.getTimeline().add_block(new HRPane("Enjoy TimelineX !"),2); 60 | if (RuntimeUtil.isWindows()) { 61 | tlx.getPlayPane().getMediaPlayer().prepareMedia(fixFilename("E:/VIDEO/Girls Are Art/163613116.mp4")); 62 | videofile = "E:/VIDEO/Girls Are Art/163613116.mp4"; 63 | videoJustOpened = true; 64 | }else if (RuntimeUtil.isMac()) { 65 | tlx.getPlayPane().getMediaPlayer().prepareMedia(fixFilename("/Users/apple/Desktop/test.mp4")); 66 | videofile = "/Users/apple/Desktop/test.mp4"; 67 | videoJustOpened = true; 68 | } 69 | readSrtFile(); 70 | tlx.getPlayPane().getMediaPlayer().setRepeat(true); 71 | System.out.println(tlx.getPlayPane().getMediaPlayerFactory().version()); 72 | //---------------------------------- 73 | 74 | } 75 | 76 | public String fixFilename(String n) { 77 | File getname = new File(n); 78 | return getname.getAbsolutePath(); 79 | } 80 | 81 | //------------------------- 82 | public static XWindow tlx; 83 | public boolean videoJustOpened; 84 | public String videofile; 85 | //------------------------- 86 | 87 | public static void main(String[] args) { 88 | 89 | } 90 | 91 | public void play() { 92 | if (Timeline.getTimeline().getPlaying()) { 93 | Timeline.getTimeline().setPlaying(false); 94 | System.out.println(tlx.getPlayPane().getMediaPlayer().getLength()); 95 | }else { 96 | Timeline.getTimeline().setPlaying(true); 97 | TimelineX.tlx.getPlayPane().getMediaPlayer().play(); 98 | System.out.println("Playing"); 99 | new Play().scheduleAtFixedRate(null, 0, 0); 100 | } 101 | } 102 | 103 | public void saveSrtFile() { 104 | try { 105 | writeFile(new File(videofile.substring(0,videofile.lastIndexOf("."))+".srt"), 106 | Timeline.getTimeline().srtBuilder.toString().replace("\n", "\r\n")); 107 | } catch (IOException e) { 108 | // TODO Auto-generated catch block 109 | e.printStackTrace(); 110 | } 111 | } 112 | 113 | public void readSrtFile() { 114 | try { 115 | File in = new File(videofile.substring(0,videofile.lastIndexOf("."))+".srt"); 116 | if (in.exists()) { 117 | Timeline.getTimeline().srtin = readFile(in).replace("\r", ""); 118 | Timeline.getTimeline().DecodeSrt(); 119 | } 120 | } catch (IOException e) { 121 | // TODO Auto-generated catch block 122 | e.printStackTrace(); 123 | } 124 | } 125 | 126 | public void writeFile(File file,String in) throws IOException { 127 | FileOutputStream fos = new FileOutputStream(file); 128 | OutputStreamWriter osw = new OutputStreamWriter(fos, "GB18030"); 129 | osw.write(in); 130 | osw.flush(); 131 | osw.close(); 132 | fos.close(); 133 | } 134 | 135 | public String readFile(File file) throws IOException { 136 | FileInputStream fis = new FileInputStream(file); 137 | InputStreamReader isr = new InputStreamReader(fis, "GB18030"); 138 | long i = file.length(); 139 | char[] buf = new char[(int)(i)]; 140 | isr.read(buf); 141 | isr.close(); 142 | fis.close(); 143 | return new String(buf); 144 | } 145 | 146 | public void readDroppedFile(DropTargetDropEvent dtde) { 147 | try { 148 | if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) { 149 | dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); 150 | List list = (List) (dtde.getTransferable() 151 | .getTransferData(DataFlavor.javaFileListFlavor)); 152 | Iterator iterator = list.iterator(); 153 | while (iterator.hasNext()) { 154 | File f = (File) iterator.next(); 155 | tlx.getPlayPane().getMediaPlayer().prepareMedia(f.getAbsolutePath()); 156 | videofile = f.getAbsolutePath(); 157 | videoJustOpened = true; 158 | readSrtFile(); 159 | tlx.getPlayPane().getMediaPlayer().setRepeat(true); 160 | TimelinePane.getTLPane().setPlayhead(1); 161 | Timeline.getTimeline().clearAll(); 162 | } 163 | dtde.dropComplete(true); 164 | }else { 165 | dtde.rejectDrop(); 166 | } 167 | } catch (IOException ioe) { 168 | } catch (UnsupportedFlavorException e) {} 169 | } 170 | 171 | public void setVolume(int v) { 172 | tlx.getPlayPane().getMediaPlayer().setVolume(v); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/modles/Timeline.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @author acely 3 | * 本程序由ACELY创作,开源代码仅供参考交流。不提供任何技术支持和质量保证。 4 | * 禁止修改、传播、再次分发以及任何商业用途。不得将部分或全部代码应用于其他任何软件。 5 | */ 6 | package modles; 7 | 8 | import java.util.Collections; 9 | import java.util.LinkedList; 10 | import java.util.Vector; 11 | 12 | import controls.DispTime; 13 | import controls.TimelineX; 14 | import views.HRPane; 15 | import views.TimelinePane; 16 | 17 | public class Timeline { 18 | private Timeline(){} 19 | private static Timeline timeline = new Timeline(); 20 | public static Timeline getTimeline() { 21 | return timeline; 22 | } 23 | //------------------ 24 | private Vector blocks = new Vector(); 25 | public boolean allow_snap = true; 26 | public int snap_factor = 10;//吸附距离 27 | public int track_max = 5;//最大轨道数 28 | public int track_hight = 25;//轨道高度 29 | public int time_unit = 100;//每个时间单位的长度(毫秒) 30 | private int time_unit_width = 3;//每个时间单位在标尺上显示的宽度(像素) 31 | public int time_total = 12;//时间轴总长度(秒) 32 | public int default_width = 2000;//块默认长度 ms 33 | public int ruler_hight = 25;//标尺高度 34 | private long curr_time = 0; 35 | public long repeat_start = -1;//循环播放的起始时间 36 | public long repeat_end = -1;//循环播放的结束时间 37 | //------------------ 38 | private boolean playing = false; 39 | //------------------ 40 | private String alltime[][]; 41 | private LinkedList time_nodes; 42 | public StringBuilder srtBuilder; 43 | public String srtin; 44 | //------------------ 45 | 46 | public Vector getBlocks() { 47 | return blocks; 48 | } 49 | 50 | public void add_block(HRPane newblock,int layer,boolean visiable) { 51 | newblock.layer = layer; 52 | blocks.add(newblock); 53 | //System.out.println("added:"+newblock.getName()); 54 | if (visiable) { 55 | TimelinePane.getTLPane().add_block_by_user(newblock); 56 | }else { 57 | TimelinePane.getTLPane().add_block(newblock); 58 | } 59 | } 60 | 61 | public void add_block_below(String name) { 62 | for (int i = 0; i < blocks.size(); i++) { 63 | if (blocks.get(i).getName().equals(name)) { 64 | HRPane ori = blocks.get(i); 65 | if (ori.layer < track_max) { 66 | HRPane newHrPane = new HRPane("->"); 67 | newHrPane.time_start = ori.time_start; 68 | newHrPane.time_end = ori.time_end; 69 | newHrPane.setLocation(ori.getX(),1+ruler_hight+ori.layer*track_hight); 70 | newHrPane.setSize(ori.getSize()); 71 | newHrPane.layer = ori.layer+1; 72 | blocks.add(newHrPane); 73 | TimelinePane.getTLPane().add_block(newHrPane); 74 | TimelinePane.getTLPane().repaint(); 75 | newHrPane.requestFocusInWindow(); 76 | } 77 | break; 78 | } 79 | } 80 | } 81 | 82 | public void remove_block(String hash) { 83 | for (int i = 0; i < blocks.size(); i++) { 84 | if (blocks.get(i).getName().equals(hash)) { 85 | TimelinePane.getTLPane().remove_block(blocks.get(i)); 86 | blocks.removeElementAt(i); 87 | System.out.println("Block with hash-"+hash+"-removed!"); 88 | break; 89 | } 90 | } 91 | //删除后也刷新文件 92 | Timeline.getTimeline().EncodeSrt(); 93 | TimelineX.getTimelineX().saveSrtFile(); 94 | TimelineX.tlx.getPlayPane().getMediaPlayer().setSubTitleFile( 95 | TimelineX.getTimelineX().videofile.substring(0,TimelineX.getTimelineX().videofile.lastIndexOf("."))+".srt"); 96 | } 97 | 98 | public void clearAll() { 99 | blocks = new Vector(); 100 | TimelinePane.getTLPane().removeAll(); 101 | TimelinePane.getTLPane().repaint(); 102 | } 103 | 104 | public long getCurrTime() { 105 | return curr_time; 106 | } 107 | 108 | public void setCurrTime(long t) { 109 | if (t >= 0) { 110 | curr_time = t; 111 | }else { 112 | curr_time = 0; 113 | } 114 | if (!playing) { 115 | TimelineX.tlx.getPlayPane().getMediaPlayer().setTime(curr_time); 116 | } 117 | } 118 | 119 | public int getTimeUnitWidth() { 120 | return time_unit_width; 121 | } 122 | 123 | public void setTimeUnitWidth(int w) { 124 | if (w >= 1) { 125 | time_unit_width = w; 126 | } 127 | } 128 | 129 | public boolean getPlaying() { 130 | return playing; 131 | } 132 | 133 | public void setPlaying(boolean s){ 134 | playing = s; 135 | } 136 | 137 | /** 138 | * 将时间轴上得所有块转换为SRT时间轴数据 139 | */ 140 | public void EncodeSrt() { 141 | alltime = new String[blocks.size()][4]; 142 | time_nodes = new LinkedList(); 143 | srtBuilder = new StringBuilder(); 144 | //构建新alltime数组,用来缩短检索时间(Vector检索速度慢) 145 | for (int i = 0; i < blocks.size(); i++) { 146 | alltime[i][0] = blocks.get(i).time_start+""; //0-存放块开始时间 147 | alltime[i][1] = blocks.get(i).time_end+""; //1-存放块结束时间 148 | alltime[i][2] = blocks.get(i).layer+""; //2-存放块所在层数 149 | alltime[i][3] = blocks.get(i).getText(); //3-存放块文字内容 150 | //把所有块的旗帜时间添加到节点库中去(不会重复) 151 | addToTimeNodes(Long.parseLong(alltime[i][0])); 152 | addToTimeNodes(Long.parseLong(alltime[i][1])); 153 | } 154 | //【非常重要】对所有的时间节点进行排序 155 | Collections.sort(time_nodes); 156 | //对每个时间节点进行分析,找出其+1后穿过的块,然后构建对应内容 157 | int index = 1;//字幕时间轴编号 158 | for (int i = 0; i < time_nodes.size()-1; i++) { 159 | String[] content = new String[track_max+1];//按最大层数+1构建一个数组,用来按层存放节点穿过的内容块对应的内容 160 | long nt = time_nodes.get(i);//存放当前块的开始时间 161 | long nxt = time_nodes.get(i+1);//存放当前块的结束时间 162 | //扫描所有块 163 | for (int j = 0; j < blocks.size(); j++) { 164 | if (nt+1 > Long.parseLong(alltime[j][0]) && nt+1 < Long.parseLong(alltime[j][1])) {//节点+1是否穿过块 165 | content[Integer.parseInt(alltime[j][2])] = alltime[j][3];//如果穿过则把文字按照层数放在数组里 166 | } 167 | } 168 | //扫描完所有的块之后,创建真正的SRT时间轴信息 169 | StringBuilder contentBuilder = new StringBuilder(); 170 | for (int n = 1; n < content.length; n++) { 171 | if (content[n] != null) { 172 | contentBuilder.append(content[n]).append("\n"); 173 | } 174 | } 175 | if (contentBuilder.toString().equals("")) { 176 | //如果这个节点没有文字数据,则调到下一个节点,不输出内容 177 | continue; 178 | } 179 | srtBuilder.append(index+"\n"); 180 | srtBuilder.append(DispTime.formatTime(nt)+" --> "+DispTime.formatTime(nxt)+"\n"); 181 | srtBuilder.append(contentBuilder.toString()+"\n"); 182 | index ++; 183 | } 184 | } 185 | 186 | /** 187 | * 188 | * @param t 以毫秒为单位的时间 189 | */ 190 | private void addToTimeNodes(long t) { 191 | //添加时间结点,并且避免重复 192 | if (time_nodes.size() == 0) { 193 | time_nodes.add(t); 194 | }else { 195 | for (int i = 0; i < time_nodes.size(); i++) { 196 | if (time_nodes.get(i) == t) { 197 | return; 198 | } 199 | } 200 | time_nodes.add(t); 201 | } 202 | } 203 | 204 | public void DecodeSrt() { 205 | blocks = new Vector(); 206 | String[] allele = srtin.split("\n\n"); 207 | long start = 0; 208 | long end = 1; 209 | for (int i = 0; i < allele.length; i++) { 210 | if (allele[i].contains(" --> ")) { 211 | String[] lines = allele[i].split("\n"); 212 | start = decodeTime(lines[1].substring(0,12)); 213 | end = decodeTime(lines[1].substring(17,29)); 214 | for (int j = 2; j < lines.length; j++) { 215 | HRPane newblock = new HRPane(lines[j]); 216 | newblock.time_start = start; 217 | newblock.time_end = end; 218 | add_block(newblock, j-1,false); 219 | } 220 | } 221 | } 222 | time_total = (int) (start/1000); 223 | TimelinePane.getTLPane().refresh_block(); 224 | } 225 | 226 | public long decodeTime(String tl) { 227 | //00:00:00,000 --> 00:00:02,000 228 | //------------ ------------ 229 | 230 | return Integer.parseInt(tl.substring(3,5))*60000+ 231 | Integer.parseInt(tl.substring(6,8))*1000+ 232 | Integer.parseInt(tl.substring(9,12)); 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /src/views/TimelinePane.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @author acely 3 | * 本程序由ACELY创作,开源代码仅供参考交流。不提供任何技术支持和质量保证。 4 | * 禁止修改、传播、再次分发以及任何商业用途。不得将部分或全部代码应用于其他任何软件。 5 | */ 6 | package views; 7 | 8 | import java.awt.Color; 9 | import java.awt.Dimension; 10 | import java.awt.Graphics; 11 | import java.awt.event.FocusEvent; 12 | import java.awt.event.FocusListener; 13 | import java.awt.event.KeyEvent; 14 | import java.awt.event.KeyListener; 15 | import java.awt.event.MouseEvent; 16 | import java.awt.event.MouseListener; 17 | import java.awt.event.MouseMotionListener; 18 | 19 | import javax.swing.JPanel; 20 | import javax.swing.JScrollPane; 21 | 22 | import controls.TimelineX; 23 | import modles.Timeline; 24 | 25 | public class TimelinePane extends JPanel { 26 | 27 | //---------------------- 28 | private int playhead = 1; 29 | public int selected_layer = 1; 30 | public boolean shiftdrag = false; 31 | //---------------------- 32 | private JPanel head; 33 | //---------------------- 34 | 35 | /** 36 | * 37 | */ 38 | private static final long serialVersionUID = 1L; 39 | private static TimelinePane tlPane = new TimelinePane(); 40 | private TimelinePane(){ 41 | setLayout(null); 42 | setDoubleBuffered(true); 43 | init(); 44 | } 45 | public static TimelinePane getTLPane() { 46 | return tlPane; 47 | } 48 | 49 | 50 | public long x_to_time(int x) { 51 | return (long) ((x-1)*((float)Timeline.getTimeline().time_unit/Timeline.getTimeline().getTimeUnitWidth())); 52 | } 53 | 54 | public int time_to_x(long time) { 55 | return (int)(time*(float)Timeline.getTimeline().getTimeUnitWidth()/Timeline.getTimeline().time_unit)+1; 56 | } 57 | 58 | /** 59 | * 由程序添加块,与用户添加块不同 60 | */ 61 | public void add_block(HRPane newblock) { 62 | this.add(newblock); 63 | } 64 | 65 | public void add_block_by_user(HRPane newblock) { 66 | this.add(newblock); 67 | //---如果没指定层,则放到当前激活的层上,起始位置与播放头一致--- 68 | if (newblock.layer == 0) { 69 | newblock.layer = selected_layer; 70 | } 71 | newblock.setSize(time_to_x(Timeline.getTimeline().default_width)-1,Timeline.getTimeline().track_hight-1); 72 | newblock.setLocation(playhead, 1+Timeline.getTimeline().ruler_hight+(newblock.layer-1)*Timeline.getTimeline().track_hight); 73 | newblock.time_start = x_to_time(playhead); 74 | newblock.time_end = newblock.time_start+Timeline.getTimeline().default_width; 75 | //---播放头跟踪--- 76 | if (!Timeline.getTimeline().getPlaying()) { 77 | //如果正在播放的话,插入块就不更新播放头位置 78 | playhead += newblock.getWidth(); 79 | Timeline.getTimeline().setCurrTime(x_to_time(playhead)); 80 | } 81 | Timeline.getTimeline().time_total = (playhead-1)/Timeline.getTimeline().getTimeUnitWidth()/(1000/Timeline.getTimeline().time_unit)+6; 82 | //如果播放头位置即将大于时间轴宽度,则增加总时间,并加宽时间轴 83 | if (playhead >= getWidth()) { 84 | Timeline.getTimeline().time_total = (playhead-1)/Timeline.getTimeline().getTimeUnitWidth()/10+5; 85 | setSize((Timeline.getTimeline().time_total*(1000/Timeline.getTimeline().time_unit))*Timeline.getTimeline().getTimeUnitWidth(), getHeight()); 86 | setPreferredSize(new Dimension((Timeline.getTimeline().time_total*(1000/Timeline.getTimeline().time_unit))*Timeline.getTimeline().getTimeUnitWidth(), getHeight())); 87 | } 88 | repaint(); 89 | } 90 | 91 | public void refresh_block() { 92 | HRPane ablock; 93 | for (int i = 0; i < Timeline.getTimeline().getBlocks().size(); i++) { 94 | ablock = Timeline.getTimeline().getBlocks().get(i); 95 | int x = time_to_x(ablock.time_start); 96 | ablock.setSize(time_to_x(ablock.time_end)-x,Timeline.getTimeline().track_hight-1); 97 | ablock.setLocation(x, 1+Timeline.getTimeline().ruler_hight+(ablock.layer-1)*Timeline.getTimeline().track_hight); 98 | } 99 | setPreferredSize(new Dimension((Timeline.getTimeline().time_total*(1000/Timeline.getTimeline().time_unit))*Timeline.getTimeline().getTimeUnitWidth(), getHeight())); 100 | paintAll(getGraphics()); 101 | paintChildren(getGraphics()); 102 | repaint(); 103 | } 104 | 105 | public void remove_block(HRPane bye) { 106 | remove(bye); 107 | requestFocusInWindow(); 108 | repaint(); 109 | } 110 | 111 | public void setPlayhead(int x) { 112 | playhead = x; 113 | //head.setLocation(x, 0); 114 | } 115 | 116 | public int getPlayhead() { 117 | return playhead; 118 | } 119 | 120 | @Override 121 | protected void paintComponent(Graphics g) { 122 | System.out.println("paint timeline"); 123 | g.setColor(new Color(30,30,30)); 124 | g.fillRect(0, 0, getWidth(), Timeline.getTimeline().ruler_hight); 125 | g.setColor(new Color(40,40,40)); 126 | g.fillRect(0, Timeline.getTimeline().ruler_hight, getWidth(), getHeight()); 127 | //画标尺 128 | g.setColor(Color.WHITE); 129 | for (int i = 0; i <= (Timeline.getTimeline().time_total*1000)/Timeline.getTimeline().time_unit; i++) { 130 | if (i%(1000/Timeline.getTimeline().time_unit) == 0) { 131 | g.drawLine(i*Timeline.getTimeline().getTimeUnitWidth()+1, 1, i*Timeline.getTimeline().getTimeUnitWidth()+1, 5); 132 | //g.drawString((i/(1000/Timeline.getTimeline().time_unit))+"s", i*Timeline.getTimeline().getTimeUnitWidth()-5, Timeline.getTimeline().ruler_hight-2); 133 | } 134 | 135 | } 136 | //画层框 137 | g.setColor(new Color(40,50,60)); 138 | g.drawLine(0, Timeline.getTimeline().ruler_hight, getWidth(), Timeline.getTimeline().ruler_hight); 139 | g.drawLine(0, Timeline.getTimeline().ruler_hight+Timeline.getTimeline().track_hight, getWidth(), Timeline.getTimeline().ruler_hight+Timeline.getTimeline().track_hight); 140 | g.drawLine(0, Timeline.getTimeline().ruler_hight+Timeline.getTimeline().track_hight*2, getWidth(), Timeline.getTimeline().ruler_hight+Timeline.getTimeline().track_hight*2); 141 | g.drawLine(0, Timeline.getTimeline().ruler_hight+Timeline.getTimeline().track_hight*3, getWidth(), Timeline.getTimeline().ruler_hight+Timeline.getTimeline().track_hight*3); 142 | g.drawLine(0, Timeline.getTimeline().ruler_hight+Timeline.getTimeline().track_hight*4, getWidth(), Timeline.getTimeline().ruler_hight+Timeline.getTimeline().track_hight*4); 143 | g.drawLine(0, Timeline.getTimeline().ruler_hight+Timeline.getTimeline().track_hight*5, getWidth(), Timeline.getTimeline().ruler_hight+Timeline.getTimeline().track_hight*5); 144 | //画选定层的高亮显示 145 | g.setColor(new Color(40,43,50)); 146 | g.fillRect(0, (selected_layer-1)*Timeline.getTimeline().track_hight+Timeline.getTimeline().ruler_hight+1, getWidth(), Timeline.getTimeline().track_hight-1); 147 | //画播放头 148 | g.setColor(Color.RED); 149 | g.drawLine(playhead,0,playhead,getHeight()); 150 | g.drawLine(playhead-3, 0, playhead+3, 0); 151 | g.drawLine(playhead-2, 1, playhead+2, 1); 152 | g.drawLine(playhead-1, 2, playhead+1, 2); 153 | } 154 | 155 | 156 | private void init() { 157 | this.addMouseListener(new MouseListener() { 158 | 159 | @Override 160 | public void mouseClicked(MouseEvent e) { 161 | // TODO Auto-generated method stub 162 | requestFocus(); 163 | playhead = e.getX(); 164 | Timeline.getTimeline().setCurrTime((long) ((playhead-1)*((float)Timeline.getTimeline().time_unit/Timeline.getTimeline().getTimeUnitWidth()))); 165 | if (e.getY() > Timeline.getTimeline().ruler_hight) { 166 | selected_layer = (e.getY()-Timeline.getTimeline().ruler_hight)/Timeline.getTimeline().track_hight + 1; 167 | } 168 | 169 | repaint(); 170 | } 171 | 172 | @Override 173 | public void mouseEntered(MouseEvent arg0) { 174 | // TODO Auto-generated method stub 175 | 176 | } 177 | 178 | @Override 179 | public void mouseExited(MouseEvent arg0) { 180 | // TODO Auto-generated method stub 181 | 182 | } 183 | 184 | @Override 185 | public void mousePressed(MouseEvent e) { 186 | System.out.println("--------------------"); 187 | Timeline.getTimeline().setPlaying(false); 188 | playhead = e.getX(); 189 | repaint(); 190 | } 191 | 192 | @Override 193 | public void mouseReleased(MouseEvent arg0) { 194 | // TODO Auto-generated method stub 195 | 196 | } 197 | 198 | }); 199 | this.addMouseMotionListener(new MouseMotionListener() { 200 | 201 | @Override 202 | public void mouseMoved(MouseEvent arg0) { 203 | // TODO Auto-generated method stub 204 | 205 | } 206 | 207 | @Override 208 | public void mouseDragged(MouseEvent e) { 209 | if (e.getX() >= 1) { 210 | if (e.getX() >= getWidth()) { 211 | playhead = getWidth(); 212 | }else { 213 | playhead = e.getX(); 214 | } 215 | Timeline.getTimeline().setCurrTime((long) ((playhead-1)*((float)Timeline.getTimeline().time_unit/Timeline.getTimeline().getTimeUnitWidth()))); 216 | }else { 217 | playhead = 1; 218 | Timeline.getTimeline().setCurrTime(0); 219 | } 220 | repaint(); 221 | 222 | } 223 | }); 224 | this.addKeyListener(new KeyListener() { 225 | 226 | @Override 227 | public void keyTyped(KeyEvent arg0) { 228 | // TODO Auto-generated method stub 229 | 230 | } 231 | 232 | @Override 233 | public void keyReleased(KeyEvent arg0) { 234 | shiftdrag = false; 235 | 236 | } 237 | 238 | @Override 239 | public void keyPressed(KeyEvent e) { 240 | int k = e.getKeyCode(); 241 | //System.out.println(k); 242 | if (e.isShiftDown()) {//垂直拖放 243 | shiftdrag = true; 244 | } 245 | if (k == 32) {//SPACE 246 | TimelineX.getTimelineX().play(); 247 | }else if (k == 37) {//方向键左 248 | if (!Timeline.getTimeline().getPlaying() && playhead > 1) { 249 | if (e.isShiftDown()) {//如果按下Shift则按10像素移动 250 | playhead -= 10; 251 | }else { 252 | playhead --; 253 | } 254 | Timeline.getTimeline().setCurrTime((long) ((playhead-1)*((float)Timeline.getTimeline().time_unit/Timeline.getTimeline().getTimeUnitWidth()))); 255 | repaint(); 256 | } 257 | }else if (k == 39) {//方向键右 258 | if (!Timeline.getTimeline().getPlaying() && playhead < getWidth()) { 259 | if (e.isShiftDown()) {//如果按下Shift则按10像素移动 260 | playhead += 10; 261 | }else { 262 | playhead ++; 263 | } 264 | Timeline.getTimeline().setCurrTime((long) ((playhead-1)*((float)Timeline.getTimeline().time_unit/Timeline.getTimeline().getTimeUnitWidth()))); 265 | repaint(); 266 | } 267 | } 268 | } 269 | }); 270 | this.addFocusListener(new FocusListener() { 271 | 272 | @Override 273 | public void focusLost(FocusEvent e) { 274 | ((JScrollPane) getParent().getParent()).setBorder(javax.swing.BorderFactory 275 | .createLineBorder(new java.awt.Color(20,20,0))); 276 | } 277 | 278 | @Override 279 | public void focusGained(FocusEvent e) { 280 | ((JScrollPane) getParent().getParent()).setBorder(javax.swing.BorderFactory 281 | .createLineBorder(new java.awt.Color(255, 102, 0))); 282 | } 283 | }); 284 | } 285 | 286 | } 287 | -------------------------------------------------------------------------------- /bin/views/XWindow.form: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | -------------------------------------------------------------------------------- /src/views/EmbeddedMediaPlayerComponentX.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @author acely 3 | * 本程序由ACELY创作,开源代码仅供参考交流。不提供任何技术支持和质量保证。 4 | * 禁止修改、传播、再次分发以及任何商业用途。不得将部分或全部代码应用于其他任何软件。 5 | */ 6 | package views; 7 | 8 | import java.awt.BorderLayout; 9 | import java.awt.Canvas; 10 | import java.awt.Color; 11 | import java.awt.Container; 12 | import java.awt.Cursor; 13 | import java.awt.Image; 14 | import java.awt.Panel; 15 | import java.awt.Point; 16 | import java.awt.Toolkit; 17 | import java.awt.Window; 18 | import java.awt.image.BufferedImage; 19 | 20 | import javax.swing.JFrame; 21 | import javax.swing.JPanel; 22 | import javax.swing.JWindow; 23 | 24 | import uk.co.caprica.vlcj.binding.internal.libvlc_media_t; 25 | import uk.co.caprica.vlcj.logger.Logger; 26 | import uk.co.caprica.vlcj.player.MediaPlayer; 27 | import uk.co.caprica.vlcj.player.MediaPlayerEventListener; 28 | import uk.co.caprica.vlcj.player.MediaPlayerFactory; 29 | import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer; 30 | import uk.co.caprica.vlcj.player.embedded.FullScreenStrategy; 31 | import uk.co.caprica.vlcj.player.embedded.videosurface.CanvasVideoSurface; 32 | 33 | /** 34 | * Encapsulation of an embedded media player. 35 | *

36 | * This component encapsulates a media player and an associated video surface suitable for embedding 37 | * inside a graphical user interface. 38 | *

39 | * Most implementation details, like creating a factory and connecting the various objects together, 40 | * are encapsulated. 41 | *

42 | * The default implementation will work out-of-the-box, but there are various template methods 43 | * available to sub-classes to tailor the behaviour of the component. 44 | *

45 | * This class implements the most the most common use-case for an embedded media player and is 46 | * intended to enable a developer to get quickly started with the vlcj framework. More advanced 47 | * applications are free to directly use the {@link MediaPlayerFactory}, if required, as has always 48 | * been the case. 49 | *

50 | * This component also implements the various media player listener interfaces, consequently an 51 | * implementation sub-class can simply override those listener methods to handle events. 52 | *

53 | * Applications can get a handle to the underlying media player object by invoking 54 | * {@link #getMediaPlayer()}. 55 | *

56 | * To use, simply create an instance of this class and add it to a visual container component like a 57 | * {@link JPanel} (or any other {@link Container}). 58 | *

59 | * For example, here a media player component is used directly as the content pane of a 60 | * {@link JFrame}, and only two lines of code that use vlcj are required: 61 | * 62 | *

 63 |  * frame = new JFrame();
 64 |  * mediaPlayerComponent = new EmbeddedMediaPlayerComponent(); // <--- 1
 65 |  * frame.setContentPane(mediaPlayerComponent);
 66 |  * frame.setSize(1050, 600);
 67 |  * frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 68 |  * frame.setVisible(true);
 69 |  * mediaPlayerComponent.getMediaPlayer().playMedia(mrl); // <--- 2
 70 |  * 
71 | * 72 | * An example of a sub-class to tailor behaviours and override event handlers: 73 | * 74 | *
 75 |  * mediaPlayerComponent = new EmbeddedMediaPlayerComponent() {
 76 |  *     protected String[] onGetMediaPlayerFactoryArgs() {
 77 |  *         return new String[] {"--no-video-title-show"};
 78 |  *     }
 79 |  *
 80 |  *     protected FullScreenStrategy onGetFullScreenStrategy() {
 81 |  *         return new XFullScreenStrategy(frame);
 82 |  *     }
 83 |  *
 84 |  *     public void videoOutputAvailable(MediaPlayer mediaPlayer, boolean videoOutput) {
 85 |  *     }
 86 |  *
 87 |  *     public void error(MediaPlayer mediaPlayer) {
 88 |  *     }
 89 |  *
 90 |  *     public void finished(MediaPlayer mediaPlayer) {
 91 |  *     }
 92 |  * };
 93 |  * 
94 | * When the media player component is no longer needed, it should be released by invoking the 95 | * {@link #release()} method. 96 | *

97 | * Since the media player factory associated by this component may be created by this component 98 | * itself or may be shared with some other media player resources it is the responsibility of 99 | * the application to also release the media player factory at the appropriate time. 100 | *

101 | * It is always a better strategy to reuse media player components, rather than repeatedly creating 102 | * and destroying instances. 103 | */ 104 | @SuppressWarnings("serial") 105 | public class EmbeddedMediaPlayerComponentX extends Panel implements MediaPlayerEventListener { 106 | 107 | /** 108 | * Default factory initialisation arguments. 109 | *

110 | * Sub-classes may totally disregard these arguments and provide their own. 111 | *

112 | * A sub-class has access to these default arguments so new ones could be merged with these if 113 | * required. 114 | */ 115 | protected static final String[] DEFAULT_FACTORY_ARGUMENTS = { 116 | "--ignore-config", 117 | "--video-title=vlcj video output", 118 | "--no-plugins-cache", 119 | "--no-video-title-show", 120 | "--no-subsdec-autodetect-utf8", 121 | "--subsdec-encoding=GB18030", 122 | "--no-snapshot-preview", 123 | "--quiet", 124 | "--quiet-synchro", 125 | "--sub-filter=logo:marq", 126 | "--intf=dummy" 127 | }; 128 | 129 | /** 130 | * Media player factory. 131 | */ 132 | private final MediaPlayerFactory mediaPlayerFactory; 133 | 134 | /** 135 | * Media player. 136 | */ 137 | private final EmbeddedMediaPlayer mediaPlayer; 138 | 139 | /** 140 | * Video surface canvas. 141 | */ 142 | private final Canvas canvas; 143 | 144 | /** 145 | * Video surface encapsulation. 146 | */ 147 | private final CanvasVideoSurface videoSurface; 148 | 149 | /** 150 | * Blank cursor to use when the cursor is disabled. 151 | */ 152 | private Cursor blankCursor; 153 | 154 | /** 155 | * Construct a media player component. 156 | */ 157 | public EmbeddedMediaPlayerComponentX() { 158 | setFocusable(false); 159 | // Create the native resources 160 | mediaPlayerFactory = onGetMediaPlayerFactory(); 161 | mediaPlayer = mediaPlayerFactory.newEmbeddedMediaPlayer(onGetFullScreenStrategy()); 162 | canvas = onGetCanvas(); 163 | videoSurface = mediaPlayerFactory.newVideoSurface(canvas); 164 | mediaPlayer.setVideoSurface(videoSurface); 165 | // Prepare the user interface 166 | setBackground(Color.black); 167 | setLayout(new BorderLayout()); 168 | add(canvas, BorderLayout.CENTER); 169 | // Register listeners 170 | mediaPlayer.addMediaPlayerEventListener(this); 171 | // Set the overlay 172 | mediaPlayer.setOverlay(onGetOverlay()); 173 | // Sub-class initialisation 174 | onAfterConstruct(); 175 | } 176 | 177 | /** 178 | * Get the media player factory reference. 179 | * 180 | * @return media player factory 181 | */ 182 | public final MediaPlayerFactory getMediaPlayerFactory() { 183 | return mediaPlayerFactory; 184 | } 185 | 186 | /** 187 | * Get the embedded media player reference. 188 | *

189 | * An application uses this handle to control the media player, add listeners and so on. 190 | * 191 | * @return media player 192 | */ 193 | public final EmbeddedMediaPlayer getMediaPlayer() { 194 | return mediaPlayer; 195 | } 196 | 197 | /** 198 | * Get the video surface {@link Canvas} component. 199 | *

200 | * An application may want to add key/mouse listeners to the video surface component. 201 | * 202 | * @return video surface component 203 | */ 204 | public final Canvas getVideoSurface() { 205 | return canvas; 206 | } 207 | 208 | /** 209 | * Enable or disable the mouse cursor when it is over the component. 210 | * 211 | * @param enabled true to enable (show) the cursor; false to disable (hide) it 212 | */ 213 | public final void setCursorEnabled(boolean enabled) { 214 | setCursor(enabled ? null : getBlankCursor()); 215 | } 216 | 217 | /** 218 | * Release the media player component and the associated native media player resources. 219 | *

220 | * The associated media player factory will not be released, the client 221 | * application is responsible for releasing the factory at the appropriate time. 222 | */ 223 | public final void release() { 224 | onBeforeRelease(); 225 | mediaPlayer.release(); 226 | onAfterRelease(); 227 | } 228 | 229 | /** 230 | * Release the media player component and the associated media player factory. 231 | *

232 | * Optionally release the media player factory. 233 | *

234 | * This method invokes {@link #release()}, then depending on the value of the releaseFactory 235 | * parameter the associated factory will also be released. 236 | * 237 | * @param releaseFactory true if the factory should also be released; false if it should not 238 | */ 239 | public final void release(boolean releaseFactory) { 240 | Logger.debug("release(releaseFactory={})", releaseFactory); 241 | release(); 242 | if(releaseFactory) { 243 | Logger.debug("Releasing media player factory"); 244 | mediaPlayerFactory.release(); 245 | } 246 | } 247 | 248 | /** 249 | * Create a blank 1x1 image to use when the cursor is disabled. 250 | * 251 | * @return cursor 252 | */ 253 | private Cursor getBlankCursor() { 254 | if(blankCursor == null) { 255 | Image blankImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); 256 | blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(blankImage, new Point(0, 0), ""); 257 | } 258 | return blankCursor; 259 | } 260 | 261 | /** 262 | * Template method to create a media player factory. 263 | *

264 | * The default implementation will invoke the {@link #onGetMediaPlayerFactoryArgs()} template 265 | * method. 266 | * 267 | * @return media player factory 268 | */ 269 | protected MediaPlayerFactory onGetMediaPlayerFactory() { 270 | return new MediaPlayerFactory(onGetMediaPlayerFactoryArgs()); 271 | } 272 | 273 | /** 274 | * Template method to obtain the initialisation arguments used to create the media player 275 | * factory instance. 276 | *

277 | * If a sub-class overrides the {@link #onGetMediaPlayerFactory()} template method there is no 278 | * guarantee that {@link #onGetMediaPlayerFactoryArgs()} will be called. 279 | * 280 | * @return media player factory initialisation arguments 281 | */ 282 | protected String[] onGetMediaPlayerFactoryArgs() { 283 | return DEFAULT_FACTORY_ARGUMENTS; 284 | } 285 | 286 | /** 287 | * Template method to obtain a full-screen strategy implementation. 288 | *

289 | * The default implementation does not provide any full-screen strategy. 290 | * 291 | * @return full-screen strategy implementation 292 | */ 293 | protected FullScreenStrategy onGetFullScreenStrategy() { 294 | return null; 295 | } 296 | 297 | /** 298 | * Template method to obtain a video surface {@link Canvas} component. 299 | *

300 | * The default implementation simply returns an ordinary Canvas with a black background. 301 | * 302 | * @return video surface component 303 | */ 304 | protected Canvas onGetCanvas() { 305 | Canvas canvas = new Canvas(); 306 | canvas.setBackground(Color.black); 307 | return canvas; 308 | } 309 | 310 | /** 311 | * Template method to obtain an overlay component. 312 | *

313 | * The default implementation does not provide an overlay. 314 | *

315 | * The overlay component may be a {@link Window} or a Window sub-class such as 316 | * {@link JWindow}. 317 | * 318 | * @return overlay component 319 | */ 320 | protected Window onGetOverlay() { 321 | return null; 322 | } 323 | 324 | /** 325 | * Template method invoked at the end of the media player constructor. 326 | */ 327 | protected void onAfterConstruct() { 328 | } 329 | 330 | /** 331 | * Template method invoked immediately prior to releasing the media player and media player 332 | * factory instances. 333 | */ 334 | protected void onBeforeRelease() { 335 | } 336 | 337 | /** 338 | * Template method invoked immediately after releasing the media player and media player factory 339 | * instances. 340 | */ 341 | protected void onAfterRelease() { 342 | } 343 | 344 | // === MediaPlayerEventListener ============================================= 345 | 346 | @Override 347 | public void mediaChanged(MediaPlayer mediaPlayer, libvlc_media_t media, String mrl) { 348 | } 349 | 350 | @Override 351 | public void opening(MediaPlayer mediaPlayer) { 352 | } 353 | 354 | @Override 355 | public void buffering(MediaPlayer mediaPlayer, float newCache) { 356 | } 357 | 358 | @Override 359 | public void playing(MediaPlayer mediaPlayer) { 360 | } 361 | 362 | @Override 363 | public void paused(MediaPlayer mediaPlayer) { 364 | } 365 | 366 | @Override 367 | public void stopped(MediaPlayer mediaPlayer) { 368 | } 369 | 370 | @Override 371 | public void forward(MediaPlayer mediaPlayer) { 372 | } 373 | 374 | @Override 375 | public void backward(MediaPlayer mediaPlayer) { 376 | } 377 | 378 | @Override 379 | public void finished(MediaPlayer mediaPlayer) { 380 | } 381 | 382 | @Override 383 | public void timeChanged(MediaPlayer mediaPlayer, long newTime) { 384 | } 385 | 386 | @Override 387 | public void positionChanged(MediaPlayer mediaPlayer, float newPosition) { 388 | } 389 | 390 | @Override 391 | public void seekableChanged(MediaPlayer mediaPlayer, int newSeekable) { 392 | } 393 | 394 | @Override 395 | public void pausableChanged(MediaPlayer mediaPlayer, int newSeekable) { 396 | } 397 | 398 | @Override 399 | public void titleChanged(MediaPlayer mediaPlayer, int newTitle) { 400 | } 401 | 402 | @Override 403 | public void snapshotTaken(MediaPlayer mediaPlayer, String filename) { 404 | } 405 | 406 | @Override 407 | public void lengthChanged(MediaPlayer mediaPlayer, long newLength) { 408 | } 409 | 410 | @Override 411 | public void videoOutput(MediaPlayer mediaPlayer, int newCount) { 412 | } 413 | 414 | @Override 415 | public void error(MediaPlayer mediaPlayer) { 416 | } 417 | 418 | @Override 419 | public void mediaMetaChanged(MediaPlayer mediaPlayer, int metaType) { 420 | } 421 | 422 | @Override 423 | public void mediaSubItemAdded(MediaPlayer mediaPlayer, libvlc_media_t subItem) { 424 | } 425 | 426 | @Override 427 | public void mediaDurationChanged(MediaPlayer mediaPlayer, long newDuration) { 428 | } 429 | 430 | @Override 431 | public void mediaParsedChanged(MediaPlayer mediaPlayer, int newStatus) { 432 | } 433 | 434 | @Override 435 | public void mediaFreed(MediaPlayer mediaPlayer) { 436 | } 437 | 438 | @Override 439 | public void mediaStateChanged(MediaPlayer mediaPlayer, int newState) { 440 | } 441 | 442 | @Override 443 | public void newMedia(MediaPlayer mediaPlayer) { 444 | } 445 | 446 | @Override 447 | public void subItemPlayed(MediaPlayer mediaPlayer, int subItemIndex) { 448 | } 449 | 450 | @Override 451 | public void subItemFinished(MediaPlayer mediaPlayer, int subItemIndex) { 452 | } 453 | 454 | @Override 455 | public void endOfSubItems(MediaPlayer mediaPlayer) { 456 | } 457 | } 458 | -------------------------------------------------------------------------------- /src/views/XWindow.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @author acely 3 | * 本程序由ACELY创作,开源代码仅供参考交流。不提供任何技术支持和质量保证。 4 | * 禁止修改、传播、再次分发以及任何商业用途。不得将部分或全部代码应用于其他任何软件。 5 | */ 6 | package views; 7 | 8 | import java.awt.BorderLayout; 9 | import java.awt.Cursor; 10 | import java.awt.dnd.DnDConstants; 11 | import java.awt.dnd.DropTarget; 12 | import java.awt.Polygon; 13 | import java.awt.dnd.DropTargetDragEvent; 14 | import java.awt.dnd.DropTargetDropEvent; 15 | import java.awt.dnd.DropTargetEvent; 16 | import java.awt.dnd.DropTargetListener; 17 | 18 | import javax.swing.JFrame; 19 | import javax.swing.JScrollPane; 20 | 21 | import com.sun.awt.AWTUtilities; 22 | 23 | 24 | 25 | 26 | import modles.Timeline; 27 | import controls.DispTime; 28 | import controls.TimelineX; 29 | 30 | /** 31 | * 32 | * @author __USER__ 33 | */ 34 | public class XWindow extends javax.swing.JFrame implements DropTargetListener{ 35 | 36 | /** 37 | * 38 | */ 39 | private static final long serialVersionUID = 1L; 40 | private EmbeddedMediaPlayerComponentX playpane; 41 | int sx, sy; 42 | 43 | /** Creates new form XWindow */ 44 | public XWindow() { 45 | playpane = new EmbeddedMediaPlayerComponentX(); 46 | initComponents(); 47 | playpancontainer.setLayout(new BorderLayout()); 48 | playpancontainer.add(playpane, BorderLayout.CENTER); 49 | /*int[] pxs = { 2, 703, 703, 920, 920, 2 }; 50 | int[] pys = { 30, 30, 0, 0, 607, 607 }; 51 | Polygon shape = new Polygon(pxs, pys, 6); 52 | AWTUtilities.setWindowShape(this, shape);*/ 53 | new DispTime(showtime).start(); 54 | new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, this); 55 | } 56 | 57 | //GEN-BEGIN:initComponents 58 | // 59 | private void initComponents() { 60 | 61 | toppane = new javax.swing.JPanel(); 62 | jScrollPane1 = new JScrollPane(TimelinePane.getTLPane()); 63 | showtime = new javax.swing.JLabel(); 64 | jButton1 = new javax.swing.JButton(); 65 | jLabel1 = new javax.swing.JLabel(); 66 | playpancontainer = new javax.swing.JPanel(); 67 | exit = new javax.swing.JLabel(); 68 | minimize = new javax.swing.JLabel(); 69 | volume = new javax.swing.JSlider(); 70 | jButton2 = new javax.swing.JButton(); 71 | 72 | setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 73 | setBackground(java.awt.SystemColor.controlDkShadow); 74 | setMinimumSize(new java.awt.Dimension(720, 480)); 75 | setUndecorated(true); 76 | addWindowListener(new java.awt.event.WindowAdapter() { 77 | public void windowClosing(java.awt.event.WindowEvent evt) { 78 | formWindowClosing(evt); 79 | } 80 | }); 81 | 82 | toppane.setBackground(new java.awt.Color(50, 50, 50)); 83 | toppane.addMouseListener(new java.awt.event.MouseAdapter() { 84 | public void mousePressed(java.awt.event.MouseEvent evt) { 85 | toppaneMousePressed(evt); 86 | } 87 | }); 88 | toppane.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() { 89 | public void mouseDragged(java.awt.event.MouseEvent evt) { 90 | toppaneMouseDragged(evt); 91 | } 92 | }); 93 | 94 | jScrollPane1.setBorder(javax.swing.BorderFactory 95 | .createLineBorder(new java.awt.Color(255, 102, 0))); 96 | jScrollPane1 97 | .setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); 98 | 99 | showtime.setFont(new java.awt.Font("微软雅黑", 0, 14)); 100 | showtime.setForeground(new java.awt.Color(255, 153, 0)); 101 | showtime.setText("0s"); 102 | 103 | jButton1.setText("ADD BLOCK"); 104 | jButton1.setFocusable(false); 105 | jButton1.addActionListener(new java.awt.event.ActionListener() { 106 | public void actionPerformed(java.awt.event.ActionEvent evt) { 107 | jButton1ActionPerformed(evt); 108 | } 109 | }); 110 | 111 | jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource( 112 | "/views/logo.png"))); // NOI18N 113 | 114 | playpancontainer.setBorder(javax.swing.BorderFactory.createLineBorder( 115 | new java.awt.Color(27, 27, 27), 2)); 116 | 117 | javax.swing.GroupLayout playpancontainerLayout = new javax.swing.GroupLayout( 118 | playpancontainer); 119 | playpancontainer.setLayout(playpancontainerLayout); 120 | playpancontainerLayout.setHorizontalGroup(playpancontainerLayout 121 | .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 122 | .addGap(0, 789, Short.MAX_VALUE)); 123 | playpancontainerLayout.setVerticalGroup(playpancontainerLayout 124 | .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 125 | .addGap(0, 444, Short.MAX_VALUE)); 126 | 127 | exit.setIcon(new javax.swing.ImageIcon(getClass().getResource( 128 | "/views/x.png"))); // NOI18N 129 | exit.addMouseListener(new java.awt.event.MouseAdapter() { 130 | public void mouseEntered(java.awt.event.MouseEvent evt) { 131 | exitMouseEntered(evt); 132 | } 133 | 134 | public void mouseExited(java.awt.event.MouseEvent evt) { 135 | exitMouseExited(evt); 136 | } 137 | 138 | public void mouseReleased(java.awt.event.MouseEvent evt) { 139 | exitMouseReleased(evt); 140 | } 141 | }); 142 | 143 | minimize.setIcon(new javax.swing.ImageIcon(getClass().getResource( 144 | "/views/min.png"))); // NOI18N 145 | minimize.addMouseListener(new java.awt.event.MouseAdapter() { 146 | public void mouseEntered(java.awt.event.MouseEvent evt) { 147 | minimizeMouseEntered(evt); 148 | } 149 | 150 | public void mouseExited(java.awt.event.MouseEvent evt) { 151 | minimizeMouseExited(evt); 152 | } 153 | 154 | public void mouseReleased(java.awt.event.MouseEvent evt) { 155 | minimizeMouseReleased(evt); 156 | } 157 | }); 158 | 159 | volume.setFocusable(false); 160 | volume.setOpaque(false); 161 | volume.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() { 162 | public void mouseDragged(java.awt.event.MouseEvent evt) { 163 | volumeMouseDragged(evt); 164 | } 165 | }); 166 | 167 | jButton2.setText("CLEAR"); 168 | jButton2.setFocusable(false); 169 | jButton2.addActionListener(new java.awt.event.ActionListener() { 170 | public void actionPerformed(java.awt.event.ActionEvent evt) { 171 | jButton2ActionPerformed(evt); 172 | } 173 | }); 174 | 175 | javax.swing.GroupLayout toppaneLayout = new javax.swing.GroupLayout( 176 | toppane); 177 | toppane.setLayout(toppaneLayout); 178 | toppaneLayout 179 | .setHorizontalGroup(toppaneLayout 180 | .createParallelGroup( 181 | javax.swing.GroupLayout.Alignment.LEADING) 182 | .addGroup( 183 | toppaneLayout 184 | .createSequentialGroup() 185 | .addContainerGap() 186 | .addGroup( 187 | toppaneLayout 188 | .createParallelGroup( 189 | javax.swing.GroupLayout.Alignment.LEADING) 190 | .addGroup( 191 | javax.swing.GroupLayout.Alignment.TRAILING, 192 | toppaneLayout 193 | .createSequentialGroup() 194 | .addComponent( 195 | playpancontainer, 196 | javax.swing.GroupLayout.DEFAULT_SIZE, 197 | javax.swing.GroupLayout.DEFAULT_SIZE, 198 | Short.MAX_VALUE) 199 | .addPreferredGap( 200 | javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) 201 | .addGroup( 202 | toppaneLayout 203 | .createParallelGroup( 204 | javax.swing.GroupLayout.Alignment.LEADING) 205 | .addGroup( 206 | toppaneLayout 207 | .createParallelGroup( 208 | javax.swing.GroupLayout.Alignment.LEADING) 209 | .addGroup( 210 | javax.swing.GroupLayout.Alignment.TRAILING, 211 | toppaneLayout 212 | .createSequentialGroup() 213 | .addComponent( 214 | minimize) 215 | .addPreferredGap( 216 | javax.swing.LayoutStyle.ComponentPlacement.RELATED) 217 | .addComponent( 218 | exit)) 219 | .addComponent( 220 | jLabel1)) 221 | .addGroup( 222 | toppaneLayout 223 | .createParallelGroup( 224 | javax.swing.GroupLayout.Alignment.TRAILING, 225 | false) 226 | .addComponent( 227 | jButton2, 228 | javax.swing.GroupLayout.Alignment.LEADING, 229 | javax.swing.GroupLayout.DEFAULT_SIZE, 230 | javax.swing.GroupLayout.DEFAULT_SIZE, 231 | Short.MAX_VALUE) 232 | .addComponent( 233 | jButton1, 234 | javax.swing.GroupLayout.Alignment.LEADING, 235 | javax.swing.GroupLayout.DEFAULT_SIZE, 236 | javax.swing.GroupLayout.DEFAULT_SIZE, 237 | Short.MAX_VALUE)))) 238 | .addComponent( 239 | jScrollPane1, 240 | javax.swing.GroupLayout.DEFAULT_SIZE, 241 | 1005, 242 | Short.MAX_VALUE) 243 | .addGroup( 244 | toppaneLayout 245 | .createSequentialGroup() 246 | .addComponent( 247 | showtime, 248 | javax.swing.GroupLayout.PREFERRED_SIZE, 249 | 134, 250 | javax.swing.GroupLayout.PREFERRED_SIZE) 251 | .addPreferredGap( 252 | javax.swing.LayoutStyle.ComponentPlacement.RELATED, 253 | 671, 254 | Short.MAX_VALUE) 255 | .addComponent( 256 | volume, 257 | javax.swing.GroupLayout.PREFERRED_SIZE, 258 | javax.swing.GroupLayout.DEFAULT_SIZE, 259 | javax.swing.GroupLayout.PREFERRED_SIZE))) 260 | .addContainerGap())); 261 | toppaneLayout 262 | .setVerticalGroup(toppaneLayout 263 | .createParallelGroup( 264 | javax.swing.GroupLayout.Alignment.LEADING) 265 | .addGroup( 266 | toppaneLayout 267 | .createSequentialGroup() 268 | .addContainerGap() 269 | .addComponent(jLabel1) 270 | .addPreferredGap( 271 | javax.swing.LayoutStyle.ComponentPlacement.RELATED) 272 | .addGroup( 273 | toppaneLayout 274 | .createParallelGroup( 275 | javax.swing.GroupLayout.Alignment.LEADING) 276 | .addGroup( 277 | toppaneLayout 278 | .createSequentialGroup() 279 | .addComponent( 280 | exit) 281 | .addGap(309, 282 | 309, 283 | 309) 284 | .addComponent( 285 | jButton2) 286 | .addPreferredGap( 287 | javax.swing.LayoutStyle.ComponentPlacement.RELATED) 288 | .addComponent( 289 | jButton1) 290 | .addGap(59, 291 | 59, 292 | 59)) 293 | .addGroup( 294 | toppaneLayout 295 | .createSequentialGroup() 296 | .addComponent( 297 | playpancontainer, 298 | javax.swing.GroupLayout.DEFAULT_SIZE, 299 | javax.swing.GroupLayout.DEFAULT_SIZE, 300 | Short.MAX_VALUE) 301 | .addPreferredGap( 302 | javax.swing.LayoutStyle.ComponentPlacement.RELATED)) 303 | .addGroup( 304 | toppaneLayout 305 | .createSequentialGroup() 306 | .addComponent( 307 | minimize) 308 | .addPreferredGap( 309 | javax.swing.LayoutStyle.ComponentPlacement.RELATED, 310 | 426, 311 | Short.MAX_VALUE))) 312 | .addGap(8, 8, 8) 313 | .addGroup( 314 | toppaneLayout 315 | .createParallelGroup( 316 | javax.swing.GroupLayout.Alignment.TRAILING, 317 | false) 318 | .addComponent(volume, 319 | 0, 0, 320 | Short.MAX_VALUE) 321 | .addComponent( 322 | showtime, 323 | javax.swing.GroupLayout.DEFAULT_SIZE, 324 | javax.swing.GroupLayout.DEFAULT_SIZE, 325 | Short.MAX_VALUE)) 326 | .addPreferredGap( 327 | javax.swing.LayoutStyle.ComponentPlacement.RELATED) 328 | .addComponent( 329 | jScrollPane1, 330 | javax.swing.GroupLayout.PREFERRED_SIZE, 331 | 170, 332 | javax.swing.GroupLayout.PREFERRED_SIZE) 333 | .addContainerGap())); 334 | 335 | javax.swing.GroupLayout layout = new javax.swing.GroupLayout( 336 | getContentPane()); 337 | getContentPane().setLayout(layout); 338 | layout.setHorizontalGroup(layout.createParallelGroup( 339 | javax.swing.GroupLayout.Alignment.LEADING).addComponent( 340 | toppane, javax.swing.GroupLayout.DEFAULT_SIZE, 341 | javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)); 342 | layout.setVerticalGroup(layout.createParallelGroup( 343 | javax.swing.GroupLayout.Alignment.LEADING).addComponent( 344 | toppane, javax.swing.GroupLayout.DEFAULT_SIZE, 345 | javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)); 346 | 347 | pack(); 348 | }// 349 | //GEN-END:initComponents 350 | 351 | private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) { 352 | Timeline.getTimeline().clearAll(); 353 | } 354 | 355 | private void volumeMouseDragged(java.awt.event.MouseEvent evt) { 356 | TimelineX.getTimelineX().setVolume(volume.getValue()); 357 | } 358 | 359 | private void minimizeMouseReleased(java.awt.event.MouseEvent evt) { 360 | setExtendedState(JFrame.ICONIFIED); 361 | } 362 | 363 | private void minimizeMouseExited(java.awt.event.MouseEvent evt) { 364 | minimize.setIcon(new javax.swing.ImageIcon(getClass().getResource( 365 | "/views/min.png"))); // NOI18N 366 | } 367 | 368 | private void minimizeMouseEntered(java.awt.event.MouseEvent evt) { 369 | minimize.setIcon(new javax.swing.ImageIcon(getClass().getResource( 370 | "/views/min_on.png"))); // NOI18N 371 | } 372 | 373 | private void exitMouseReleased(java.awt.event.MouseEvent evt) { 374 | playpane.getMediaPlayer().stop(); 375 | playpane.release(); 376 | System.exit(0); 377 | } 378 | 379 | private void exitMouseExited(java.awt.event.MouseEvent evt) { 380 | exit.setIcon(new javax.swing.ImageIcon(getClass().getResource( 381 | "/views/x.png"))); // NOI18N 382 | } 383 | 384 | private void exitMouseEntered(java.awt.event.MouseEvent evt) { 385 | exit.setIcon(new javax.swing.ImageIcon(getClass().getResource( 386 | "/views/x_on.png"))); // NOI18N 387 | } 388 | 389 | private void toppaneMouseDragged(java.awt.event.MouseEvent e) { 390 | setLocation(getX() + (e.getX() - sx), getY() + (e.getY() - sy)); 391 | } 392 | 393 | private void toppaneMousePressed(java.awt.event.MouseEvent e) { 394 | sx = e.getX(); 395 | sy = e.getY(); 396 | } 397 | 398 | private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { 399 | Timeline.getTimeline().add_block(new HRPane(""), 0, true); 400 | } 401 | 402 | private void formWindowClosing(java.awt.event.WindowEvent evt) { 403 | playpane.getMediaPlayer().stop(); 404 | playpane.release(); 405 | } 406 | 407 | /** 408 | * @param args the command line arguments 409 | */ 410 | public static void main(String args[]) { 411 | java.awt.EventQueue.invokeLater(new Runnable() { 412 | public void run() { 413 | new XWindow().setVisible(true); 414 | } 415 | }); 416 | } 417 | 418 | public EmbeddedMediaPlayerComponentX getPlayPane() { 419 | return playpane; 420 | } 421 | 422 | //GEN-BEGIN:variables 423 | // Variables declaration - do not modify 424 | private javax.swing.JLabel exit; 425 | private javax.swing.JButton jButton1; 426 | private javax.swing.JButton jButton2; 427 | private javax.swing.JLabel jLabel1; 428 | private javax.swing.JScrollPane jScrollPane1; 429 | private javax.swing.JLabel minimize; 430 | private javax.swing.JPanel playpancontainer; 431 | public javax.swing.JLabel showtime; 432 | private javax.swing.JPanel toppane; 433 | private javax.swing.JSlider volume; 434 | // End of variables declaration//GEN-END:variables 435 | 436 | @Override 437 | public void dragEnter(DropTargetDragEvent arg0) { 438 | setCursor(new Cursor(Cursor.MOVE_CURSOR)); 439 | } 440 | 441 | @Override 442 | public void dragExit(DropTargetEvent arg0) { 443 | setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); 444 | } 445 | 446 | @Override 447 | public void dragOver(DropTargetDragEvent arg0) { 448 | // TODO Auto-generated method stub 449 | 450 | } 451 | 452 | @Override 453 | public void drop(DropTargetDropEvent arg0) { 454 | setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); 455 | TimelineX.getTimelineX().readDroppedFile(arg0); 456 | } 457 | 458 | @Override 459 | public void dropActionChanged(DropTargetDragEvent arg0) { 460 | // TODO Auto-generated method stub 461 | 462 | } 463 | 464 | } 465 | -------------------------------------------------------------------------------- /src/views/HRPane.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @author acely 3 | * 本程序由ACELY创作,开源代码仅供参考交流。不提供任何技术支持和质量保证。 4 | * 禁止修改、传播、再次分发以及任何商业用途。不得将部分或全部代码应用于其他任何软件。 5 | */ 6 | package views; 7 | 8 | import java.awt.Color; 9 | import java.awt.Cursor; 10 | import java.awt.Graphics; 11 | import java.awt.event.FocusEvent; 12 | import java.awt.event.FocusListener; 13 | import java.awt.event.KeyEvent; 14 | import java.awt.event.KeyListener; 15 | import java.awt.event.MouseEvent; 16 | import java.awt.event.MouseListener; 17 | import java.awt.event.MouseMotionListener; 18 | 19 | import javax.swing.JLabel; 20 | import javax.swing.JPanel; 21 | import javax.swing.JTextField; 22 | 23 | import controls.TimelineX; 24 | import modles.Timeline; 25 | 26 | public class HRPane extends JPanel{ 27 | 28 | /** 29 | * 30 | */ 31 | private static final long serialVersionUID = 1L; 32 | JLabel text = new JLabel(); 33 | JTextField edittext = new JTextField(); 34 | //------------ 35 | int resize_anchor = 6;//调整块的宽度 36 | boolean on = false; 37 | boolean onleft = false; 38 | boolean onright = false; 39 | boolean pressed = false; 40 | boolean draging = false; 41 | boolean chosen = false;//has focus 42 | boolean usesnapvalue = false;//吸附后,从吸附点获取时间值,不使用坐标来计算时间 43 | boolean editing = false;//为true时不响应鼠标操作 44 | int drag_type = 0;//在拖拽时是移动还是缩放,1-左侧缩放 2-右侧缩放 3-移动 45 | int sx = 0;//鼠标按下时的x坐标 46 | int sy = 0;//鼠标按下时的y坐标 47 | int ex = 0;//鼠标松开时的x坐标 48 | int ey = 0;//鼠标松开时的x坐标 49 | int temp_width = 0;//鼠标按下时的块宽度 50 | int temp_x = 0;//鼠标按下时块在容器中de的x坐标 51 | int temp_y = 0;//鼠标按下时块在容器中de的y坐标 52 | int temp_blockend = 0; 53 | long snap_to_value = 0;//吸附点的时间值 54 | public int layer = 0; 55 | public int group = 1; 56 | public long time_start = 0; 57 | public long time_end = 0; 58 | //------------ 59 | //运单号200000540865 60 | public HRPane(String t) { 61 | setFocusable(true); 62 | setDoubleBuffered(true); 63 | setName(hashCode()+""); 64 | init(); 65 | text.setForeground(new Color(80,240,240)); 66 | edittext.setVisible(false);; 67 | edittext.setDragEnabled(false); 68 | edittext.setBackground(Color.DARK_GRAY); 69 | edittext.setForeground(Color.WHITE); 70 | edittext.setSelectionColor(Color.LIGHT_GRAY); 71 | edittext.setSelectedTextColor(Color.BLUE); 72 | text.setText(t); 73 | edittext.setText(t); 74 | setToolTipText(t); 75 | this.add(text); 76 | this.add(edittext); 77 | //-------------- 78 | } 79 | 80 | public void setText(String t) { 81 | text.setText(t); 82 | edittext.setText(t); 83 | } 84 | 85 | public String getText() { 86 | return text.getText(); 87 | } 88 | 89 | @Override 90 | protected void paintComponent(Graphics g) { 91 | //System.out.println("paint block"); 92 | text.setLocation(resize_anchor+5, getHeight()/2-8); 93 | text.setSize(getWidth()-2*resize_anchor-10,text.getHeight()); 94 | edittext.setLocation(resize_anchor+1,2); 95 | edittext.setSize(getWidth()-2*resize_anchor-10,Timeline.getTimeline().track_hight-6); 96 | // TODO Auto-generated method stub 97 | super.paintComponent(g); 98 | //画边框 99 | g.setColor(new Color(20,20,30)); 100 | g.drawRect(0, 0, getWidth()-1, getHeight()-1); 101 | //画填充 102 | if (on) { 103 | g.setColor(new Color(60,80,90)); 104 | }else { 105 | g.setColor(Color.DARK_GRAY); 106 | } 107 | g.fillRect(resize_anchor+1, 1, getWidth()-2*resize_anchor-2, getHeight()-2); 108 | //画选中标记 109 | if (chosen) { 110 | g.setColor(Color.RED); 111 | g.fillRect(resize_anchor+2, 1, getWidth()-2*resize_anchor-4, 2); 112 | } 113 | //画选拖拽中标记 114 | if (draging) { 115 | g.setColor(Color.LIGHT_GRAY); 116 | g.fillRect(resize_anchor+2, getHeight()-3, getWidth()-2*resize_anchor-4, 2); 117 | } 118 | //左侧的调整块 119 | if (onleft && !editing) { 120 | g.setColor(Color.RED); 121 | }else { 122 | g.setColor(getColor(group)); 123 | } 124 | g.fillRect(1, 1, resize_anchor, getHeight()-2); 125 | //右侧的调整块 126 | if (onright && !editing) { 127 | g.setColor(Color.RED); 128 | }else { 129 | g.setColor(getColor(group)); 130 | } 131 | g.fillRect(getWidth()-(resize_anchor+1), 1, resize_anchor, getHeight()-2); 132 | //--- 133 | } 134 | 135 | private Color getColor(int g) { 136 | switch (g) { 137 | case 1: 138 | return new Color(255,160,0); 139 | case 2: 140 | return new Color(80,225,25); 141 | case 3: 142 | return new Color(10,240,250); 143 | case 4: 144 | return new Color(20,125,255); 145 | case 5: 146 | return new Color(250,75,135); 147 | default:return Color.ORANGE; 148 | } 149 | 150 | } 151 | 152 | private void init() { 153 | this.addMouseMotionListener(new MouseMotionListener() { 154 | 155 | @Override 156 | public void mouseMoved(MouseEvent e) { 157 | if (editing) { 158 | return; 159 | } 160 | int x = e.getX(); 161 | int y = e.getY(); 162 | //左侧的调整块感应 163 | if (x >= 1 && x <= resize_anchor+1 && y >= 1 && y<= getHeight()-2) { 164 | boolean onleft_ori = onleft; 165 | onleft = true; 166 | if (onleft_ori != onleft) {//大大减少了repaint()的调用次数 167 | setCursor(new Cursor(Cursor.W_RESIZE_CURSOR)); 168 | repaint(); 169 | } 170 | }else { 171 | //右侧的调整块感应 172 | if (x >= getWidth()-(resize_anchor+1) && x <= getWidth()-2 && y >= 1 && y<= getHeight()-2) { 173 | boolean onright_ori = onright; 174 | onright = true; 175 | if (onright_ori != onright) {//大大减少了repaint()的调用次数 176 | setCursor(new Cursor(Cursor.W_RESIZE_CURSOR)); 177 | repaint(); 178 | } 179 | }else { 180 | boolean onleft_ori = onleft; 181 | boolean onright_ori = onright; 182 | onright = false; 183 | onleft = false; 184 | if (onleft_ori != onleft || onright_ori != onright) {//大大减少了repaint()的调用次数 185 | setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); 186 | repaint(); 187 | } 188 | } 189 | } 190 | } 191 | 192 | @Override 193 | public void mouseDragged(MouseEvent e) { 194 | if (editing) { 195 | return; 196 | } 197 | draging = true; 198 | if (onright) {//----------------------------RIGHT RESIZE----------------------------- 199 | if (temp_width+(e.getX()-sx) < 2*resize_anchor+3) { 200 | return;//限定块最小宽度 201 | } 202 | boolean snap = false; 203 | if (Timeline.getTimeline().allow_snap) { 204 | HRPane oneblock = null; 205 | for (int i = 0; i < Timeline.getTimeline().getBlocks().size(); i++) { 206 | //要避免吸附自己 207 | oneblock = Timeline.getTimeline().getBlocks().get(i); 208 | if (oneblock.getName().equals(getName())) { 209 | continue; 210 | } 211 | int endx = oneblock.getX()+oneblock.getWidth(); 212 | if (Math.abs(getX()+temp_width+(e.getX()-sx)-oneblock.getX()) < Timeline.getTimeline().snap_factor) { 213 | if (oneblock.getX()-getX() < 2*resize_anchor+3) { 214 | break;//与最小宽度冲突则不吸附 215 | } 216 | setSize(oneblock.getX()-getX(), getHeight()); 217 | snap = true; 218 | usesnapvalue = true; 219 | snap_to_value = oneblock.time_start; 220 | break; 221 | } 222 | if (Math.abs(getX()+temp_width+(e.getX()-sx)-endx) < Timeline.getTimeline().snap_factor) { 223 | if (endx-getX() < 2*resize_anchor+3) { 224 | break;//与最小宽度冲突则不吸附 225 | } 226 | setSize(endx-getX(), getHeight()); 227 | snap = true; 228 | usesnapvalue = true; 229 | snap_to_value = oneblock.time_end; 230 | break;//--- 231 | } 232 | } 233 | } 234 | if (!snap) { 235 | setSize(temp_width+(e.getX()-sx), getHeight()); 236 | usesnapvalue = false; 237 | } 238 | drag_type = 2; 239 | }else if (onleft) {//----------------------------LEFT RESIZE----------------------------- 240 | if (getWidth()-(e.getX()-sx) < 2*resize_anchor+3) { 241 | return;//限定块最小宽度 242 | } 243 | boolean snap = false; 244 | if (Timeline.getTimeline().allow_snap) { 245 | HRPane oneblock = null; 246 | for (int i = 0; i < Timeline.getTimeline().getBlocks().size(); i++) { 247 | //要避免吸附自己 248 | oneblock = Timeline.getTimeline().getBlocks().get(i); 249 | if (oneblock.getName().equals(getName())) { 250 | continue; 251 | } 252 | int endx = oneblock.getX()+oneblock.getWidth(); 253 | if (Math.abs(getX()+(e.getX()-sx)-endx) < Timeline.getTimeline().snap_factor) { 254 | if (temp_blockend-(oneblock.getX()+oneblock.getWidth()) < 2*resize_anchor+3) { 255 | break;//与最小宽度冲突则不吸附 256 | } 257 | setSize(temp_blockend-(oneblock.getX()+oneblock.getWidth()), getHeight()); 258 | setLocation(oneblock.getX()+oneblock.getWidth(), getY()); 259 | snap = true; 260 | usesnapvalue = true; 261 | snap_to_value = oneblock.time_end; 262 | break; 263 | } 264 | if (Math.abs(getX()+(e.getX()-sx)-oneblock.getX()) < Timeline.getTimeline().snap_factor) { 265 | if (temp_blockend-oneblock.getX() < 2*resize_anchor+3) { 266 | break;//与最小宽度冲突则不吸附 267 | } 268 | setSize(temp_blockend-oneblock.getX(), getHeight()); 269 | setLocation(oneblock.getX(), getY()); 270 | snap = true; 271 | usesnapvalue = true; 272 | snap_to_value = oneblock.time_start; 273 | break;//--- 274 | } 275 | } 276 | } 277 | if (!snap) { 278 | setSize(getWidth()-(e.getX()-sx), getHeight()); 279 | setLocation(getX()+(e.getX()-sx), getY()); 280 | usesnapvalue = false; 281 | } 282 | drag_type = 1; 283 | }else {//----------------------------MOVE----------------------------- 284 | //-------------------换层------------------ 285 | if (Math.abs(e.getY()-sy) > getHeight()) { 286 | if (e.getY()-sy > 0) { 287 | if (layer < Timeline.getTimeline().track_max) { 288 | //确保不超出设定的最大轨道数 289 | setLocation(getX(), temp_y + Timeline.getTimeline().track_hight); 290 | temp_y += Timeline.getTimeline().track_hight; 291 | layer ++; 292 | } 293 | }else { 294 | if (getY()-1 != Timeline.getTimeline().ruler_hight) { 295 | setLocation(getX(), temp_y - Timeline.getTimeline().track_hight); 296 | temp_y -= Timeline.getTimeline().track_hight; 297 | layer --; 298 | } 299 | } 300 | } 301 | if (TimelinePane.getTLPane().shiftdrag) { 302 | return; 303 | } 304 | //-------------------移动------------------------ 305 | if (getX()+(e.getX()-sx) < 1) {//不超出左侧边界 306 | return; 307 | } 308 | if (Math.abs(getX()+(e.getX()-sx)) < Timeline.getTimeline().snap_factor) {//吸附左侧边界 309 | setLocation(1, getY()); 310 | return; 311 | } 312 | //-----------------吸附------------------ 313 | boolean snap = false; 314 | if (Timeline.getTimeline().allow_snap) { 315 | HRPane oneblock = null; 316 | for (int i = 0; i < Timeline.getTimeline().getBlocks().size(); i++) { 317 | //要避免吸附自己 318 | oneblock = Timeline.getTimeline().getBlocks().get(i); 319 | if (oneblock.getName().equals(getName())) { 320 | continue; 321 | } 322 | int endx = oneblock.getX()+oneblock.getWidth(); 323 | if (Math.abs(getX()+(e.getX()-sx)-endx) < Timeline.getTimeline().snap_factor) { 324 | setLocation(oneblock.getX()+oneblock.getWidth(), getY()); 325 | snap = true; 326 | usesnapvalue = true; 327 | snap_to_value = oneblock.time_end; 328 | break; 329 | } 330 | if (Math.abs(getX()+(e.getX()-sx)-oneblock.getX()) < Timeline.getTimeline().snap_factor) { 331 | setLocation(oneblock.getX(), getY()); 332 | snap = true; 333 | usesnapvalue = true; 334 | snap_to_value = oneblock.time_start; 335 | break;//--- 336 | } 337 | } 338 | } 339 | if (!snap) { 340 | setLocation(getX()+(e.getX()-sx), getY()); 341 | usesnapvalue = false; 342 | } 343 | drag_type = 3; 344 | 345 | } 346 | 347 | } 348 | }); 349 | 350 | this.addMouseListener(new MouseListener() { 351 | @Override 352 | public void mouseEntered(MouseEvent e) { 353 | on = true; 354 | repaint(); 355 | } 356 | @Override 357 | public void mouseExited(MouseEvent e) { 358 | if (pressed) { 359 | return; 360 | } 361 | on = false; 362 | onleft = false; 363 | onright = false; 364 | setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); 365 | repaint(); 366 | } 367 | @Override 368 | public void mousePressed(MouseEvent e){ 369 | if (editing) { 370 | return; 371 | } 372 | pressed = true; 373 | sx = e.getX();temp_x = getX();temp_width = getWidth(); 374 | sy = e.getY();temp_y = getY(); 375 | temp_blockend = getX() + getWidth(); 376 | repaint(); 377 | } 378 | @Override 379 | public void mouseReleased(MouseEvent e){ 380 | if (editing) { 381 | return; 382 | } 383 | //更新边界时间信息 384 | switch (drag_type) {//1-左侧缩放 2-右侧缩放 3-移动 385 | case 1:// 386 | if (usesnapvalue) { 387 | time_start = snap_to_value; 388 | }else { 389 | time_start = TimelinePane.getTLPane().x_to_time(getX()); 390 | } 391 | break; 392 | case 2: 393 | if (usesnapvalue) { 394 | time_end = snap_to_value; 395 | }else { 396 | time_end = TimelinePane.getTLPane().x_to_time(getX()+getWidth()); 397 | } 398 | break; 399 | case 3: 400 | long len = time_end-time_start; 401 | if (usesnapvalue) { 402 | time_start = snap_to_value; 403 | }else { 404 | time_start = TimelinePane.getTLPane().x_to_time(getX()); 405 | } 406 | time_end = time_start+len; 407 | break; 408 | default:break; 409 | } 410 | //如果选中的话,调整完长度,还要更新重复播放的区间 411 | if (chosen) { 412 | Timeline.getTimeline().repeat_start = time_start; 413 | Timeline.getTimeline().repeat_end = time_end; 414 | } 415 | //退出拖拽状态 416 | pressed = false; 417 | draging = false; 418 | ex = e.getX(); 419 | ey = e.getY(); 420 | onleft = false; 421 | onright = false; 422 | if (!(e.getX() >= 0 && e.getX()<= getWidth() && e.getY() >= 0 && e.getY() <= getHeight())) { 423 | on = false; 424 | } 425 | setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); 426 | repaint(); 427 | if (Timeline.getTimeline().getBlocks().size() != 0) {//如果界面上没有东西,则不生成文件 428 | Timeline.getTimeline().EncodeSrt(); 429 | TimelineX.getTimelineX().saveSrtFile(); 430 | TimelineX.tlx.getPlayPane().getMediaPlayer().setSubTitleFile( 431 | TimelineX.getTimelineX().videofile.substring(0,TimelineX.getTimelineX().videofile.lastIndexOf("."))+".srt"); 432 | } 433 | } 434 | @Override 435 | public void mouseClicked(MouseEvent e) { 436 | requestFocus(); 437 | TimelinePane.getTLPane().selected_layer = layer; 438 | TimelinePane.getTLPane().repaint(); 439 | if (e.getClickCount() == 2) { 440 | edittext.setVisible(true); 441 | text.setVisible(false); 442 | edittext.requestFocusInWindow(); 443 | temp_width = getWidth(); 444 | setSize(600, getHeight()); 445 | editing = true; 446 | repaint(); 447 | } 448 | } 449 | }); 450 | 451 | this.addFocusListener(new FocusListener() { 452 | @Override 453 | public void focusLost(FocusEvent e) { 454 | chosen = false; 455 | Timeline.getTimeline().repeat_start = -1; 456 | Timeline.getTimeline().repeat_end = -1; 457 | repaint(); 458 | } 459 | @Override 460 | public void focusGained(FocusEvent e) { 461 | chosen = true; 462 | Timeline.getTimeline().repeat_start = time_start; 463 | Timeline.getTimeline().repeat_end = time_end; 464 | repaint(); 465 | } 466 | }); 467 | this.addKeyListener(new KeyListener() { 468 | @Override 469 | public void keyTyped(KeyEvent e) { 470 | // TODO Auto-generated method stub 471 | 472 | } 473 | @Override 474 | public void keyReleased(KeyEvent e) { 475 | TimelinePane.getTLPane().shiftdrag = false; 476 | 477 | } 478 | @Override 479 | public void keyPressed(KeyEvent e) { 480 | int k = e.getKeyCode(); 481 | //System.out.println(k); 482 | if (e.isShiftDown()) {//垂直拖放 483 | TimelinePane.getTLPane().shiftdrag = true; 484 | } 485 | if (k == 8 || k == 127) {//删除键 486 | Timeline.getTimeline().remove_block(getName()); 487 | }else if (k == 10) {//回车键,进行文字编辑 488 | edittext.setVisible(true); 489 | text.setVisible(false); 490 | edittext.requestFocusInWindow(); 491 | temp_width = getWidth(); 492 | setSize(600, getHeight()); 493 | editing = true; 494 | repaint(); 495 | }else if (k == 27) {//ESC键,丢弃焦点,将焦点转移到时间轴 496 | TimelinePane.getTLPane().requestFocusInWindow(); 497 | }else if (k == 32) {//SPACE 498 | TimelineX.getTimelineX().play(); 499 | }else if (k == 49 && e.isAltDown()) {//分配到第1组(数字1键) 500 | group = 1;repaint(); 501 | }else if (k == 50 && e.isAltDown()) {//分配到第2组(数字2键) 502 | group = 2;repaint(); 503 | }else if (k == 51 && e.isAltDown()) {//分配到第3组(数字3键) 504 | group = 3;repaint(); 505 | }else if (k == 52 && e.isAltDown()) {//分配到第4组(数字4键) 506 | group = 4;repaint(); 507 | }else if (k == 53 && e.isAltDown()) {//分配到第5组(数字5键) 508 | group = 5;repaint(); 509 | } 510 | } 511 | }); 512 | edittext.addKeyListener(new KeyListener() { 513 | @Override 514 | public void keyTyped(KeyEvent e) { 515 | 516 | } 517 | @Override 518 | public void keyReleased(KeyEvent e) { 519 | // TODO Auto-generated method stub 520 | 521 | } 522 | @Override 523 | public void keyPressed(KeyEvent e) { 524 | int k = e.getKeyCode(); 525 | //System.out.println(k); 526 | if (k == 10) {//按下回车退出块文字编辑状态 527 | text.setText(edittext.getText()); 528 | setToolTipText(edittext.getText()); 529 | edittext.setVisible(false); 530 | text.setVisible(true); 531 | setSize(temp_width, getHeight()); 532 | editing = false; 533 | if (e.isControlDown()) {//按下Ctl的话按回车在下面产生新的块 534 | System.out.println("duplicate:"+getName()); 535 | Timeline.getTimeline().add_block_below(getName()); 536 | }else { 537 | requestFocusInWindow(); 538 | } 539 | repaint(); 540 | if (Timeline.getTimeline().getBlocks().size() != 0) {//如果界面上没有东西,则不生成文件 541 | Timeline.getTimeline().EncodeSrt(); 542 | TimelineX.getTimelineX().saveSrtFile(); 543 | TimelineX.tlx.getPlayPane().getMediaPlayer().setSubTitleFile( 544 | TimelineX.getTimelineX().videofile.substring(0,TimelineX.getTimelineX().videofile.lastIndexOf("."))+".srt"); 545 | } 546 | } 547 | } 548 | }); 549 | edittext.addFocusListener(new FocusListener() { 550 | @Override 551 | public void focusLost(FocusEvent arg0) { 552 | //文本框失去焦点时退出文字编辑状态,并且让块获取焦点 553 | text.setText(edittext.getText()); 554 | setToolTipText(edittext.getText()); 555 | edittext.setVisible(false); 556 | text.setVisible(true); 557 | setSize(temp_width, getHeight()); 558 | editing = false; 559 | repaint(); 560 | //requestFocusInWindow(); 561 | } 562 | @Override 563 | public void focusGained(FocusEvent arg0) { 564 | // TODO Auto-generated method stub 565 | 566 | } 567 | }); 568 | } 569 | } 570 | -------------------------------------------------------------------------------- /gpl-2.0.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | --------------------------------------------------------------------------------