how to judge there is content in QTextEdit in QT? - qt5

I have written a notepad which looks like notepad in Windows. How to set to make the find action disabled when the QTextEdit empty but enabled when something in it

The myTextEdit->plainText().isEmpty() procedure does not seem to be very efficient: The plainText method needs to convert the full QTextEdit contents into a new QString buffer, which is expensive if the QTextEdit contains a large amount of text.
I suggest to use myTextEdit->document()->isEmpty() instead, which queries the QTextDocument storage, i.e. the original data structure.
In my use case, the QTextEdit contains an error log, and before appending a line I check if the text is empty; if not, I insert a newline(*). Converting the log buffer to a QString each time a line is appended would be a bad idea.
(*) I cannot insert a newline together with each log entry, because the entries themselves are comma-separated lists. Roughly speaking I have a newEntry(...) and a newLine(...) function, and newEntry does not know if newLine or newEntry will be called next.

You connect a function that enables/disables the action based on the text edits plainText(), to the textChanged() signal of the text edit.
For example:
void MyWidget::someSetupMethod()
{
// ... some code that sets up myTextEdit and myFindAction here
connect(myTextEdit, &QTextEdit::textChanged, myFindAction, [myTextEdit, myFindAction]() {
myFindAction->setEnabled(!myTextEdit->plainText().isEmpty());
});
// ...
}
or, if you cannot or do not want to use C++11, something like
void MyWidget::someSetupMethod()
{
// ... some code that sets up m_myTextEdit and m_myFindAction here
connect(m_myTextEdit, &QTextEdit::textChanged, this, &MyWidget::updateFindAction);
// ...
}
void MyWidget::updateFindAction()
{
m_myFindAction->setEnabled(!m_myTextEdit->plainText().isEmpty());
}

Related

How to repeat Mono while not empty

I have a method which returns like this!
Mono<Integer> getNumberFromSomewhere();
I need to keep calling this until it has no more items to emit. That is I need to make this as Flux<Integer>.
One option is to add repeat. the point is - I want to stop when the above method emits the first empty signal.
Is there any way to do this? I am looking for a clean way.
A built-in operator that does that (although it is intended for "deeper" nesting) is expand.
expand naturally stops expansion when the returned Publisher completes empty.
You could apply it to your use-case like this:
//this changes each time one subscribes to it
Mono<Integer> monoWithUnderlyingState;
Flux<Integer> repeated = monoWithUnderlyingState
.expand(i -> monoWithUnderlyingState);
I'm not aware of a built-in operator which would do the job straightaway. However, it can be done using a wrapper class and a mix of operators:
Flux<Integer> repeatUntilEmpty() {
return getNumberFromSomewhere()
.map(ResultWrapper::new)
.defaultIfEmpty(ResultWrapper.EMPTY)
.repeat()
.takeWhile(ResultWrapper::isNotEmpty)
}
// helper class, not necessarily needs to be Java record
record ResultWrapper(Integer value) {
public static final ResultWrapper EMPTY = new ResultWrapper(null);
public boolean isNotEmpty() {
return value != null;
}
}

Locate all xpath attributes that contains part of the value

I need to wait for all elements to not be visible with an attribute 'id' that contains the word 'mask'. I have tried like this:
//*[contains(#id *= 'mask')]
However it is giving me an element not found exception.
I believe the syntax you're looking for is:
//*[contains(#id,'mask')]
I do something similar where I wait until the count is zero for classes that contain "BlockUI":
public static void waitForBlockUIToDisappear() {
// This function checks the entire currently-loaded web page for the
// presence of any web element of the
// class "blockUI" and loops until there are none. The presence of an
// element with this class does exactly
// what it implies: it blocks user input. If you get the error that a
// different web element would receive
// the click, for example, this is why and you'd need to call this
// method before doing a click. Generally,
// this function should be implemented before sending any input to a web
// page - click, sendkeys, select...
String blockUI = "//*[contains(#class,'blockUI')]";
while (true) {
if (driver.findElements(By.xpath(blockUI)).size() == 0)
break;
}
;
}
You should be able to alter that code to look for your id to contain your text.
You can use explicit wait in this case, as below.
WebDriverWait wait = new WebDriverWait(driver,15);
wait.until(ExpectedConditions.invisibilityOfAllElements(driver.findElements(By.xpath("//*[starts-with(#id,'mask')]"))));
In c# they were not implemented this method, but you can implement that.
Below is the url that can help you to write.
https://github.com/SeleniumHQ/selenium/blob/master/dotnet/src/support/UI/ExpectedConditions.cs#L140

How to write a string in textfield which contains underscore in it using TestFX?

I am writing a simple login form in JavaFX for which I am writing a test program in TestFX. My TestFX script automatically types the credentials in the textfields and clicks the login button and it works fine further.
But when I want the script to type credentials which contain underscore, it doesn't type the underscore and types until the underscore comes. I have used backslash before underscore but it didn't help me.
Below is a screenshot of my login page.
Below is my test script which works fine when I give string without an underscore.
#Test
public void invalidCredentialsShouldNotLogin()
{
controller.click("#username").type("invalid");
controller.click("#password").type("invalid");
controller.click("#button");
verifyThat("#welcome", hasText("Login failed"));
}
And this is the script which tries to type a string which contains underscore in it and does not work as intended, and gives exception as invalid key code.
#Test
public void invalidCredentialsShouldNotLogin()
{
controller.click("#username").type("user_name");
controller.click("#password").type("invalid");
controller.click("#button");
verifyThat("#welcome", hasText("Login failed"));
}
This is the output of the above code.
The same thing happens when I use colon in place of underscore.
Please help me fix this. If you require any more information, please tell me. Thanks
I have got the answer of this question. Actually every special character like underscore or colon has a keycode associated with it. We have to use that keycode to type in the TextField using TestFX script.
In the question above, I wanted to type underscore. Usually when we type underscore, we press two keys together i.e. shift and hyphen (-). Same way we will use the keycodes of these two keys to type underscore using TestFX script.
Below is the code that worked for me and typed underscore in the TextField.
#Test
public void enterCredentialsWithUnderscore()
{
TextField usernameField = (TextField)GuiTest.find("#username");
if(username.indexOf("_") != -1)
{
String[] tokens = username.split("_");
for(int i=0; i<tokens.length; i++)
{
if (i == 0)
controller.click(usernameField).type(tokens[i]);
else
controller.push(KeyCode.SHIFT, KeyCode.MINUS).type(tokens[i]);
}
}
}
KeyCode.MINUS is keycode for hyphen key. And push(KeyCode.SHIFT, KeyCode.MINUS) method pushes the both buttons together thus typing underscore.
Below is a screenshot of the output I received.
Thanks to all.

On input of long escaped property value in LESS, how to split it to a newline

Suppose I have a really long escaped property value to input in LESS. I can get it to output with newlines in the final formatted css by setting a variable to add a newline like so #nl: `"\n"`; and use that in my escaped string to output newlines in the property value. So this:
#nl: `"\n"`;
.test {
property: ~"one,#{nl} two";
}
Will output this:
.test {
property: one,
two;
}
The question is whether there is any way to input it with newlines, something like:
.test {
property: ~"one,
two";
}
This throws a Parse error: Unrecognised input in LESS. A long set of property values like one might have with a progid:DXImageTransform.Microsoft.Matrix would benefit from being able to code it with newlines to begin with.
Though I posted an answer to my own question that I discovered worked, I'm open to a simpler one if it exists.
Well, one solution I have found is to put each line in its own escaped string. So this seems to work reasonably well for both input and output (depending on what the tab setting is):
Input LESS
#nl: `"\n\t\t\t"`;
.test {
property: ~"#{nl}"
~"one,#{nl}"
~"two";
}
Output CSS
.test {
property:
one,
two;
}
In short, no. Less does not support any kind of multiline strings (Recently this feature was proposed and rejected for various reasons). Though, speaking of IE hacks, the following code compiles fine since v1.4.2:
.rotate(#angle) {
#cos: cos(#angle);
#sin: sin(#angle);
#nsin: (0-sin(#angle));
-ms-filter: progid:DXImageTransform.Microsoft.Matrix(
M11=#cos,
M12=#sin,
M21=#nsin,
M22=#cos,
sizingMethod='auto expand'
);
}
test {
.rotate(20deg);
}
The only problem there is the combination of =, - and func() that needs some special handling.
Update,
as for the per line escaped strings example I guess the following would look a bit more clear:
#nl: ~`"\n "`;
.test {
property: #nl
~"one", #nl
~"two";
}

sprintf() and WriteFile() affecting string Buffer

I have a very weird problem which I cannot seem to figure out. Unfortunately, I'm not even sure how to describe it without describing my entire application. What I am trying to do is:
1) read a byte from the serial port
2) store each char into tagBuffer as they are read
3) run a query using tagBuffer to see what type of tag it is (book or shelf tag)
4) depending on the type of tag, output a series of bytes corresponding to the type of tag
Most of my code is implemented and I can get the right tag code sent back out the serial port. But there are two lines that I've added as debug statements which when I tried to remove them, they cause my program to stop working.
The lines are the two lines at the very bottom:
sprintf(buf,"%s!\n", tagBuffer);
WriteFile(hSerial,buf,strlen(buf), &dwBytesWritten,&ovWrite);
If I try to remove them, "tagBuffer" will only store the last character as oppose being a buffer. Same thing with the next line, WriteFile().
I thought sprintf and WriteFile are I/O functions and would have no effect on variables.
I'm stuck and I need help to fix this.
//keep polling as long as stop character '-' is not read
while(szRxChar != '-')
{
// Check if a read is outstanding
if (HasOverlappedIoCompleted(&ovRead))
{
// Issue a serial port read
if (!ReadFile(hSerial,&szRxChar,1,
&dwBytesRead,&ovRead))
{
DWORD dwErr = GetLastError();
if (dwErr!=ERROR_IO_PENDING)
return dwErr;
}
}
// resets tagBuffer in case tagBuffer is out of sync
time_t t_time = time(0);
char buf[50];
if (HasOverlappedIoCompleted(&ovWrite))
{
i=0;
}
// Wait 5 seconds for serial input
if (!(HasOverlappedIoCompleted(&ovRead)))
{
WaitForSingleObject(hReadEvent,RESET_TIME);
}
// Check if serial input has arrived
if (GetOverlappedResult(hSerial,&ovRead,
&dwBytesRead,FALSE))
{
// Wait for the write
GetOverlappedResult(hSerial,&ovWrite,
&dwBytesWritten,TRUE);
if( strlen(tagBuffer) >= PACKET_LENGTH )
{
i = 0;
}
//load tagBuffer with byte stream
tagBuffer[i] = szRxChar;
i++;
tagBuffer[i] = 0; //char arrays are \0 terminated
//run query with tagBuffer
sprintf(query,"select type from rfid where rfidnum=\"");
strcat(query, tagBuffer);
strcat(query, "\"");
mysql_real_query(&mysql,query,(unsigned int)strlen(query));
//process result and send back to handheld
res = mysql_use_result(&mysql);
while(row = mysql_fetch_row(res))
{
printf("result of query is %s\n",row[0]);
string str = "";
str = string(row[0]);
if( str == "book" )
{
WriteFile(hSerial,BOOK_INDICATOR,strlen(BOOK_INDICATOR),
&dwBytesWritten,&ovWrite);
}
else if ( str == "shelf" )
{
WriteFile(hSerial,SHELF_INDICATOR,strlen(SHELF_INDICATOR),
&dwBytesWritten,&ovWrite);
}
else //this else doesn't work
{
WriteFile(hSerial,NOK,strlen(NOK),
&dwBytesWritten,&ovWrite);
}
}
mysql_free_result(res);
// Display a response to input
//printf("query is %s!\n", query);
//printf("strlen(tagBuffer) is %d!\n", strlen(tagBuffer));
//without these, tagBuffer only holds the last character
sprintf(buf,"%s!\n", tagBuffer);
WriteFile(hSerial,buf,strlen(buf), &dwBytesWritten,&ovWrite);
}
}
With those two lines, my output looks like this:
s sh she shel shelf shelf0 shelf00 BOOKCODE shelf0001
Without them, I figured out that tagBuffer and buf only stores the most recent character at any one time.
Any help at all will be greatly appreciated. Thanks.
Where are you allocating tagbuffer, how large is it?
It's possible that you are overwriting 'buf' because you are writing past the end of tagbuffer.
It seems unlikely that those two lines would have that effect on a correct program - maybe you haven't allocated sufficient space in buf for the whole length of the string in tagBuffer? This might cause a buffer overrun that is disguising the real problem?
The first thing I'd say is a piece of general advice: bugs aren't always where you think they are. If you've got something going on that doesn't seem to make sense, it often means that your assumptions somewhere else are wrong.
Here, it does seem very unlikely that an sprintf() and a WriteFile() will change the state of the "buf" array variable. However, those two lines of test code do write to "hSerial", while your main loop also reads from "hSerial". That sounds like a recipie for changing the behaviour of your program.
Suggestion: Change your lines of debugging output to store the output somewhere else: to a dialog box, or to a log file, or similar. Debugging output should generally not go to files used in the core logic, as that's too likely to change how the core logic behaves.
In my opinion, the real problem here is that you're trying to read and write the serial port from a single thread, and this is making the code more complex than it needs to be. I suggest that you read the following articles and reconsider your design:
Serial Port I/O from Joseph Newcomer's website.
Serial Communications in Win32 from MSDN.
In a multithreaded implementation, whenever the reader thread reads a message from the serial port you would then post it to your application's main thread. The main thread would then parse the message and query the database, and then queue an appropriate response to the writer thread.
This may sound more complex than your current design, but really it isn't, as Newcomer explains.
I hope this helps!