1 packageorg.crazyit.editor;2
3 importjava.awt.BorderLayout;4 importjava.awt.Color;5 importjava.awt.Insets;6 importjava.awt.event.ActionEvent;7 importjava.awt.event.InputEvent;8 importjava.io.File;9 importjava.util.ArrayList;10 importjava.util.List;11
12 importjavax.swing.AbstractAction;13 importjavax.swing.Action;14 importjavax.swing.Box;15 importjavax.swing.BoxLayout;16 importjavax.swing.ImageIcon;17 importjavax.swing.JDesktopPane;18 importjavax.swing.JFileChooser;19 importjavax.swing.JFrame;20 importjavax.swing.JInternalFrame;21 importjavax.swing.JMenu;22 importjavax.swing.JMenuBar;23 importjavax.swing.JOptionPane;24 importjavax.swing.JScrollPane;25 importjavax.swing.JSplitPane;26 importjavax.swing.JTabbedPane;27 importjavax.swing.JTextArea;28 importjavax.swing.JToolBar;29 importjavax.swing.JTree;30 importjavax.swing.KeyStroke;31 importjavax.swing.tree.TreePath;32
33 importorg.crazyit.editor.commons.AddInfo;34 importorg.crazyit.editor.commons.EditFile;35 importorg.crazyit.editor.commons.WorkSpace;36 importorg.crazyit.editor.handler.add.AddFileHandler;37 importorg.crazyit.editor.handler.add.AddFolderHandler;38 importorg.crazyit.editor.handler.add.AddProjectHandler;39 importorg.crazyit.editor.handler.run.JavaRunHandler;40 importorg.crazyit.editor.handler.save.SaveMediator;41 importorg.crazyit.editor.handler.save.SaveMediatorConcrete;42 importorg.crazyit.editor.tree.ProjectTreeModel;43 importorg.crazyit.editor.tree.ProjectTreeNode;44 importorg.crazyit.editor.tree.TreeCreator;45
46 /**
47 * 编辑界面48 *49 *@authoryangenxiong yangenxiong2009@gmail.com50 *@version1.051 *
网站: 疯狂Java联盟52 *
Copyright (C), 2009-2010, yangenxiong53 *
This program is protected by copyright laws.54 */
55 public class EditorFrame extendsJFrame {56
57 //多文件的tab标题
58 privateJTabbedPane tabPane;59
60 //存放tabPane与desk
61 privateBox box;62
63 //创建一个多文档的桌面容器
64 privateJDesktopPane desk;65
66 //用于分隔主编辑区和信息显示区的容器
67 privateJSplitPane editorSplitPane;68
69 //可以滚动的JScrollPane对象,用于放infoArea
70 privateJScrollPane infoPane;71
72 //用于显示信息的文本域
73 privateJTextArea infoArea;74
75 //存放树的可滚动容器
76 privateJScrollPane treePane;77
78 //整个界面的分隔组件的容器
79 privateJSplitPane mainSplitPane;80
81 //项目树对象
82 privateJTree tree;83
84 //菜单栏对象
85 privateJMenuBar menuBar;86
87 //编辑菜单对象
88 privateJMenu editMenu;89
90 //文件菜单
91 privateJMenu fileMenu;92
93 //工具条
94 privateJToolBar toolBar;95
96 privateWorkSpace workSpace;97
98 privateTreeCreator treeCreator;99
100 //添加的界面
101 privateAddFrame addFrame;102
103 //文件选择器
104 privateFileChooser fileChooser;105
106 //当前正在编辑的文件对象
107 privateEditFile currentFile;108
109 //窗口监听器
110 privateIFrameListener iframeListener;111
112 //打开文件的集合
113 private List openFiles = new ArrayList();114
115 //中介者对象
116 privateSaveMediator saveMediator;117
118 //运行class文件的处理类
119 privateJavaRunHandler runHandler;120
121 //新建文件的Action对象
122 private Action fileNew = new AbstractAction("新建文件", new ImageIcon("images/newFile.gif")) {123 public voidactionPerformed(ActionEvent e) {124 newFile();125 }126 };127 //新建目录的Action对象
128 private Action folerNew = new AbstractAction("新建目录", new ImageIcon("images/newFile.gif")) {129 public voidactionPerformed(ActionEvent e) {130 newFolder();131 }132 };133 //新建项目的Action对象
134 private Action projectNew = new AbstractAction("新建项目", new ImageIcon("images/newFile.gif")) {135 public voidactionPerformed(ActionEvent e) {136 newProject();137 }138 };139 //打开文件的Action对象
140 private Action open = new AbstractAction("打 开", new ImageIcon("images/open.gif")) {141 public voidactionPerformed(ActionEvent e) {142 selectFile();143 }144 };145 //保存文件的Action对象
146 private Action save = new AbstractAction("保 存", new ImageIcon("images/save.gif")) {147 public voidactionPerformed(ActionEvent e) {148 saveFile(getCurrentFile());149 }150 };151 //刷新树的Action对象
152 private Action refresh = new AbstractAction("刷 新", new ImageIcon("images/refresh.gif")) {153 public voidactionPerformed(ActionEvent e) {154 reloadNode(getSelectNode());155 }156 };157 //运行文件的Action对象
158 private Action run = new AbstractAction("运 行", new ImageIcon("images/run.gif")) {159 public voidactionPerformed(ActionEvent e) {160 run();161 }162 };163 //退出的Action对象
164 private Action exit = new AbstractAction("退 出") {165 public voidactionPerformed(ActionEvent e) {166 System.exit(0);//直接退出
167 }168 };169 //复制文本的Action对象
170 private Action copy = new AbstractAction("复 制", new ImageIcon("images/copy.gif")) {171 public voidactionPerformed(ActionEvent e) {172 if (getCurrentFile() != null) {173 getCurrentFile().getEditPane().copy();174 }175 }176 };177 //剪切文本的Action对象
178 private Action cut = new AbstractAction("剪 切", new ImageIcon("images/cut.gif")) {179 public voidactionPerformed(ActionEvent e) {180 if (getCurrentFile() != null) {181 getCurrentFile().getEditPane().cut();182 }183 }184 };185 //粘贴文本的Action对象
186 private Action paste = new AbstractAction("粘 贴", new ImageIcon("images/paste.gif")) {187 public voidactionPerformed(ActionEvent e) {188 if (getCurrentFile() != null) {189 getCurrentFile().getEditPane().paste();190 }191 }192 };193
194 publicEditorFrame(String title, TreeCreator treeCreator) {195 super(title); //设置标题
196 this.treeCreator =treeCreator;197 this.iframeListener = new IFrameListener(this);198 this.saveMediator = newSaveMediatorConcrete();199 this.runHandler = newJavaRunHandler();200 }201
202 public voidinitFrame(WorkSpace space) {203 this.workSpace =space;204 //设置窗口关闭,退出程序
205 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);206 //创建主编辑区的tabPane
207 tabPane = newJTabbedPane(JTabbedPane.TOP, JTabbedPane.SCROLL_TAB_LAYOUT );208 desk = new JDesktopPane();//创建JDesktopPane对象
209 desk.setBackground(Color.GRAY);//设置desk的背景颜色为灰色
210 box = new Box(BoxLayout.Y_AXIS);//设置box的布局
211 box.add(tabPane);212 box.add(desk);213 //创建信息显示区的文本域
214 infoArea = new JTextArea("", 5, 50);215 //将infoArea文本域作为组件放到infoPane中
216 infoPane = newJScrollPane(infoArea);217 //设置信息区不可编辑
218 infoArea.setEditable(false);219 //创建这个分隔组件的容器,并将box对象和infoPane放置其中
220 editorSplitPane = newJSplitPane(JSplitPane.VERTICAL_SPLIT, box, infoPane);221 editorSplitPane.setDividerSize(3);222 editorSplitPane.setDividerLocation(500);223 //创建树
224 tree = treeCreator.createTree(this);225 //创建可滚动的容器对象
226 treePane = newJScrollPane(tree);227 //创建主界面的JSplitPane,横向,左边为treePane,右边为editorSplitPane
228 mainSplitPane = newJSplitPane(JSplitPane.HORIZONTAL_SPLIT, treePane,229 editorSplitPane);230 //设置分隔条的位置
231 mainSplitPane.setDividerLocation(200);232 //设置分隔条的粗细
233 mainSplitPane.setDividerSize(3);234 add(mainSplitPane);235
236 //创建菜单栏对象
237 menuBar = newJMenuBar();238 //创建编辑菜单对象
239 editMenu = new JMenu("编辑");240 //创建文件菜单
241 fileMenu = new JMenu("文件");242 //将文件菜单添加到菜单栏中
243 menuBar.add(fileMenu);244 //将编辑菜单添加到菜单栏中
245 menuBar.add(editMenu);246 //设置JFrame的菜单栏
247 setJMenuBar(menuBar);248
249 toolBar = newJToolBar();250 toolBar.setFloatable(false);//设置工具栏不可移动
251 toolBar.setMargin(new Insets(0, 10, 5, 5));//设置工具栏的边距
252 add(toolBar, BorderLayout.NORTH);//将工具栏添加到EditorFrame中
253
254 pack();//使JFrame调整最佳大小
255 addListeners();256 }257
258 publicTreeCreator getTreeCreator() {259 returntreeCreator;260 }261
262 //为EditorFrame中的组件添加监听器
263 public voidaddListeners() {264 //新建文件的监听器
265 fileMenu.add(fileNew).setAccelerator(KeyStroke.getKeyStroke('N', InputEvent.CTRL_MASK));266 //新建目录的监听器
267 fileMenu.add(folerNew).setAccelerator(KeyStroke.getKeyStroke('F', InputEvent.CTRL_MASK));268 //新建项目的监听器
269 fileMenu.add(projectNew).setAccelerator(KeyStroke.getKeyStroke('P', InputEvent.CTRL_MASK));270 //打开菜单添加监听器
271 fileMenu.add(open).setAccelerator(KeyStroke.getKeyStroke('O', InputEvent.CTRL_MASK));272 //为保存菜单添加监听器
273 fileMenu.add(save).setAccelerator(KeyStroke.getKeyStroke('S', InputEvent.CTRL_MASK));274 //为刷新菜单添加监听器
275 fileMenu.add(refresh).setAccelerator(KeyStroke.getKeyStroke("F5"));276 //为运行菜单添加监听器
277 fileMenu.add(run).setAccelerator(KeyStroke.getKeyStroke('R', InputEvent.CTRL_MASK));278 fileMenu.add(exit);279 //添加复制监听器
280 editMenu.add(copy).setAccelerator(KeyStroke.getKeyStroke('C', InputEvent.CTRL_MASK));281 //添加剪切监听器
282 editMenu.add(cut).setAccelerator(KeyStroke.getKeyStroke('X', InputEvent.CTRL_MASK));283 //添加粘贴监听器
284 editMenu.add(paste).setAccelerator(KeyStroke.getKeyStroke('V', InputEvent.CTRL_MASK));285
286 //为工具条添加各个操作
287 toolBar.add(fileNew).setToolTipText("新建文件");288 toolBar.add(open).setToolTipText("打开");289 toolBar.add(save).setToolTipText("保存");290 toolBar.add(refresh).setToolTipText("刷新");291 toolBar.add(run).setToolTipText("运行");292 toolBar.add(copy).setToolTipText("复制");293 toolBar.add(cut).setToolTipText("剪切");294 toolBar.add(paste).setToolTipText("粘贴");295
296 //为tabPane添加监听器
297 tabPane.addChangeListener(new TabListener(this));298 }299
300 //获取编辑器主界面项目树中所选中的节点
301 publicProjectTreeNode getSelectNode() {302 //获得当前树选择的节点在树中的路径
303 TreePath path =tree.getSelectionPath();304 //如果当前选择了节点
305 if (path != null) {306 //创建一个ProjectTreeNode对象并用于返回
307 ProjectTreeNode selectNode =(ProjectTreeNode)path.getLastPathComponent();308 returnselectNode;309 }310 //当前没有选择节就返回null
311 return null;312 }313
314 //显示iframe对象
315 public voidshowIFrame(JInternalFrame iframe) {316 try{317 iframe.setSelected(true);318 iframe.toFront();319 } catch(Exception ex) {320 }321 }322
323 //打开文件的方法
324 public voidopenFile(File file) {325 if (currentFile != null) {326 //如果参数file是当前正在编辑的文件
327 if (file.equals(currentFile.getFile())) return;328 }329 //在打开文件的集合中查找该文件, 再判断该文件是否已经打开
330 EditFile openedFile =getOpenFile(file);331 //如果文件已经打开了,调用打开方法(打开已经在编辑tab页面中显示的文件)
332 if (openedFile != null) {333 openExistFile(openedFile, file);334 return;335 }336 //打开新的文件
337 openNewFile(file);338 }339
340 //从本类中记录已经打开的文件集合中得到与参数file一样的EditFile对象
341 privateEditFile getOpenFile(File file) {342 for(EditFile openFile : openFiles) {343 if (openFile.getFile().equals(file)) returnopenFile;344 }345 return null;346 }347
348 //根据参数file获取该file对应的tab页中的索引
349 private intgetFileIndex(File file) {350 //如果从打开文件的集合中找不到与参数file对应的EditFile对象,返回-1
351 EditFile openFile =getEditFile(file);352 if (openFile == null) return -1;353 returngetTabIndex(openFile.getIframe().getToolTipText());354 }355
356 //在打开的文件中获得文件是file的EditFile对象
357 privateEditFile getEditFile(File file) {358 for(EditFile openFile : openFiles) {359 if (openFile.getFile().equals(file)) returnopenFile;360 }361 return null;362 }363
364 //根据tab页中的tips找到所对应的在tabPane的索引
365 public intgetTabIndex(String tips) {366 for (int i = 0; i < this.tabPane.getTabCount(); i++) {367 if (this.tabPane.getToolTipTextAt(i).equals(tips)) returni;368 }369 return -1;370 }371
372 //打开已经存在的文件(已经在编辑文件集合中的文件),openFiles集合中的文件
373 public voidopenExistFile(EditFile openedFile, File willOpenFile) {374 //将tab页变成当前所选择文件的索引
375 tabPane.setSelectedIndex(getFileIndex(willOpenFile));376 //显示iframe
377 showIFrame(openedFile.getIframe());378 //设置当前打开文件
379 this.currentFile =openedFile;380 //添加到当前打开的文件集合中
381 this.openFiles.add(openedFile);382 }383
384 //打开一个不在编辑集合中的文件
385 public voidopenNewFile(File file) {386 //设置EditorFrame的标题为该文件的全路径
387 setTitle(file.getAbsolutePath());388 //创建一个JInternalFrame对象,title为文件的绝对路径
389 JInternalFrame iframe = new JInternalFrame(file.getAbsolutePath(), true, true, true, true);390
391 //新建一个EditPane对象
392 EditPane editPane = newEditPane(file);393
394 //为EditPane添加键盘监听器
395 editPane.getDocument().addDocumentListener(new EditDocumentListener(this));396 iframe.add(newJScrollPane(editPane));397 //为JInternalFrame添加窗口监听器
398 iframe.addInternalFrameListener(this.iframeListener);399 desk.add(iframe);400 iframe.show();401 iframe.reshape(0, 0, 400, 300);402 tabPane.addTab(file.getName(), null, null, file.getAbsolutePath());403 tabPane.setSelectedIndex(tabPane.getTabCount() - 1);404 //设置当前的文件对象
405 this.currentFile = new EditFile(file, true, iframe, editPane);406 //将当前的文件加到打开的文件集合中
407 this.openFiles.add(this.currentFile);408 }409
410 public voidselectFile() {411 fileChooser = new FileChooser(this);412 }413
414 //新建文件的方法
415 public voidnewFile() {416 //当没有选择一个节点而新建目录的时候,需要提醒
417 if (getSelectNode() == null) {418 JOptionPane.showMessageDialog(this, "请选择目录");419 return;420 }421 AddInfo info = new AddInfo("文件名称:", this, newAddFileHandler());422 showAddFrame(info);423 }424 //显示新增的界面
425 private voidshowAddFrame(AddInfo info) {426 //使EditorFrame变为不可用
427 setEnabled(false);428 addFrame = newAddFrame(info);429 addFrame.pack();430 addFrame.setVisible(true);431 }432
433 //刷新树节点
434 public voidreloadNode(ProjectTreeNode selectNode) {435 if (selectNode == null) return;436 //刷新树的节点
437 ProjectTreeModel model =(ProjectTreeModel)getTree().getModel();438 //重新加载所选择的节点
439 model.reload(selectNode, treeCreator);440 }441
442 publicWorkSpace getWorkSpace() {443 returnworkSpace;444 }445
446 publicJTree getTree() {447 return this.tree;448 }449
450 //新建目录的方法
451 public voidnewFolder() {452 //当没有选择一个节点而新建目录的时候,需要提醒
453 if (getSelectNode() == null) {454 JOptionPane.showMessageDialog(this, "请选择目录");455 return;456 }457 AddInfo info = new AddInfo("目录名称:", this, newAddFolderHandler());458 showAddFrame(info);459 }460
461 //新建项目的方法
462 public voidnewProject() {463 AddInfo info = new AddInfo("项目名称:", this, newAddProjectHandler());464 showAddFrame(info);465 }466
467 //重新在treePane中构造一次树
468 public voidrefreshTree(JTree newTree) {469 //将tree对象变为参数中的newTree
470 this.tree =newTree;471 //让treePane(放树的容器)设置newTree为新的视图
472 treePane.setViewportView(newTree);473 //更新界面
474 treePane.updateUI();475 }476
477 publicEditFile getCurrentFile() {478 returncurrentFile;479 }480
481 public voidsetCurrentFile(EditFile currentFile) {482 this.currentFile =currentFile;483 }484
485 public ListgetOpenFiles() {486 returnopenFiles;487 }488
489 publicJDesktopPane getDesk() {490 returndesk;491 }492
493 publicJTabbedPane getTabPane() {494 returntabPane;495 }496
497 //根据JInternalFrame标题找到JInternalFrame对象
498 publicJInternalFrame getIFrame(String title) {499 JInternalFrame[] iframes =desk.getAllFrames();500 for(JInternalFrame iframe : iframes) {501 if (iframe.getTitle().equals(title)) returniframe;502 }503 return null;504 }505
506 //根据JInternalFrame在打开的文件集合中获取相应的文件对象
507 publicEditFile getEditFile(JInternalFrame iframe) {508 for(EditFile openFile : openFiles) {509 if (openFile.getIframe().equals(iframe)) returnopenFile;510 }511 return null;512 }513
514 //询问是否要保存, 参数为将被打开的文件
515 public voidaskSave(EditFile file) {516 //该份文件修改过没有保存
517 if (!file.isSaved()) {518 //弹出询问
519 int val = JOptionPane.showConfirmDialog(this, "是否要保存?", "询问",520 JOptionPane.YES_NO_OPTION);521 //点击了需要保存
522 if (JOptionPane.YES_OPTION ==val) {523 //调用EditorFrame的保存方法对文件进行保存
524 saveFile(file);525 }526 }527 }528
529 //用于保存当前所打开的文件
530 public voidsaveFile(EditFile file) {531 if (file == null) return;532 //调用中介者对象的方法去保存文件
533 String result = saveMediator.doSave(this);534 //将结果放到信息显示区的文本域中
535 infoArea.setText(result);536 //写完文件后,设置当前文件的保存状态为true,表示已经保存
537 file.setSaved(true);538 }539
540 //关闭一个窗口
541 public voidcloseIFrame(JInternalFrame iframe) {542 //获得当前的文件,即要关闭的文件对象
543 EditFile closeFile =getEditFile(iframe);544 //设置本类中的currentFile属性
545 afterClose(closeFile);546 //获得该iframe在tab页中对应的索引
547 int index =getTabIndex(iframe.getTitle());548 //从tab页中删除
549 getTabPane().remove(index);550 //从打开的文件集合中删除这个关闭的文件
551 openFiles.remove(closeFile);552 }553
554 //当关闭一份文件后,设置本对象的currentFile属性
555 private voidafterClose(EditFile closeFile) {556 //获取关闭文件在打开文件集合中的索引
557 int openFilesIndex =getEditFileIndex(closeFile);558 //如果该文件已经是所有打开的文件的最后一份
559 if (this.openFiles.size() == 1) {560 this.currentFile = null;561 } else {//如果还有其他文件,判断关闭的文件位置
562 if (openFilesIndex == 0) {563 //如果关闭的文件是第一份,拿集合中的第二份
564 this.currentFile = openFiles.get(openFilesIndex + 1);565 } else if (openFilesIndex == (openFiles.size() - 1)) {566 //如果关闭的是最后一份,取倒数第二份
567 this.currentFile = openFiles.get(openFiles.size() - 2);568 } else{569 //不是第一份,也不是最后一份
570 this.currentFile = openFiles.get(openFilesIndex - 1);571 }572 }573 }574
575 //获取editFile在打开的文件集合中的索引
576 private intgetEditFileIndex(EditFile editFile) {577 for (int i = 0; i < this.openFiles.size(); i++) {578 if (openFiles.get(i).equals(editFile)) returni;579 }580 return -1;581 }582
583 //返回项目树当前所选中的节点所属的项目节点对应的目录
584 publicFile getCurrentProject() {585 //获取根节点(工作空间)
586 ProjectTreeNode root =(ProjectTreeNode)getSelectNode().getRoot();587 //获取根节点下的所有子节点(即项目节点集合)
588 List projects =root.getChildren();589 ProjectTreeNode selectNode =getSelectNode();590 if (selectNode != null) {591 for(ProjectTreeNode project : projects) {592 //当前先中节点是该project下的子节点
593 if(selectNode.isNodeAncestor(project)) {594 returnproject.getFile();595 }596 }597 }598 return null;599 }600
601 //运行文件的方法
602 public voidrun() {603 //运行前先保存
604 saveFile(getCurrentFile());605 //将结果显示
606 String result = runHandler.run(this);607 infoArea.setText(result);608 }609
610 }611 class FileChooser extendsJFileChooser {612
613 privateEditorFrame editorFrame;614
615
616 publicFileChooser(EditorFrame editorFrame){617 //调用父类的构造器618 //利用editorFrame的工作空间作为文件选择器打开时的默认目录
619 super(editorFrame.getWorkSpace().getFolder());620 this.editorFrame =editorFrame;621 showOpenDialog(editorFrame);622 }623
624 public voidapproveSelection() {625 File file =getSelectedFile();626 //设置树当前选择的节点为null, 即树没有被选中
627 this.editorFrame.getTree().setSelectionPath(null);628 this.editorFrame.openFile(file);629 super.approveSelection();630 }631 }