PageRenderTime 77ms CodeModel.GetById 49ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 1ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/textarea/Selection.java

#
Java | 715 lines | 494 code | 89 blank | 132 comment | 108 complexity | 6068652470c77bff00750530476a50fa MD5 | raw file
  1/*
  2 * Selection.java - Selected text
  3 * :tabSize=8:indentSize=8:noTabs=false:
  4 * :folding=explicit:collapseFolds=1:
  5 *
  6 * Copyright (C) 2001, 2002 Slava Pestov
  7 *
  8 * This program is free software; you can redistribute it and/or
  9 * modify it under the terms of the GNU General Public License
 10 * as published by the Free Software Foundation; either version 2
 11 * of the License, or any later version.
 12 *
 13 * This program is distributed in the hope that it will be useful,
 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16 * GNU General Public License for more details.
 17 *
 18 * You should have received a copy of the GNU General Public License
 19 * along with this program; if not, write to the Free Software
 20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 21 */
 22
 23package org.gjt.sp.jedit.textarea;
 24
 25//{{{ Imports
 26import java.util.ArrayList;
 27import org.gjt.sp.jedit.Buffer;
 28import org.gjt.sp.jedit.MiscUtilities;
 29//}}}
 30
 31/**
 32 * An abstract class that holds data on a region of selected text.
 33 * As an abstract class, it cannot be used
 34 * directly, but instead serves as a parent class for two specific types
 35 * of selection structures:
 36 * <ul>
 37 * <li>{@link Selection.Range} - represents an ordinary range of selected text.</li>
 38 * <li>{@link Selection.Rect} - represents a rectangular selection.</li>
 39 * </ul>
 40 *
 41 * @author Slava Pestov
 42 * @author John Gellene (API documentation)
 43 * @version $Id: Selection.java 5012 2004-04-06 19:05:31Z spestov $
 44 * @since jEdit 3.2pre1
 45 */
 46public abstract class Selection implements Cloneable
 47{
 48	//{{{ getStart() method
 49	/**
 50	 * Returns the start offset of this selection.
 51	 */
 52	public int getStart()
 53	{
 54		return start;
 55	} //}}}
 56
 57	//{{{ getEnd() method
 58	/**
 59	 * Returns the end offset of this selection.
 60	 */
 61	public int getEnd()
 62	{
 63		return end;
 64	} //}}}
 65
 66	//{{{ getStart() method
 67	/**
 68	 * Returns the beginning of the portion of the selection
 69	 * falling on the specified line. Used to manipulate
 70         * selection text on a line-by-line basis.
 71	 * @param buffer The buffer
 72	 * @param line The line number
 73	 * @since jEdit 4.1pre1
 74	 */
 75	public abstract int getStart(Buffer buffer, int line);
 76	//}}}
 77
 78	//{{{ getEnd() method
 79	/**
 80	 * Returns the end of the portion of the selection
 81	 * falling on the specified line. Used to manipulate
 82         * selection text on a line-by-line basis.
 83	 * @param buffer The buffer
 84	 * @param line The line number
 85	 * @since jEdit 4.1pre1
 86	 */
 87	public abstract int getEnd(Buffer buffer, int line);
 88	//}}}
 89
 90	//{{{ getStartLine() method
 91	/**
 92	 * Returns the starting line number of this selection.
 93	 */
 94	public int getStartLine()
 95	{
 96		return startLine;
 97	} //}}}
 98
 99	//{{{ getEndLine() method
100	/**
101	 * Returns the ending line number of this selection.
102	 */
103	public int getEndLine()
104	{
105		return endLine;
106	} //}}}
107
108	//{{{ overlaps() method
109	/**
110	 * Returns if this selection and the specified selection overlap.
111	 * @param s The other selection
112	 * @since jEdit 4.1pre1
113	 */
114	public boolean overlaps(Selection s)
115	{
116		if((start >= s.start && start <= s.end)
117			|| (end >= s.start && end <= s.end))
118			return true;
119		else
120			return false;
121	} //}}}
122
123	//{{{ toString() method
124	public String toString()
125	{
126		return getClass().getName() + "[start=" + start
127			+ ",end=" + end + ",startLine=" + startLine
128			+ ",endLine=" + endLine + "]";
129	} //}}}
130
131	//{{{ clone() method
132	public Object clone()
133	{
134		try
135		{
136			return super.clone();
137		}
138		catch(CloneNotSupportedException e)
139		{
140			throw new InternalError("I just drank a whole "
141				+ "bottle of cough syrup and I feel "
142				+ "funny!");
143		}
144	} //}}}
145
146	//{{{ Package-private members
147	int start, end;
148	int startLine, endLine;
149
150	//{{{ Selection constructor
151	Selection()
152	{
153	} //}}}
154
155	//{{{ Selection constructor
156	Selection(Selection sel)
157	{
158		this.start = sel.start;
159		this.end = sel.end;
160	} //}}}
161
162	//{{{ Selection constructor
163	Selection(int start, int end)
164	{
165		this.start = start;
166		this.end = end;
167	} //}}}
168
169	// should the next two be public, maybe?
170	abstract void getText(Buffer buffer, StringBuffer buf);
171	abstract int setText(Buffer buffer, String text);
172
173	abstract boolean contentInserted(Buffer buffer, int startLine, int start,
174		int numLines, int length);
175	abstract boolean contentRemoved(Buffer buffer, int startLine, int start,
176		int numLines, int length);
177	//}}}
178
179	//{{{ Range class
180	/**
181	 * An ordinary range selection.
182	 * @since jEdit 3.2pre1
183	 */
184	public static class Range extends Selection
185	{
186		//{{{ Range constructor
187		public Range()
188		{
189		} //}}}
190
191		//{{{ Range constructor
192		public Range(Selection sel)
193		{
194			super(sel);
195		} //}}}
196
197		//{{{ Range constructor
198		public Range(int start, int end)
199		{
200			super(start,end);
201		} //}}}
202
203		//{{{ getStart() method
204		public int getStart(Buffer buffer, int line)
205		{
206			if(line == startLine)
207				return start;
208			else
209				return buffer.getLineStartOffset(line);
210		} //}}}
211
212		//{{{ getEnd() method
213		public int getEnd(Buffer buffer, int line)
214		{
215			if(line == endLine)
216				return end;
217			else
218				return buffer.getLineEndOffset(line) - 1;
219		} //}}}
220
221		//{{{ Package-private members
222
223		//{{{ getText() method
224		void getText(Buffer buffer, StringBuffer buf)
225		{
226			buf.append(buffer.getText(start,end - start));
227		} //}}}
228
229		//{{{ setText() method
230		int setText(Buffer buffer, String text)
231		{
232			buffer.remove(start,end - start);
233			if(text != null && text.length() != 0)
234			{
235				buffer.insert(start,text);
236				return start + text.length();
237			}
238			else
239				return start;
240		} //}}}
241
242		//{{{ contentInserted() method
243		boolean contentInserted(Buffer buffer, int startLine, int start,
244			int numLines, int length)
245		{
246			boolean changed = false;
247
248			if(this.start >= start)
249			{
250				this.start += length;
251				if(numLines != 0)
252					this.startLine = buffer.getLineOfOffset(this.start);
253				changed = true;
254			}
255
256			if(this.end >= start)
257			{
258				this.end += length;
259				if(numLines != 0)
260					this.endLine = buffer.getLineOfOffset(this.end);
261				changed = true;
262			}
263
264			return changed;
265		} //}}}
266
267		//{{{ contentRemoved() method
268		boolean contentRemoved(Buffer buffer, int startLine, int start,
269			int numLines, int length)
270		{
271			int end = start + length;
272			boolean changed = false;
273
274			if(this.start > start && this.start <= end)
275			{
276				this.start = start;
277				changed = true;
278			}
279			else if(this.start > end)
280			{
281				this.start -= length;
282				changed = true;
283			}
284
285			if(this.end > start && this.end <= end)
286			{
287				this.end = start;
288				changed = true;
289			}
290			else if(this.end > end)
291			{
292				this.end -= length;
293				changed = true;
294			}
295
296			if(changed && numLines != 0)
297			{
298				this.startLine = buffer.getLineOfOffset(this.start);
299				this.endLine = buffer.getLineOfOffset(this.end);
300			}
301
302			return changed;
303		} //}}}
304
305		//}}}
306	} //}}}
307
308	//{{{ Rect class
309	/**
310	 * A rectangular selection.
311	 * @since jEdit 3.2pre1
312	 */
313	// this class is not very fast...
314	public static class Rect extends Selection
315	{
316		//{{{ Rect constructor
317		public Rect()
318		{
319			super();
320		} //}}}
321
322		//{{{ Rect constructor
323		public Rect(Selection sel)
324		{
325			super(sel);
326		} //}}}
327
328		//{{{ Rect constructor
329		public Rect(int start, int end)
330		{
331			super(start,end);
332		} //}}}
333
334		//{{{ Rect constructor
335		public Rect(int startLine, int start, int endLine, int end)
336		{
337			this.startLine = startLine;
338			this.start = start;
339			this.endLine = endLine;
340			this.end = end;
341		} //}}}
342
343		//{{{ Rect constructor
344		public Rect(Buffer buffer, int startLine, int startColumn,
345			int endLine, int endColumn)
346		{
347			this.startLine = startLine;
348			this.endLine = endLine;
349
350			int[] width = new int[1];
351			int startOffset = buffer.getOffsetOfVirtualColumn(startLine,
352				startColumn,width);
353			if(startOffset == -1)
354			{
355				extraStartVirt = startColumn - width[0];
356				startOffset = buffer.getLineEndOffset(startLine) - 1;
357			}
358			else
359				startOffset += buffer.getLineStartOffset(startLine);
360
361			int endOffset = buffer.getOffsetOfVirtualColumn(endLine,
362				endColumn,width);
363			if(endOffset == -1)
364			{
365				extraEndVirt = endColumn - width[0];
366				endOffset = buffer.getLineEndOffset(endLine) - 1;
367			}
368			else
369				endOffset += buffer.getLineStartOffset(endLine);
370		} //}}}
371
372		//{{{ getStartColumn() method
373		public int getStartColumn(Buffer buffer)
374		{
375			int virtColStart = buffer.getVirtualWidth(startLine,
376				start - buffer.getLineStartOffset(startLine)) + extraStartVirt;
377			int virtColEnd = buffer.getVirtualWidth(endLine,
378				end - buffer.getLineStartOffset(endLine)) + extraEndVirt;
379			return Math.min(virtColStart,virtColEnd);
380		} //}}}
381
382		//{{{ getEndColumn() method
383		public int getEndColumn(Buffer buffer)
384		{
385			int virtColStart = buffer.getVirtualWidth(startLine,
386				start - buffer.getLineStartOffset(startLine)) + extraStartVirt;
387			int virtColEnd = buffer.getVirtualWidth(endLine,
388				end - buffer.getLineStartOffset(endLine)) + extraEndVirt;
389			return Math.max(virtColStart,virtColEnd);
390		} //}}}
391
392		//{{{ getStart() method
393		public int getStart(Buffer buffer, int line)
394		{
395			return getColumnOnOtherLine(buffer,line,
396				getStartColumn(buffer));
397		} //}}}
398
399		//{{{ getEnd() method
400		public int getEnd(Buffer buffer, int line)
401		{
402			return getColumnOnOtherLine(buffer,line,
403				getEndColumn(buffer));
404		} //}}}
405
406		//{{{ Package-private members
407		int extraStartVirt;
408		int extraEndVirt;
409
410		//{{{ getText() method
411		void getText(Buffer buffer, StringBuffer buf)
412		{
413			int start = getStartColumn(buffer);
414			int end = getEndColumn(buffer);
415
416			for(int i = startLine; i <= endLine; i++)
417			{
418				int lineStart = buffer.getLineStartOffset(i);
419				int lineLen = buffer.getLineLength(i);
420
421				int rectStart = buffer.getOffsetOfVirtualColumn(
422					i,start,null);
423				if(rectStart == -1)
424					rectStart = lineLen;
425
426				int rectEnd = buffer.getOffsetOfVirtualColumn(
427					i,end,null);
428				if(rectEnd == -1)
429					rectEnd = lineLen;
430
431				if(rectEnd < rectStart)
432					System.err.println(i + ":::" + start + ":" + end
433						+ " ==> " + rectStart + ":" + rectEnd);
434				buf.append(buffer.getText(lineStart + rectStart,
435					rectEnd - rectStart));
436
437				if(i != endLine)
438					buf.append('\n');
439			}
440		} //}}}
441
442		//{{{ setText() method
443		int setText(Buffer buffer, String text)
444		{
445			int startColumn = getStartColumn(buffer);
446			int endColumn = getEndColumn(buffer);
447
448			int[] total = new int[1];
449
450			int tabSize = buffer.getTabSize();
451
452			int maxWidth = 0;
453			int totalLines = 0;
454			ArrayList lines = new ArrayList();
455
456			//{{{ Split the text into lines
457			if(text != null)
458			{
459				int lastNewline = 0;
460				int currentWidth = startColumn;
461				for(int i = 0; i < text.length(); i++)
462				{
463					char ch = text.charAt(i);
464					if(ch == '\n')
465					{
466						totalLines++;
467						lines.add(text.substring(
468							lastNewline,i));
469						lastNewline = i + 1;
470						maxWidth = Math.max(maxWidth,currentWidth);
471						lines.add(new Integer(currentWidth));
472						currentWidth = startColumn;
473					}
474					else if(ch == '\t')
475						currentWidth += tabSize - (currentWidth % tabSize);
476					else
477						currentWidth++;
478				}
479
480				if(lastNewline != text.length())
481				{
482					totalLines++;
483					lines.add(text.substring(lastNewline));
484					lines.add(new Integer(currentWidth));
485					maxWidth = Math.max(maxWidth,currentWidth);
486				}
487			} //}}}
488
489			//{{{ Insert the lines into the buffer
490			int endOffset = 0;
491			int lastLine = Math.max(startLine + totalLines - 1,endLine);
492			for(int i = startLine; i <= lastLine; i++)
493			{
494				if(i == buffer.getLineCount())
495					buffer.insert(buffer.getLength(),"\n");
496
497				int lineStart = buffer.getLineStartOffset(i);
498				int lineLen = buffer.getLineLength(i);
499
500				int rectStart = buffer.getOffsetOfVirtualColumn(
501					i,startColumn,total);
502				int startWhitespace;
503				if(rectStart == -1)
504				{
505					startWhitespace = (startColumn - total[0]);
506					rectStart = lineLen;
507				}
508				else
509					startWhitespace = 0;
510
511				int rectEnd = buffer.getOffsetOfVirtualColumn(
512					i,endColumn,null);
513				if(rectEnd == -1)
514					rectEnd = lineLen;
515
516				buffer.remove(rectStart + lineStart,rectEnd - rectStart);
517
518				if(startWhitespace != 0)
519				{
520					buffer.insert(rectStart + lineStart,
521						MiscUtilities.createWhiteSpace(startWhitespace,0));
522				}
523
524				int endWhitespace;
525				if(totalLines == 0)
526				{
527					if(rectEnd == lineLen)
528						endWhitespace = 0;
529					else
530						endWhitespace = maxWidth - startColumn;
531				}
532				else
533				{
534					int index = 2 * ((i - startLine) % totalLines);
535					String str = (String)lines.get(index);
536					buffer.insert(rectStart + lineStart + startWhitespace,str);
537					if(rectEnd == lineLen)
538						endWhitespace = 0;
539					else
540					{
541						endWhitespace = maxWidth
542							- ((Integer)lines.get(index+1))
543							.intValue();
544					}
545					startWhitespace += str.length();
546				}
547
548				if(endWhitespace != 0)
549				{
550					buffer.insert(rectStart + lineStart
551						+ startWhitespace,
552						MiscUtilities.createWhiteSpace(endWhitespace,0));
553				}
554
555				endOffset = rectStart + lineStart
556					+ startWhitespace
557					+ endWhitespace;
558			} //}}}
559
560			//{{{ Move the caret down a line
561			if(text == null || text.length() == 0)
562				return end;
563			else
564				return endOffset;
565			//}}}
566		} //}}}
567
568		//{{{ contentInserted() method
569		boolean contentInserted(Buffer buffer, int startLine, int start,
570			int numLines, int length)
571		{
572			if(this.end < start)
573				return false;
574
575			this.end += length;
576
577			if(this.startLine > startLine)
578			{
579				this.start += length;
580				if(numLines != 0)
581				{
582					this.startLine = buffer.getLineOfOffset(
583						this.start);
584					this.endLine = buffer.getLineOfOffset(
585						this.end);
586				}
587				return true;
588			}
589
590			int endVirtualColumn = buffer.getVirtualWidth(
591				this.endLine,end
592				- buffer.getLineStartOffset(this.endLine));
593
594			if(this.start == start)
595			{
596				int startVirtualColumn = buffer.getVirtualWidth(
597					this.startLine,start
598					- buffer.getLineStartOffset(
599					this.startLine));
600
601				this.start += length;
602
603				int newStartVirtualColumn
604					= buffer.getVirtualWidth(
605						startLine,start -
606						buffer.getLineStartOffset(
607						this.startLine));
608
609				int[] totalVirtualWidth = new int[1];
610				int newEnd = buffer.getOffsetOfVirtualColumn(
611					this.endLine,endVirtualColumn +
612					newStartVirtualColumn -
613					startVirtualColumn,
614					totalVirtualWidth);
615
616				if(newEnd != -1)
617				{
618					end = buffer.getLineStartOffset(
619						this.endLine) + newEnd;
620				}
621				else
622				{
623					end = buffer.getLineEndOffset(
624						this.endLine) - 1;
625					extraEndVirt = totalVirtualWidth[0]
626						- endVirtualColumn;
627				}
628			}
629			else if(this.start > start)
630			{
631				this.start += length;
632				if(numLines != 0)
633				{
634					this.startLine = buffer.getLineOfOffset(
635						this.start);
636				}
637			}
638
639			if(numLines != 0)
640				this.endLine = buffer.getLineOfOffset(this.end);
641			int newEndVirtualColumn = buffer.getVirtualWidth(
642				endLine,
643				end - buffer.getLineStartOffset(this.endLine));
644			if(startLine == this.endLine && extraEndVirt != 0)
645			{
646				extraEndVirt += (endVirtualColumn
647					- newEndVirtualColumn);
648			}
649			else if(startLine == this.startLine
650				&& extraStartVirt != 0)
651			{
652				extraStartVirt += (endVirtualColumn
653					- newEndVirtualColumn);
654			}
655
656			return true;
657		} //}}}
658
659		//{{{ contentRemoved() method
660		boolean contentRemoved(Buffer buffer, int startLine, int start,
661			int numLines, int length)
662		{
663			int end = start + length;
664			boolean changed = false;
665
666			if(this.start > start && this.start <= end)
667			{
668				this.start = start;
669				changed = true;
670			}
671			else if(this.start > end)
672			{
673				this.start -= length;
674				changed = true;
675			}
676
677			if(this.end > start && this.end <= end)
678			{
679				this.end = start;
680				changed = true;
681			}
682			else if(this.end > end)
683			{
684				this.end -= length;
685				changed = true;
686			}
687
688			if(changed && numLines != 0)
689			{
690				this.startLine = buffer.getLineOfOffset(this.start);
691				this.endLine = buffer.getLineOfOffset(this.end);
692			}
693
694			return changed;
695		} //}}}
696
697		//}}}
698
699		//{{{ Private members
700
701		//{{{ getColumnOnOtherLine() method
702		private int getColumnOnOtherLine(Buffer buffer, int line,
703			int col)
704		{
705			int returnValue = buffer.getOffsetOfVirtualColumn(
706				line,col,null);
707			if(returnValue == -1)
708				return buffer.getLineEndOffset(line) - 1;
709			else
710				return buffer.getLineStartOffset(line) + returnValue;
711		} //}}}
712
713		//}}}
714	} //}}}
715}