Bug 279931 - Qyoto has severely broken QFile class
Summary: Qyoto has severely broken QFile class
Status: RESOLVED UPSTREAM
Alias: None
Product: bindings
Classification: Developer tools
Component: general (show other bugs)
Version: unspecified
Platform: unspecified All
: NOR normal
Target Milestone: ---
Assignee: kde-bindings
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-08-12 00:05 UTC by roland
Modified: 2011-08-13 10:03 UTC (History)
1 user (show)

See Also:
Latest Commit:
Version Fixed In:


Attachments
C++ example with error (248 bytes, application/octet-stream)
2011-08-12 21:55 UTC, Arno Rehn
Details

Note You need to log in before you can comment on or make changes to this bug.
Description roland 2011-08-12 00:05:23 UTC
The QFile class is severely broken.  If you create a new QFile() with a name it "claims" to automatically open the file for you, but it never does.  Even if you Close() the file and re-open it you will get an error saying file is already open.

Probably the most frustrating is the following error message:
QIODevice::open: File access not specified
caused by this statement:  outF.Open( Qyoto.Qyoto.GetCPPEnumValue("Qt.QIODevice", "WriteOnly"));

the following:
<code>
            //QFileInfo fi = new QFileInfo( QDir.Temp(), "bynumbers.txt");
            //Console.WriteLine( fi.AbsoluteFilePath());
            QFile outF = new QFile( "/tmp/bynumbers.txt" );
          //  Console.WriteLine("about to close");
           // outF.Close();  // major bug where QFile tries to open
            //Console.WriteLine( "about to set text");
            //outF.SetTextModeEnabled( true);
            HandleQtEvents();
           // Console.WriteLine( "about to open");
            outF.Open( Qyoto.Qyoto.GetCPPEnumValue("Qt.QIODevice", "WriteOnly"));
            //Console.WriteLine( "file opened");
            HandleQtEvents();
            QTextStream outFile = new QTextStream( outF);
            
            HandleQtEvents();
            
            DateTime today = DateTime.Now;
            int padCount1 = 34 - today.ToString().Length;
            int padCount2 = 39 - ("Drawing Data".Length/2) - 9;
            string outStr = string.Format( "{0}{1}Drawing Data{2}Page {3,4:0000}\n\n",
                                today.ToString(),
                                " ".PadLeft( padCount1),
                                " ".PadLeft( padCount2),
                                1);
            Console.WriteLine( outStr);
            outFile.Write( outStr);

            string drawDtStr;
            
            while( q.Next()) {
                HandleQtEvents();
                QSqlRecord rec = q.Record();
                drawDtStr = rec.Field("DRAW_DT").Value().ToDate().ToString("yyyy/MM/dd");
                no1 = rec.Field("NO_1").Value().ToInt();
                no2 = rec.Field("NO_2").Value().ToInt();
                no3 = rec.Field("NO_3").Value().ToInt();
                no4 = rec.Field("NO_4").Value().ToInt();
                no5 = rec.Field("NO_5").Value().ToInt();
                megaNo = rec.Field("MEGA_NO").Value().ToInt();
                HandleQtEvents();
                outStr = string.Format(
                    "{0,10} {1,5:00} {2,5:00} {3,5:00} {4,5:00} {5,5:00} {6,5:00}\n",
                    drawDtStr, no1, no2, no3, no4, no5, megaNo);
                outFile.Write(outStr);
                Console.WriteLine( outStr);
            }  // end while loop
            outFile.Flush();
            q.Finish();
            //outF.Close();

</code>


creates the following CONSOLE output:
cmdStr:select * from drawing_data where  (no_1 = 8 or no_2 = 8 or no_3 = 8 or no_4 = 8 or no_5 = 8 or mega_no = 8)  and  (no_1 = 39 or no_2 = 39 or no_3 = 39 or no_4 = 39 or no_5 = 39 or mega_no = 39) ;
QIODevice::open: File access not specified
8/11/2011 6:55:10 PM              Drawing Data                        Page 0001


2010/01/26    07    08    38    39    48    22

2008/06/27    08    14    22    39    50    44

2008/01/29    08    23    39    40    42    24

2006/05/05    08    20    39    53    55    10


but the file is never created.

This is really bad.  QFile() shouldn't be "helping you out" by automatically attempting a file open.  Worse yet, it should actually succeed don't you thing?

I searched high and low for the syntax that would cause a 2 to pop out for the WriteOnly attribute.  I'm quite ticked that it gets ignored.
Comment 1 Arno Rehn 2011-08-12 15:35:24 UTC
It works exactly as it's supposed to.

First, the QFile constructor does NOT open the file for you. (I wonder where you got that from, certainly it doesn't say so in the Qt docs).

Second, you're doing it wrong. See the following snippet to learn how to do it the right way:


using System;
using Qyoto;

class MainClass {
    public static void Main(string[] args) {
        new QCoreApplication(args);  // just for Qyoto initialization

        QFile file = new QFile("hello.txt");
        file.Open((uint) QIODevice.OpenModeFlag.WriteOnly);

        QTextStream stream = new QTextStream(file);
        stream.Write("Hello World!");

        file.Close();
    }
}
Comment 2 roland 2011-08-12 18:14:28 UTC
That's what I love!  Speak with great authority directly out rectal sphincter on a Friday without testing the actual case presented.  Add one line to your "proof" and QFile is horribly busted.

using System;
using Qyoto;

class MainClass {
    public static void Main(string[] args) {
        new QCoreApplication(args);  // just for Qyoto initialization


        QFile file = new QFile("hello.txt");
        file.SetTextModeEnabled( true);    // notice this one line
        file.Open((uint) QIODevice.OpenModeFlag.WriteOnly);

        QTextStream stream = new QTextStream(file);
        stream.Write("Hello World!");

        file.Close();
    }

}


mcs test_snippet_1.cs  -r:/usr/lib/mono/qyoto/qt-dotnet.dll


roland@linux-c345:~/mega_mono_qt> mono test_snippet_1.exe
QFile::open: File (hello.txt) already open
QIODevice::write: ReadOnly device
roland@linux-c345:~/mega_mono_qt> dir *.txt
ls: cannot access *.txt: No such file or directory
roland@linux-c345:~/mega_mono_qt> 

As to my using:

Qyoto.Qyoto.GetCPPEnumValue("Qt.QIODevice","WriteOnly"));

I did that because that is what the UI compiler generates in its code and that is what you find in examples.  I agree your method is cleaner, but I could not find it documented, hence, one of the main reasons I'm writing this book.
Comment 3 roland 2011-08-12 18:39:07 UTC
I hate it when I forget to log in first!

That's what I love!  Speak with great authority directly out rectal sphincter
on a Friday without testing the actual case presented.  It's always entertaining!

Add one line to your "proof" and QFile is horribly busted.

using System;
using Qyoto;

class MainClass {
    public static void Main(string[] args) {
        new QCoreApplication(args);  // just for Qyoto initialization


        QFile file = new QFile("hello.txt");
        file.SetTextModeEnabled( true);    // ****notice this one line
        file.Open((uint) QIODevice.OpenModeFlag.WriteOnly);

        QTextStream stream = new QTextStream(file);
        stream.Write("Hello World!");

        file.Close();
    }

}


mcs test_snippet_1.cs  -r:/usr/lib/mono/qyoto/qt-dotnet.dll


roland@linux-c345:~/mega_mono_qt> mono test_snippet_1.exe
QFile::open: File (hello.txt) already open
QIODevice::write: ReadOnly device
roland@linux-c345:~/mega_mono_qt> dir *.txt
ls: cannot access *.txt: No such file or directory
roland@linux-c345:~/mega_mono_qt> 

As to my using:

Qyoto.Qyoto.GetCPPEnumValue("Qt.QIODevice","WriteOnly"));

I did that because that is what the UI compiler generates in its code and that
is what you find in examples.  I agree your method is cleaner, but I could not
find it documented, hence, one of the main reasons I'm writing this book.
Comment 4 Arno Rehn 2011-08-12 21:55:08 UTC
Yep, you're right. Setting this flag at that point will make it work incorrectly. However, this has nothing to do with the bindings. It's the same behaviour if you write it in plain C++/Qt (example attached).

Solution: Call SetTextModeEnabled(true) *after* you've opened the file. Then it should work as expected.

Regarding me not testing the actual case presented: I didn't do that because your example isn't self-contained. This has nothing to do with me being rude or anything. It's just that I can't compile and test your example code without modifying it (and thus maybe erasing the bug), which makes it *very* difficult to track down the actual bug.

Sorry if I seemed rude or arrogant, that certainly hasn't been my intention.
Comment 5 Arno Rehn 2011-08-12 21:55:45 UTC
Created attachment 62786 [details]
C++ example with error
Comment 6 roland 2011-08-12 22:03:56 UTC
Send this bug up-stream then.  A "set" method should only "set" a property, never actually OPEN a file.  I will agree this is a baseline Qt bug, but the bug needs to be bubbled up from here since it was found here and we have complete examples that reproduce it consistently.

Please "bubble-up" to Nokia.
Comment 7 Arno Rehn 2011-08-13 10:03:11 UTC
http://www.qtcentre.org/threads/20543-QFile-and-setTextMode so the issue seems to be known.

Personally, I don't think this that this is actually a bug. The method only sets the QIODevice::Text flag for the open mode, which doesn't make sense if the file is not yet opened. Closing this bug now.

If you still think it's a bug, please go ahead and report it on the Qt bugtracker.