How to Set AlignSpan Style on current cursor paragraph? - android

I know for set a style into spannable, we can use setSpan(Object classOfStyle, int start, int end, int flags).
I wanna set alignspan into a current paragraph. Current paragraph detected by current cursor position. It`s possible? May i can get start-position and end-position of paragraph?
Edit :
A paragraph is a group of sentences. One of paragraph will be ended by "Enter Character".

I've written a small helper class (optimized for speed) that will do exactly what you want. You pass a Spannable object which will be parsed to find all paragraphs:
public class Layout {
private static final Pattern LINEBREAK_PATTERN = Pattern.compile("\\r\\n|\\r|\\n");
private int mNrOfLines = 0;
private ArrayList<Selection> mSelection = new ArrayList<Selection>();
public Layout(Spannable spannable) {
String s = spannable.toString();
// remove the trailing line feeds
int len = s.length();
char c = len > 0 ? s.charAt(len - 1) : '-';
while (len > 0 && (c == '\n' || c == '\r')) {
len--;
c = s.charAt(len - 1);
}
// now find the line breaks and the according lines / paragraphs
mNrOfLines = 1;
Matcher m = LINEBREAK_PATTERN.matcher(s.substring(0, len));
int groupStart = 0;
while (m.find()) {
mSelection.add( new Selection(groupStart, m.end()) );
groupStart = m.end();
mNrOfLines++;
}
if (groupStart < len) {
mSelection.add( new Selection(groupStart, len) );
}
}
public List<Selection> getParagraphs() {
return mSelection;
}
public int getLineForOffset(int offset) {
int lineNr = 0;
while(lineNr < mNrOfLines && offset >= mSelection.get(lineNr).end()) {
lineNr++;
}
return Math.min(Math.max(0, lineNr), mSelection.size() - 1);
}
public int getLineStart(int line) {
return mNrOfLines == 0 || line < 0 ? 0 :
line<mNrOfLines ? mSelection.get(line).start() :
mSelection.get(mNrOfLines-1).end()-1;
}
public int getLineEnd(int line) {
return mNrOfLines == 0 || line < 0 ? 0 :
line<mNrOfLines ? mSelection.get(line).end() :
mSelection.get(mNrOfLines-1).end()-1;
}
}
The three methods getLineForOffset, getLineStart and getLineEnd can be used to find the paragraphs for the current Selection. The Selection can be either the current cursor position (which is basically a Selection with start==end) or the selected text. The following code will return the selected paragraphs for the current selection:
Selection getParagraphs(EditText editor) {
Layout layout = new Layout( editor.getEditableText() );
int selStart = editor.getSelectionStart();
int selEnd = editor.getSelectionEnd();
int firstLine = layout.getLineForOffset(selStart);
int end = selStart == selEnd ? selEnd : selEnd - 1;
int lastLine = layout.getLineForOffset(end);
return new Selection(layout.getLineStart(firstLine), layout.getLineEnd(lastLine));
}
If e.g. your text is:
line 1
l[ine 2
line ]3
line 4
with everything between the [] selected, getParagraphs() would return the second and third line (it basically expands the selected text to include all (even partially) selected paragraphs.

I Write some method for get first position of paragraph and last position of paragraph.
I don`t know, which one is better performance. Please correct me if its wrong.
public static int getFirstPositionOfParagraph(String paragraph, int cursorPosition) {
StringBuffer buffer = new StringBuffer(paragraph);
List pos = new ArrayList();
for (String breaker : LINE_BREAK){
pos.add(buffer.lastIndexOf(breaker, cursorPosition));
}
int firstPosition = Collections.max(pos);
return firstPosition
public static int getLastPositionOfParagraph(String paragraph, int cursorPosition) {
StringBuffer buffer = new StringBuffer(paragraph);
List pos = new ArrayList();
for (String breaker : LINE_BREAK){
int breakerPos = buffer.indexOf(breaker, cursorPosition);
if (breakerPos > 0)
pos.add(breakerPos);
}
return pos.size() > 0 ? Collections.min(pos) + 1 : paragraph.length();
}

Related

How to resolve java.lang.StringIndexOutOfBoundsException?

I am getting an error, while calculating on String,
java.lang.StringIndexOutOfBoundsException: length=4; regionStart=5; regionLength=2
My implementation is below.
private void initializeMyPLsAllotted() {
int theMonthWhenICame = Integer.parseInt(myDateHired.substring(5, 7)); //This line is showing the error
int theYearWhenICame = Integer.parseInt(myDateHired.substring(0,4));
int theCurrentMonth = Integer.parseInt(todaysDate.substring(5, 7));
int theCurrentYear = Integer.parseInt(todaysDate.substring(0, 4));
int myTotalMonths = (theCurrentYear - theYearWhenICame)*12 + theCurrentMonth - theMonthWhenICame;
if (myTotalMonths > 6) {
numberOfPLsAllotted = 2;
} else {
numberOfPLsAllotted = 0;
}
myPLs = numberOfPLsAllotted;
}
java.lang.StringIndexOutOfBoundsException: length=4; regionStart=5; regionLength=2
it clearly says that length of your string is 4 and you are trying to fetch sub-string from index 5. make sure your string is valid
you can check something like that to avoid crashing your app
private void initializeMyPLsAllotted() {
if(myDateHired.length() > 7 && todaysDate.length() > 7){
int theMonthWhenICame = Integer.parseInt(myDateHired.substring(5, 7));
int theYearWhenICame = Integer.parseInt(myDateHired.substring(0,4));
int theCurrentMonth = Integer.parseInt(todaysDate.substring(5, 7));
int theCurrentYear = Integer.parseInt(todaysDate.substring(0, 4));
int myTotalMonths = (theCurrentYear - theYearWhenICame)*12 + theCurrentMonth - theMonthWhenICame;
if(myTotalMonths>6) {
numberOfPLsAllotted = 2;
} else {
numberOfPLsAllotted = 0;
}
myPLs = numberOfPLsAllotted;
} else {
// print some error message
}
}
StringIndexOutOfBoundsException means that the section you're trying to substring is outside of the string length.
Example
String test = "123";
String testSubstringOne = test.substring(0, 1);
//testSubstringOne -> "1"
String testSubstringTwo = test.substring(0, 5);
//testSubstringTwo -> java.lang.StringIndexOutOfBoundsException
Make sure your myDateHired has the value you expect.
Tip from the coach
You say that those values are from a server... Maybe you should look into returning data in a more friendly format such as json.
As doc says, the IndexOutOfBoundsException will be throwed when:
if the beginIndex is negative, or endIndex is larger than the length
of this String object, or beginIndex is larger than endIndex
so check myDateHired before using it.

MPAndroidChart with null values

I'm using the MPAndroidChart and am really enjoying it.
A 'little' need I have is that I can put null values to the 'entrys'. I'm monitoring the apache conections on servers of my system, and I would to see if they is down (where I put the null value) or if they just no conections (0).
I tried, but the Entry class don't accept 'null' as value showing the message: 'The constructor Entry(null, int) is undefined'
Thanks!
A possible solution for you could be to check weather the object you received is null, or not. If the object is null, you don't even create an Entry object instead of just setting it's value to null.
Example:
// array that contains the information you want to display
ConnectionHolder[] connectionHolders = ...;
ArrayList<Entry> entries = new ArrayList<Entry>();
int cnt = 0;
for(ConnectionHolder ch : connectionHolders) {
if(ch != null) entries.add(new Entry(ch.getNrOfConnections(), cnt));
else {
// do nothing
}
cnt++; // always increment
}
This would create e.g. a LineChart where no circles are drawn on indices where the ConnectionHolder object was null.
For a future release of the library, I will try to add the feature so that null values are supported.
My solution is to draw another DataSet with TRANSPARENT (or arbitrary) color:
- chart with fixed number of X values
- Y values are updated periodically
- boolean flag indicate transparent part (or another color)
private static final int SERIES_SIZE = 360;
int xIndex = -1;
float xIndexVal;
private LineChart chart;
private boolean currentFlag;
public void createChart(LineDataSet dataSet) {
LineData chartData = new LineData();
prepareDataSet(dataSet);
chartData.addDataSet(dataSet);
for (int i = 0; i < SERIES_SIZE; i++) {
chartData.addXValue("" /*+ i*/);
}
chart.setData(chartData);
}
private void prepareDataSet(LineDataSet dataSet, YAxis axis, int color) {
// configure set
}
public void update(Float val, boolean flag) {
List<ILineDataSet> dsl = chart.getData().getDataSets();
Log.d("chart", String.format("%s --- %d sets, index %d", descr, dsl.size(), xIndex));
if (xIndex == SERIES_SIZE - 1) {
// remove all entries at X index 0
for (int i = 0; i < chart.getData().getDataSetCount(); i++) {
Entry entry0 = chart.getData().getDataSetByIndex(i).getEntryForIndex(0);
if (entry0 != null && entry0.getXIndex() == 0) {
chart.getData().removeEntry(entry0, i);
Log.d("chart", String.format("entry 0 removed from dataset %d, %d entries in the set", i, chart.getData().getDataSetByIndex(i).getEntryCount()));
}
else {
Log.d("chart", String.format("all %d entries in the set kept", chart.getData().getDataSetByIndex(i).getEntryCount()));
}
}
// remove empty set, if any
for (Iterator<ILineDataSet> mit = dsl.iterator(); mit.hasNext(); ) {
if (mit.next().getEntryCount() == 0) {
mit.remove();
Log.d("chart", String.format("set removed, %d sets", dsl.size()));
}
}
// move all entries by -1
for (ILineDataSet ds : dsl) {
for (Entry entry : ((LineDataSet)ds).getYVals()) {
entry.setXIndex(entry.getXIndex() - 1);
}
}
}
else {
xIndex++;
}
if (currentFlag != flag) {
currentFlag = !currentFlag;
LineDataSet set = new LineDataSet(null, "");
prepareDataSet(set, chart.getAxisLeft(), currentFlag ? Color.TRANSPARENT : Color.BLUE);
chart.getData().addDataSet(set);
if (xIndex != 0) {
chart.getData().addEntry(new Entry(xIndexVal, xIndex - 1), dsl.size() - 1);
}
}
xIndexVal = val;
chart.getData().addEntry(new Entry(val, xIndex), dsl.size() - 1);
chart.notifyDataSetChanged();
chart.invalidate();
}

Need help generating a unique request code for alarm

My app structure is like, there are 1000 masjids/mosques and each masjid has been given a unique id like 1,2,3,4 ..... 1000 . Now each mosque has seven alarms associated with it , I wish to generate a unique request code number for each alarm so that they don't overlap each other,
Following is the code:
//note integer NamazType has range 0 to 5
public int generateRequestCodeForAlarm(int MasjidID,int NamazType )
{
return (MasjidID *(10)) + (namazType);
}
Will this code work?
you can simply concatenate masjidID and namaztype( or specifically namaz ID). This will always return unique.
public int generateRequestCodeForAlarm(int MasjidID,int NamazType )
{
return Integer.ParseInt(String.valueOf(MasjidID)+""+NamazType)
}
Use Random class:
Try out like this:
//note integer NamazType has range 0 to 5
public int generateRequestCodeForAlarm(int MasjidID, int NamazType)
{
return (MasjidID * (Math.abs(new Random().nextInt()))) + (namazType);
}
It will work for sure.
public int generateRequestCodeForAlarm(int MasjidID,int NamazType )
{
return (MasjidID*(10)) + (NamazType );
}
Output:
Have a look at this
If MasjidID and NamazType are unique, then
Integer.parseInt( MasjidID + "" + NamazType );
would be enough to do the trick!
Example:
Masjid ID = 96, Namaz type = 1, Unique no = 961
MasjidId = 960, Namaz type = 1, Unique no = 9601
MasjidID = 999, Namaz type = 6, Unique no = 9996
I don't find any way in which it would get repeated. However, it is very similar to
(MasjidID * 10) + NamazType
Irrespective of MasjidID and NamazType, if a random number needs to be generated, this can be used.
public class NoRepeatRandom {
private int[] number = null;
private int N = -1;
private int size = 0;
public NoRepeatRandom(int minVal, int maxVal)
{
N = (maxVal - minVal) + 1;
number = new int[N];
int n = minVal;
for(int i = 0; i < N; i++)
number[i] = n++;
size = N;
}
public void Reset() { size = N; }
// Returns -1 if none left
public int GetRandom()
{
if(size <= 0) return -1;
int index = (int) (size * Math.random());
int randNum = number[index];
// Swap current value with current last, so we don't actually
// have to remove anything, and our list still contains everything
// if we want to reset
number[index] = number[size-1];
number[--size] = randNum;
return randNum;
}
}

Android : Remove last paragraph tag generated by Html.toHtml

I'm editing content that may be html in an EditText. Just before saving the result, I use Html.toHtml to convert the input into a string to be sent to the server. However this method call seems to be generating paragraph tags which I dont need. Eg -
Test edited
seems to get converted to
<p dir="ltr">Test edited</p>
I would like to strip out the last paragraph tag before saving the content. If there are other paragraph tags, I would like to keep those. I have this regex that matches all p tags
"(<p.*>)(.*)(</p>)";
but I'm not sure how to match just the last paragraph and remove just the tags for it.
public static void handleOneParagraph(SpannableStringBuilder text) {
int start = 0;
int end = text.length();
String chars1 = "<p";
if (end < 2)
return;
while (start < end ) {
String seq = text.toString().substring(start, start + 2);
if (seq.equalsIgnoreCase(chars1))
break;
start++;
}
if (text.toString().substring(start, start + 2).equalsIgnoreCase(chars1) ) {
int start2 = start + 1;
String chars2 = ">";
while (start2 < end && !text.subSequence(start2, start2+1).toString().equalsIgnoreCase(chars2) ) {
start2++;
}
if (start2 >= end)
return;
text.replace(start, start2+1, "");
end = text.length();
start = end;
String chars3 = "</p>";
while (start > start2 + 4) {
String last_p = text.subSequence(start - 4, start).toString();
if (last_p.equalsIgnoreCase(chars3) ) {
text.replace(start - 4, start, "");
break;
}
start--;
}
}
}
And now, you can use it like this...
SpannableStringBuilder cleaned_text = new SpannableStringBuilder(Html.toHtml(your_text));
handleOneParagraph(cleaned_text);

Indexing Android

My problem is I have around 1000+ records in an Android App
string field1;
string field2;
string field3;
string field4;
//...
I want to search in this set of records and get the best results on two fields (field1 and field2).
Currently I read each record and compare() (string compare) with the text i want to search so that takes a long time.
What is the best method to perform search?
Store each records in SQLite DB and do "select query where like"
Hash-Mapped
? any other suggestions?
Or may be create an Index of the records and do search.
If you want to search for not exact matches, I would try to make an ArrayList of MyAppRecord where
public class MyAppRecord {
private String record;
private int deviance;
}
and get for each record the deviance of the String you want to find with:
public static int getLevenshteinDistance (String s, String t) {
if (s == null || t == null) {
throw new IllegalArgumentException("Strings must not be null");
}
int n = s.length(); // length of s
int m = t.length(); // length of t
if (n == 0) {
return m;
} else if (m == 0) {
return n;
}
int p[] = new int[n+1]; //'previous' cost array, horizontally
int d[] = new int[n+1]; // cost array, horizontally
int _d[]; //placeholder to assist in swapping p and d
// indexes into strings s and t
int i; // iterates through s
int j; // iterates through t
char t_j; // jth character of t
int cost; // cost
for (i = 0; i<=n; i++) {
p[i] = i;
}
for (j = 1; j<=m; j++) {
t_j = t.charAt(j-1);
d[0] = j;
for (i=1; i<=n; i++) {
cost = s.charAt(i-1)==t_j ? 0 : 1;
// minimum of cell to the left+1, to the top+1, diagonally left and up +cost
d[i] = Math.min(Math.min(d[i-1]+1, p[i]+1), p[i-1]+cost);
}
// copy current distance counts to 'previous row' distance counts
_d = p;
p = d;
d = _d;
}
// our last action in the above loop was to switch d and p, so p now
// actually has the most recent cost counts
return p[n];
}
}
save it to your MyAppRecord-object and finally sort your ArrayList by the deviance of its MyAppRecord-objects.
Note that this could take some time, depending on your set of records. And NOTE that there is no way of telling wether dogA or dogB is on a certain position in your list by searching for dog.
Read up on the Levensthein distance to get a feeling on how it works. You may get the idea of sorting out strings that are possibly to long/short to get a distance that is okay for a threshold you may have.
It is also possible to copy "good enough" results to a different ArrayList.

Categories

Resources