I have written a function that takes an input string and wraps the input text to a specified width that is passed in as a parameter. Right now, it takes approximately 290ms to run this function 1,000 times with a 4000 character string.
Can anyone suggest ways to improve this function? I will be trying a number of ideas that I found online here, but I wanted to see if there are any recommendations here.
This is my function:
CREATE OR REPLACE FUNCTION SPLIT_STRING (
p_str VARCHAR2, --String input to split
p_del VARCHAR2 DEFAULT NULL, --Delimiter (If NULL, will only split on length [p_len NOT NULL])
p_len INTEGER DEFAULT NULL, --Length of each chunk (If NULL, will only split on delimiter)
p_force INTEGER DEFAULT NULL)
RETURN array_type IS
--
v_str_array array_type;
v_line_array array_type;
v_len PLS_INTEGER; -- Total string length
v_str VARCHAR2(32767); -- String being built
v_chunk VARCHAR2(32767); -- Current chunk
v_char VARCHAR2(1 CHAR); -- Current character
v_cur_len PLS_INTEGER; -- Current chuk length
v_idx PLS_INTEGER DEFAULT 1; -- For loop counter
v_start PLS_INTEGER DEFAULT 1;
v_stop PLS_INTEGER;
v_line PLS_INTEGER DEFAULT 0;
v_word binary_integer;
BEGIN
--Determine total string length
v_len:= LENGTH(p_str);
-- Split into individual word chunks by delimiter
IF p_del IS NOT NULL
THEN
FOR pos IN 1..v_len
LOOP
v_char:= SUBSTR(p_str, pos, 1);
IF (v_char = p_del) OR (pos = v_len)
THEN
v_stop:= pos+1;
v_chunk:=SUBSTR(p_str, v_start, v_stop-v_start);
v_str_array(v_idx):= v_chunk;
v_start:=v_stop;
v_line:=v_idx;
v_idx:=v_idx+1;
END IF;
END LOOP;
END IF;
--Split the string into chunks and add to an array
IF p_del IS NOT NULL AND p_len IS NOT NULL
THEN
-- Wrap words into each line
v_idx:=1;
v_cur_len:=0;
v_line:=0;
v_word:=v_str_array.FIRST;
WHILE v_str_array(v_word) IS NOT NULL
LOOP
IF(v_cur_len+LENGTH(v_str_array(v_word)) <= p_len)
THEN
IF(v_word <= 1)
THEN
v_chunk:=v_str_array(v_word);
ELSE
v_chunk:=v_chunk||v_str_array(v_word);
END IF;
IF v_line=0
THEN
v_line:=1;
END IF;
ELSIF (p_force = 1)
THEN
-- Force line width to match specification
v_chunk:=SUBSTR(v_str_array(v_word),1,p_len);
IF v_str_array.NEXT(v_word) IS NOT NULL
THEN
v_str_array(v_word+1) := SUBSTR(v_str_array(v_word),p_len+1,LENGTH(v_str_array(v_word)))|| v_str_array(v_word+1);
ELSE
v_str_array(v_word+1) := SUBSTR(v_str_array(v_word),p_len+1,LENGTH(v_str_array(v_word)));
END IF;
v_line:=v_line+1;
ELSE
-- Prevent words from being split if they are larger than width specification
v_chunk:=v_str_array(v_word);
v_line:=v_line+1;
END IF;
v_line_array(v_line):= v_chunk;
v_cur_len:= LENGTH(v_chunk);
v_word:=v_str_array.NEXT(v_word);
IF v_word IS NULL
THEN
EXIT;
END IF;
END LOOP;
ELSIF p_del IS NULL AND p_len IS NOT NULL
THEN
-- Chop into exact length lines
v_line:= CEIL(v_len/p_len);
v_start:=1;
v_stop:= p_len;
FOR line IN 1..v_line
LOOP
v_line_array(line):= SUBSTR(p_str, v_start, p_len);
v_start:=v_stop+1;
v_stop:=v_stop+p_len;
END LOOP;
ELSIF p_len IS NULL AND p_del IS NOT NULL
THEN
-- Split into word chunks by deliminator if length is not specified
v_line_array:= v_str_array;
ELSE
-- Do nothing to the string if no delimiter OR length is specified
v_line_array(1):= p_str;
RETURN v_line_array;
END IF;
RETURN v_line_array;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Exception in function "SPLIT_STRING": '||SQLERRM);
v_line_array(1):= p_str;
RETURN v_line_array;
END SPLIT_STRING;
/
This is how I am "testing" the function in a simulated table load environment where the function is called on every entry in a table.
DECLARE
type array_type is table of varchar2(32767) index by binary_integer;
v_str_array array_type;
P_STR VARCHAR2(32767);
P_DEL VARCHAR2(32767);
P_LEN NUMBER;
P_FORCE NUMBER;
V_ITTERATIONS NUMBER;
V_EXECUTIONTIME NUMBER;
V_TIMESTART NUMBER;
BEGIN
P_STR := 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum. Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc, quis gravida magna mi a libero. Fusce vulputate eleifend sapien. Vestibulum purus quam, scelerisque ut, mollis sed, nonummy id, metus. Nullam accumsan lorem in dui. Cras ultricies mi eu turpis hendrerit fringilla. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In ac dui quis mi consectetuer lacinia. Nam pretium turpis et arcu. Duis arcu tortor, suscipit eget, imperdiet nec, imperdiet iaculis, ipsum. Sed aliquam ultrices mauris. Integer ante arcu, accumsan a, consectetuer eget, posuere ut, mauris. Praesent adipiscing. Phasellus ullamcorper ipsum rutrum nunc. Nunc nonummy metus. Vestibulum volutpat pretium libero. Cras id dui. Aenean ut eros et nisl sagittis vestibulum. Nullam nulla eros, ultricies sit amet, nonummy id, imperdiet feugiat, pede. Sed lectus. Donec mollis hendrerit risus. Phasellus nec sem in justo pellentesque facilisis. Etiam imperdiet imperdiet orci. Nunc nec neque. Phasellus leo dolor, tempus non, auctor et, hendrerit quis, nisi. Curabitur ligula sapien, tincidunt non, euismod vitae, posuere imperdiet, leo. Maecenas malesuada. Praesent congue erat at massa. Sed cursus turpis vitae tortor. Donec posuere vulputate arcu. Phasellus accumsan cursus velit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed aliquam, nisi quis porttitor congue, elit erat euismod orci, ac placerat dolor lectus quis orci. Phasellus consectetuer vestibulum elit. Aenean tellus metus, bibendum sed, posuere ac, mattis non, nunc. Vestibulum fringilla pede sit amet augue. In turpis. Pellentesque posuere. Praesent turpis. Aenean posuere, tortor sed cursus feugiat, nunc augue blandit nunc, eu sollicitudin urna dolor sagittis lacus. Donec elit libero, sodales nec, volutpat a, suscipit non, turpis. Nullam sagittis. Suspendisse pulvinar, augue ac venenatis condimentum, sem libero volutpat nibh, nec pellentesque velit pede quis nunc. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce id purus. Ut varius tincidunt libero. Phasellus dolor. Maecenas vestibulum mollis diam. Pellentesque ut neque. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In dui magna, posuere eget, vestibulum et, tempor auctor, justo. In ac felis quis tortor malesuada pretium. Pellentesque auctor neque nec urna. Proin sapien ipsum, porta a, auctor quis, euismod ut, mi. Aenean viverra rhoncus pede. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut non enim eleifend felis pretium feugiat. Vivamus quis mi. Phasellus a est. Phas';
P_DEL := ' ';
P_LEN := 60;
P_FORCE := 1;
V_ITTERATIONS := 10;
--Get Start Time
V_TIMESTART:= DBMS_UTILITY.Get_time();
--Run Testing
FOR stress_test_loop IN 1..V_ITTERATIONS
LOOP
v_str_array:= SPLIT_STRING ( P_STR, P_DEL, P_LEN, P_FORCE );
END LOOP;
--Calculate run time
SELECT (dbms_utility.get_time() - V_TIMESTART) INTO V_EXECUTIONTIME FROM DUAL;
--Display output
DBMS_OUTPUT.Put_Line('Completed sucessfully.'||CHR(10)||'Itterations: '||V_ITTERATIONS||CHR(10)||'Execution Time: '||V_EXECUTIONTIME||'ms');
DBMS_OUTPUT.Put_Line('Function output: '||CHR(10));
FOR line IN 1..v_str_array.LAST
LOOP
DBMS_OUTPUT.Put_Line(v_str_array(line));
END LOOP;
COMMIT;
END;
The function simply wraps text like this (with force =0):
1---------n
This is a
test
testing
123...
Then like this with force = 1:
1---------n
This is a
test testi
g 123...
So far the function performs pretty badly with a high number of sequntial calls:
I would like to get it to under 1 sec for atleast 500 thuosand calls idealy (although this may be wishful thinking).
SOLUTION:
CREATE OR REPLACE FUNCTION SPLIT_STRINGV2 (
p_str VARCHAR2, --String input to split
p_len INTEGER, --Length of each chunk (If NULL, will only split on delimiter)
p_del VARCHAR2 DEFAULT ' ', --Delimiter (If NULL, will only split on length [p_len NOT NULL])
p_force INTEGER DEFAULT 0)
RETURN T_VAR_32K IS
--
v_line_array T_VAR_32K;
v_len PLS_INTEGER; -- Total string length
v_chunk VARCHAR2(32767); -- Current chunk
v_char VARCHAR2(1 CHAR); -- Current character
v_line PLS_INTEGER DEFAULT 1;
v_start PLS_INTEGER DEFAULT 1;
v_pos PLS_INTEGER DEFAULT 1;
v_prev PLS_INTEGER;
v_next PLS_INTEGER;
v_numb PLS_INTEGER;
BEGIN
--Determine total string length
v_len:= LENGTH(p_str);
WHILE (v_pos<=v_len)
LOOP
v_chunk:= SUBSTR(p_str, v_start, p_len);
IF p_force = 0 AND p_del IS NOT NULL
THEN
v_prev:=INSTR(SUBSTR(p_str, v_start, p_len), p_del, -1);
v_next:=INSTR(SUBSTR(p_str, v_prev+1, v_len), p_del, 1)+v_prev;
v_char:=SUBSTR(v_chunk, LENGTH(v_chunk)-1, 1);
IF v_char=p_del
THEN
v_chunk:=SUBSTR(v_chunk, 1, p_len);
ELSE
v_numb:=LENGTH(SUBSTR(v_chunk, 1, p_len)) - length(replace(SUBSTR(v_chunk, 1, p_len), p_del));
IF v_prev != 0 AND v_numb <= 1
THEN
v_chunk:=SUBSTR(p_str, v_start, v_next);
ELSIF v_prev !=0 AND v_numb > 1
THEN
v_chunk:=SUBSTR(p_str, v_start, v_prev);
ELSE
v_chunk:=SUBSTR(v_chunk, 1, p_len);
END IF;
END IF;
ELSE
v_chunk:=SUBSTR(v_chunk, 1, p_len);
END IF;
IF v_chunk IS NOT NULL
THEN
v_line_array(v_line):=v_chunk;
END IF;
v_pos:= v_pos+LENGTH(v_chunk);
v_line:= v_line+1;
v_start := v_pos+1;
END LOOP;
RETURN v_line_array;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Exception in function "SPLIT_STRING": '||SQLERRM);
v_line_array(1):= p_str;
RETURN v_line_array;
END SPLIT_STRINGV2;
/
In the end, I had a VERY impressive execution speed reduction from about 20min to 10 seconds for 1,000,000 calls to the function. That's a 99% improvement!
See here: https://community.oracle.com/thread/3700483
The main idea is:
SELECT rn, txt
FROM ( SELECT ROWNUM AS rn, TRIM (REGEXP_SUBSTR (:p_txt, '.{1,' || :v_linesize || '}( |$)', 1, ROWNUM)) AS txt
FROM DUAL
CONNECT BY ROWNUM <= CEIL (LENGTH (:p_txt) / :v_linesize) + 10)
WHERE txt IS NOT NULL
ORDER BY rn
The delimiter here is ' '.
Related
I am unable to get ScrollView in Kivy to scroll through paragraphs of text. I have attached a code example below. Can anyone state what is wrong? Thank you.
import kivy
import string
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
class longTextLabelApp(App):
def build(self):
scrollViewLayout = ScrollView(do_scroll_x=False)
childLayout = GridLayout(cols = 1, size_hint_x = 1, size_hint_y = None)
childLayout.bind(minimum_height=childLayout.setter('height'))
def longTextLabel():
_long_text = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus odio nisi, pellentesque molestie adipiscing vitae, aliquam at tellus. Fusce quis est ornare erat pulvinar elementum ut sed felis. Donec vel neque mauris. In sit amet nunc sit amet diam dapibus lacinia. In sodales placerat mauris, ut euismod augue laoreet at. Integer in neque non odio fermentum volutpat nec nec nulla. Donec et risus non mi viverra posuere. Phasellus cursus augue purus, eget volutpat leo. Phasellus sed dui vitae ipsum mattis facilisis vehicula eu justo.
Quisque neque dolor, egestas sed venenatis eget, porta id ipsum. Ut faucibus, massa vitae imperdiet rutrum, sem dolor rhoncus magna, non lacinia nulla risus non dui. Nulla sit amet risus orci. Nunc libero justo, interdum eu pulvinar vel, pulvinar et lectus. Phasellus sed luctus diam. Pellentesque non feugiat dolor. Cras at dolor velit, gravida congue velit. Aliquam erat volutpat. Nullam eu nunc dui, quis sagittis dolor. Ut nec dui eget odio pulvinar placerat. Pellentesque mi metus, tristique et placerat ac, pulvinar vel quam. Nam blandit magna a urna imperdiet molestie. Nullam ut nisi eget enim laoreet sodales sit amet a felis.
"""
reallyLongText = _long_text + _long_text + _long_text + _long_text +_long_text
myLabel = Label(text = reallyLongText, text_size = (700,None), line_height=1.5)
return myLabel
childLayout.add_widget(longTextLabel())
scrollViewLayout.add_widget(childLayout)
return scrollViewLayout
if __name__ == '__main__':
longTextLabelApp().run()
The default size of a Label (and Widget) is (100,100). It doesn't matter if you are seeing all the text on the screen. If you print myLabel.size you will realize of this. You need to be sure to set the height of the Label (myLabel.height: 2200) but first set the size_hint_y to None first (myLabel.size_hint_y=None). The following code should work:
import kivy
import string
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.graphics import Rectangle, Color
class longTextLabelApp(App):
def build(self):
scrollViewLayout = ScrollView(do_scroll_x=False)
childLayout = GridLayout(cols = 1, size_hint_x = 1, size_hint_y = None)
childLayout.bind(minimum_height=childLayout.setter('height'))
def longTextLabel():
_long_text = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus odio nisi, pellentesque molestie adipiscing vitae, aliquam at tellus. Fusce quis est ornare erat pulvinar elementum ut sed felis. Donec vel neque mauris. In sit amet nunc sit amet diam dapibus lacinia. In sodales placerat mauris, ut euismod augue laoreet at. Integer in neque non odio fermentum volutpat nec nec nulla. Donec et risus non mi viverra posuere. Phasellus cursus augue purus, eget volutpat leo. Phasellus sed dui vitae ipsum mattis facilisis vehicula eu justo.
Quisque neque dolor, egestas sed venenatis eget, porta id ipsum. Ut faucibus, massa vitae imperdiet rutrum, sem dolor rhoncus magna, non lacinia nulla risus non dui. Nulla sit amet risus orci. Nunc libero justo, interdum eu pulvinar vel, pulvinar et lectus. Phasellus sed luctus diam. Pellentesque non feugiat dolor. Cras at dolor velit, gravida congue velit. Aliquam erat volutpat. Nullam eu nunc dui, quis sagittis dolor. Ut nec dui eget odio pulvinar placerat. Pellentesque mi metus, tristique et placerat ac, pulvinar vel quam. Nam blandit magna a urna imperdiet molestie. Nullam ut nisi eget enim laoreet sodales sit amet a felis.
"""
reallyLongText = _long_text + _long_text + _long_text + _long_text +_long_text
myLabel = Label(text = reallyLongText, text_size = (700,None), line_height=1.5)
print "The label size is ", myLabel.size
myLabel.size_hint_y = None
myLabel.height = 2200
return myLabel
childLayout.add_widget(longTextLabel())
scrollViewLayout.add_widget(childLayout)
return scrollViewLayout
if __name__ == '__main__':
longTextLabelApp().run()
EDIT - RST Document
Depending on your objectives it might be better to use a RSTDocument. Label are just that, labels. They don't adjust to content or text. Think of them as stickers. The (RSTDocment)[http://kivy.org/docs/api-kivy.uix.rst.html], still indicated as highly experimental though is more suitable for long texts, specially if they are dynamic. They actually includes the Scroll.
from kivy.app import App
from kivy.uix.rst import RstDocument
class RstDocumentApp(App):
def build(self):
_long_text = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus odio nisi, pellentesque molestie adipiscing vitae, aliquam at tellus. Fusce quis est ornare erat pulvinar elementum ut sed felis. Donec vel neque mauris. In sit amet nunc sit amet diam dapibus lacinia. In sodales placerat mauris, ut euismod augue laoreet at. Integer in neque non odio fermentum volutpat nec nec nulla. Donec et risus non mi viverra posuere. Phasellus cursus augue purus, eget volutpat leo. Phasellus sed dui vitae ipsum mattis facilisis vehicula eu justo.
Quisque neque dolor, egestas sed venenatis eget, porta id ipsum. Ut faucibus, massa vitae imperdiet rutrum, sem dolor rhoncus magna, non lacinia nulla risus non dui. Nulla sit amet risus orci. Nunc libero justo, interdum eu pulvinar vel, pulvinar et lectus. Phasellus sed luctus diam. Pellentesque non feugiat dolor. Cras at dolor velit, gravida congue velit. Aliquam erat volutpat. Nullam eu nunc dui, quis sagittis dolor. Ut nec dui eget odio pulvinar placerat. Pellentesque mi metus, tristique et placerat ac, pulvinar vel quam. Nam blandit magna a urna imperdiet molestie. Nullam ut nisi eget enim laoreet sodales sit amet a felis.
"""
reallyLongText = _long_text + _long_text + _long_text + _long_text +_long_text
return RstDocument(text = reallyLongText)
if __name__ == '__main__':
RstDocumentApp().run()
You can set the Label to be of the size of the texture inside it like this.
FloatLayout:
Label:
# adding a background to see the amount of space the label takes
canvas.before:
Color:
rgba: .5, .5, .5, .5
Rectangle:
size: self.size
pos: self.pos
text: "How can the only thing constant in the universe be `change` when\nchange itself is by it's very nature `not constant`?"
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint: None, None
size: self.texture_size
However with this you would only get a label that just expands how much text is in it and would require you to add \n yourself to make it wrap. A better approach would be to let the text inside the label auto wrap at a certain width by setting text_size something like the following::
FloatLayout:
ScrollView:
# take half of parents size
size_hint: .5, .5
pos_hint: {'center_x': .5, 'center_y': .5}
Label:
canvas.before:
Color:
rgba: .5, .5, .5, .5
Rectangle:
size: self.size
pos: self.pos
text: "\n1. Two hunters are out in the woods when one of them collapses. He doesn't seem to be breathing and his eyes are glazed. The other guy whips out his phone and calls the emergency services. He gasps, `My friend is dead! What can I do?`\n\n The operator says `Calm down. I can help. First, let's make sure he's dead.`\n\n There is a silence, then a gun shot is heard. Back on the phone, the guy says `OK, now what?`\n\n\n2. Sherlock Holmes and Dr Watson were going camping. They pitched their tent under the stars and went to sleep. Sometime in the middle of the night Holmes woke Watson up and said:\n\n `Watson, look up at the sky, and tell me what you see.`\n\n Watson replied: `I see millions and millions of stars.`\n\n Holmes said: `And what do you deduce from that?`\n\n Watson replied: `Well, if there are millions of stars, and if even a few of those have planets, it’s quite likely there are some planets like Earth out there. And if there are a few planets like Earth out there, there might also be life.`\n\n And Holmes said: `Watson, you idiot, it means that somebody stole our tent.`\n\n\n3. Three women talk about their husband is performance as lovers.\n\nThe first woman says, `My husband is a marriage counselor, so he always buys me flowers and candy before we make love.`\n\nThe second woman says, `My husband is a motorcycle mechanic. He likes to play rough and use leather sometimes.`\n\nThe third woman shakes her head and says, `My husband works for an Internet company. He just sits on the edge of the bed and tells me how great it's going to be when I get it.` \n\n\n4. As within, so outside. Fractals equations show the possibility of having infinity within minutia. Each and every cell can be a image of the whole; merging the micro and the macro into one.\n"
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint: 1, None
text_size: self.width, None
height: self.texture_size[1]
I just got a crash report (at launch), after submitting my app to the Mac App Store, for review :
Application Specific Information:
objc[1832]: garbage collection is ON
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSDictionary initWithObjects:forKeys:]: count of objects (0) differs from count of keys (2)'
terminate called throwing an exception
abort() called
This is the part of code, I'm suspecting :
- (NSMutableDictionary*)getNewChapterWithTitle:(NSString*)title
{
if (title==nil) title = [NSString stringWithFormat:#"Chapter %d",[[self appChapters] count]+1];
// Align Justify
NSMutableParagraphStyle * paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[paragraphStyle setAlignment:NSJustifiedTextAlignment];
// Set Font
NSDictionary *font = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:[NSFont fontWithName:#"Garamond" size:15.0],paragraphStyle, nil] forKeys:[NSArray arrayWithObjects:NSFontAttributeName, NSParagraphStyleAttributeName, nil]];
NSString* lipsum = #"\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc consequat fermentum faucibusPhasellus ac consequat metus. Sed at lectus sit amet tellus vulputate mollis vel suscipit metus. Nulla a sapien purus. Aenean sollicitudin lacus varius nisi faucibus nec lacinia mauris fermentum. Aliquam euismod quam rhoncus ipsum pulvinar quis condimentum magna imperdiet. Nullam augue leo, dictum tincidunt ullamcorper id, porta in lorem. Duis in vestibulum nisl.\
\n\n\
Donec imperdiet dignissim massa, at ultricies enim dignissim at. Etiam pharetra neque quis quam condimentum vitae viverra nisl volutpat. Vivamus urna ante, ultrices ut tincidunt id, auctor id est. Nunc eget diam purus, at viverra orci. Maecenas eu magna mi, id venenatis arcu. Maecenas ornare, tortor sit amet gravida placerat, diam urna lacinia nunc, a dictum arcu libero sed metus. Nulla pulvinar sapien vitae lectus faucibus quis tempus elit volutpat. Integer facilisis interdum lectus, sit amet dapibus enim mattis non. Donec sed pulvinar risus. Mauris in nulla urna, sit amet placerat turpis. Proin felis erat, pretium sed pharetra vel, tincidunt quis tortor. Donec ut nisi dui. Pellentesque gravida gravida justo, quis convallis leo euismod in. Nam pretium accumsan sapien ac interdum.";
NSMutableAttributedString* theLipsum = [[NSMutableAttributedString alloc] initWithString:lipsum attributes:font];
return [[NSMutableDictionary dictionaryWithObjectsAndKeys:
[title retain],#"title",
[theLipsum retain],#"content",
[NSNumber numberWithInt:0],#"isMarkdown",
nil] retain];
}
Do you see anything "obviously" wrong with the above? (It's being called like 4-5 times, from awakeFromNib, so I guess that's the culprit...)
HINT : The retains have been added after the report; I don't know if it's going to help though at all...
[NSFont fontWithName:#"Garamond" size:15.0] probably returns nil. As far as I know it's not a default font on OSX. So your objects array is empty, because only the objects up until the first nil are added.
i think the problem is here - [NSFont fontWithName:#"Garamond" size:15.0]
This code returns nil, so the array is empty.
May be this font is not standard but it is installed on your computer.
if the problem is here, you should add this font to app resources.
// textView is type of UITextView
self.textView.text = #"Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
CGSize maxSize = {self.textView.contentSize.width, CGFLOAT_MAX};
CGSize computedSize = [self.textView.text sizeWithFont:self.textView.font
constrainedToSize:maxSize
lineBreakMode:UILineBreakModeWordWrap];
NSLog(#"Computed size - width:%f height:%f\nContent size - width:%f height:%f", computedSize.width, computedSize.height, self.textView.contentSize.width, self.textView.contentSize.height);
Console output:
Computed size - width:320.000000 height:450.000000
Content size - width:320.000000 height:484.000000
Why are not these values equal? At least heights.
What is the .bounds.size of the text view? If all text fits within the text view the content size can still be reported as the views full size.
The UITextView is implemented using an internal web view, with allot of private magic. It is generally not a good idea to trust the text view with anything apart from displaying and editing text. The internal measurements and calculations has, and will continues to, change between OS updates.
If what you want is to change the size of the UITextView to fit all text then you must let the text view itself do this calculation. For example:
CGRect frame = textView.frame;
frame.size.height = [textView sizeThatFits:CGSizeMake(frame.size.width, CGFLOAT_MAX)];
textView.frame = frame;
In html, you can do something like this
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eget
aliquet odio. Fusce id quam eu augue sollicitudin imperdiet eu ac eros.
<em>Etiam nec nisi lorem</em>, ac venenatis ipsum. In sollicitudin,
lectus eget varius tincidunt, felis sapien porta eros, non
pellentesque dui quam vitae tellus.
</p>
It is nice, because the paragraph of text still looks like a paragraph in the markup. In haml, it looks like this
%p
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eget
aliquet odio. Fusce id quam eu augue sollicitudin imperdiet eu ac eros.
%em Etiam nec nisi lorem
, ac venenatis ipsum. In sollicitudin,
lectus eget varius tincidunt, felis sapien porta eros, non
pellentesque dui quam vitae tellus.
Is there any way to totally inline a tag in haml?
Haml excels for structural markup, but it's not really intended for inline markup. Read: Haml Sucks for Content. Just put your inline tags as HTML:
.content
%p
Lorem ipsum <em>dolor</em> sit amet.
Or else use a filter:
.content
:markdown
Lorem ipsum *dolor* sit amet.
I know this is old. But figured I'd post this in case anyone lands here. You can also do this sort of thing in haml (And maybe more what the OP was looking for?).
%p Here is some text I want to #{content_tag(:em, "emphasize!")}, and here the word #{content_tag(:strong, "BOLD")} is in bold. and #{link_to("click here", "url")} for a link.
Useful for those situations where doing it on multiple lines adds spaces you don't want
I.E. When you have a link at the end of a sentence, and don't want that stupid space between the link and the period. (or like in the OP's example, there would be a space between the and the comma.
Just don't get carried away like i did in the example :)
You can inline HTML in any HAML doing
%p!= "Lorem ipsum <em>dolor</em> sit amet"
The != operator means that whatever the right side returns it will be outputted.
As a hybrid of these nice answers by others, I think you can define a Helper method in your application_helper.rb for some inline markups you'd frequently use. You don't need to mix HTML with HAML, nor do you have to type much.
In your helper;
def em(text)
content_tag(:em, text)
end
#def em(text)
# "<em>#{text}</em>".html_safe
#end
In your haml;
%p
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eget
aliquet odio. Fusce id quam eu augue sollicitudin imperdiet eu ac eros.
#{em 'Etiam nec nisi lorem'}, ac venenatis ipsum. In sollicitudin,
lectus eget varius tincidunt, felis sapien porta eros, non
pellentesque dui quam vitae tellus.
It's all about indentation:
%p
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eget aliquet odio. Fusce id quam eu augue sollicitudin imperdiet eu ac eros.
%em
Etiam nec nisi lorem, ac venenatis ipsum. In sollicitudin, lectus eget varius tincidunt, felis sapien porta eros, non pellentesque dui quam vitae tellus.
I'm taking some user data and adding it to a PowerPoint presentation using VSTO. To get the formatting to look right, though I need to be able to set the left margin of some of the text in the textbox. There will be an initial block of text followed by another, indented block. For example (underlines added to emphasize spacing):
Lorem ipsum dolor sit amet,
consectetur adipiscing elit. Sed
vestibulum elementum neque id rhoncus.
In fermentum eros nec dolor lobortis
sit amet fermentum est consequat.
Curabitur eleifend nunc eu odio
vehicula ut elementum erat aliquam. Ut
adipiscing ipsum sit amet leo pulvinar
hendrerit. Cum sociis natoque
penatibus et magnis dis parturient
montes, nascetur ridiculus mus. Nulla
non neque in velit lacinia tempor et a
lacus.
___________Cras auctor bibendum urna, a facilisis lacus
lacinia non.
___________Nullam at quam a mauris consequat vulputate sed eu
sapien.
___________Fusce sed urna nulla, ut sagittis lacus. Pellentesque
tortor
___________augue, scelerisque at aliquet a, pretium ac
ipsum.
I can get this effect by setting Shape.TextFrame.TextRange.IndentLevel = 2 on the lower block of text. However, I cannot figure out how to programmatically set the value of the margin. Does anyone know how to do this?
This is taken care of via Shape.TextFrame.MarginRight and Shape.TextFrame.MarginLeft and the like.